diff options
1076 files changed, 30262 insertions, 10956 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/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java index 696c3178a4f4..4832ea624bd7 100644 --- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java +++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java @@ -893,8 +893,9 @@ public class DeviceIdleController extends SystemService } // Fall through when quick doze is not requested. - if (!mIsOffBody) { - // Quick doze was not requested and device is on body so turn the device active. + if (!mIsOffBody && !mForceIdle) { + // Quick doze wasn't requested, doze wasn't forced and device is on body + // so turn the device active. mActiveReason = ACTIVE_REASON_ONBODY; becomeActiveLocked("on_body", Process.myUid()); } 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 3fd67db95e1b..ac98a944722d 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"; @@ -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); @@ -10733,6 +10731,7 @@ package android.content { field public static final String DROPBOX_SERVICE = "dropbox"; field public static final String EUICC_SERVICE = "euicc"; field public static final String FILE_INTEGRITY_SERVICE = "file_integrity"; + field public static final String FINGERPRINT_SERVICE = "fingerprint"; field public static final String GAME_SERVICE = "game"; field public static final String GRAMMATICAL_INFLECTION_SERVICE = "grammatical_inflection"; field public static final String HARDWARE_PROPERTIES_SERVICE = "hardware_properties"; @@ -13217,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"; @@ -13509,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 @@ -18053,6 +18052,24 @@ package android.graphics.pdf { method public android.graphics.pdf.PdfDocument.PageInfo.Builder setContentRect(android.graphics.Rect); } + public final class PdfRenderer implements java.lang.AutoCloseable { + ctor public PdfRenderer(@NonNull android.os.ParcelFileDescriptor) throws java.io.IOException; + method public void close(); + method public int getPageCount(); + method public android.graphics.pdf.PdfRenderer.Page openPage(int); + method public boolean shouldScaleForPrinting(); + } + + public final class PdfRenderer.Page implements java.lang.AutoCloseable { + method public void close(); + method public int getHeight(); + method public int getIndex(); + method public int getWidth(); + method public void render(@NonNull android.graphics.Bitmap, @Nullable android.graphics.Rect, @Nullable android.graphics.Matrix, int); + field public static final int RENDER_MODE_FOR_DISPLAY = 1; // 0x1 + field public static final int RENDER_MODE_FOR_PRINT = 2; // 0x2 + } + } package android.graphics.text { @@ -20363,6 +20380,54 @@ package android.hardware.display { } +package android.hardware.fingerprint { + + @Deprecated public class FingerprintManager { + method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.USE_BIOMETRIC, android.Manifest.permission.USE_FINGERPRINT}) public void authenticate(@Nullable android.hardware.fingerprint.FingerprintManager.CryptoObject, @Nullable android.os.CancellationSignal, int, @NonNull android.hardware.fingerprint.FingerprintManager.AuthenticationCallback, @Nullable android.os.Handler); + method @Deprecated @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public boolean hasEnrolledFingerprints(); + method @Deprecated @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public boolean isHardwareDetected(); + field public static final int FINGERPRINT_ACQUIRED_GOOD = 0; // 0x0 + field public static final int FINGERPRINT_ACQUIRED_IMAGER_DIRTY = 3; // 0x3 + field public static final int FINGERPRINT_ACQUIRED_INSUFFICIENT = 2; // 0x2 + field public static final int FINGERPRINT_ACQUIRED_PARTIAL = 1; // 0x1 + field public static final int FINGERPRINT_ACQUIRED_TOO_FAST = 5; // 0x5 + field public static final int FINGERPRINT_ACQUIRED_TOO_SLOW = 4; // 0x4 + field public static final int FINGERPRINT_ERROR_CANCELED = 5; // 0x5 + field public static final int FINGERPRINT_ERROR_HW_NOT_PRESENT = 12; // 0xc + field public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1; // 0x1 + field public static final int FINGERPRINT_ERROR_LOCKOUT = 7; // 0x7 + field public static final int FINGERPRINT_ERROR_LOCKOUT_PERMANENT = 9; // 0x9 + field public static final int FINGERPRINT_ERROR_NO_FINGERPRINTS = 11; // 0xb + field public static final int FINGERPRINT_ERROR_NO_SPACE = 4; // 0x4 + field public static final int FINGERPRINT_ERROR_TIMEOUT = 3; // 0x3 + field public static final int FINGERPRINT_ERROR_UNABLE_TO_PROCESS = 2; // 0x2 + field public static final int FINGERPRINT_ERROR_USER_CANCELED = 10; // 0xa + field public static final int FINGERPRINT_ERROR_VENDOR = 8; // 0x8 + } + + @Deprecated public abstract static class FingerprintManager.AuthenticationCallback { + ctor @Deprecated public FingerprintManager.AuthenticationCallback(); + method @Deprecated public void onAuthenticationError(int, CharSequence); + method @Deprecated public void onAuthenticationFailed(); + method @Deprecated public void onAuthenticationHelp(int, CharSequence); + method @Deprecated public void onAuthenticationSucceeded(android.hardware.fingerprint.FingerprintManager.AuthenticationResult); + } + + @Deprecated public static class FingerprintManager.AuthenticationResult { + method @Deprecated public android.hardware.fingerprint.FingerprintManager.CryptoObject getCryptoObject(); + } + + @Deprecated public static final class FingerprintManager.CryptoObject { + ctor @Deprecated public FingerprintManager.CryptoObject(@NonNull java.security.Signature); + ctor @Deprecated public FingerprintManager.CryptoObject(@NonNull javax.crypto.Cipher); + ctor @Deprecated public FingerprintManager.CryptoObject(@NonNull javax.crypto.Mac); + method @Deprecated public javax.crypto.Cipher getCipher(); + method @Deprecated public javax.crypto.Mac getMac(); + method @Deprecated public java.security.Signature getSignature(); + } + +} + package android.hardware.input { public final class HostUsiVersion implements android.os.Parcelable { @@ -34019,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"; @@ -35750,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; @@ -37098,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[]>>); @@ -39734,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/removed.txt b/core/api/removed.txt index c61f16333fe8..3c7c0d6e6ea1 100644 --- a/core/api/removed.txt +++ b/core/api/removed.txt @@ -35,7 +35,6 @@ package android.content { method @Deprecated @Nullable public String getFeatureId(); method public abstract android.content.SharedPreferences getSharedPreferences(java.io.File, int); method public abstract java.io.File getSharedPreferencesPath(String); - field public static final String FINGERPRINT_SERVICE = "fingerprint"; } public class ContextWrapper extends android.content.Context { @@ -146,54 +145,6 @@ package android.hardware { } -package android.hardware.fingerprint { - - @Deprecated public class FingerprintManager { - method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.USE_BIOMETRIC, android.Manifest.permission.USE_FINGERPRINT}) public void authenticate(@Nullable android.hardware.fingerprint.FingerprintManager.CryptoObject, @Nullable android.os.CancellationSignal, int, @NonNull android.hardware.fingerprint.FingerprintManager.AuthenticationCallback, @Nullable android.os.Handler); - method @Deprecated @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public boolean hasEnrolledFingerprints(); - method @Deprecated @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public boolean isHardwareDetected(); - field public static final int FINGERPRINT_ACQUIRED_GOOD = 0; // 0x0 - field public static final int FINGERPRINT_ACQUIRED_IMAGER_DIRTY = 3; // 0x3 - field public static final int FINGERPRINT_ACQUIRED_INSUFFICIENT = 2; // 0x2 - field public static final int FINGERPRINT_ACQUIRED_PARTIAL = 1; // 0x1 - field public static final int FINGERPRINT_ACQUIRED_TOO_FAST = 5; // 0x5 - field public static final int FINGERPRINT_ACQUIRED_TOO_SLOW = 4; // 0x4 - field public static final int FINGERPRINT_ERROR_CANCELED = 5; // 0x5 - field public static final int FINGERPRINT_ERROR_HW_NOT_PRESENT = 12; // 0xc - field public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1; // 0x1 - field public static final int FINGERPRINT_ERROR_LOCKOUT = 7; // 0x7 - field public static final int FINGERPRINT_ERROR_LOCKOUT_PERMANENT = 9; // 0x9 - field public static final int FINGERPRINT_ERROR_NO_FINGERPRINTS = 11; // 0xb - field public static final int FINGERPRINT_ERROR_NO_SPACE = 4; // 0x4 - field public static final int FINGERPRINT_ERROR_TIMEOUT = 3; // 0x3 - field public static final int FINGERPRINT_ERROR_UNABLE_TO_PROCESS = 2; // 0x2 - field public static final int FINGERPRINT_ERROR_USER_CANCELED = 10; // 0xa - field public static final int FINGERPRINT_ERROR_VENDOR = 8; // 0x8 - } - - @Deprecated public abstract static class FingerprintManager.AuthenticationCallback { - ctor public FingerprintManager.AuthenticationCallback(); - method public void onAuthenticationError(int, CharSequence); - method public void onAuthenticationFailed(); - method public void onAuthenticationHelp(int, CharSequence); - method public void onAuthenticationSucceeded(android.hardware.fingerprint.FingerprintManager.AuthenticationResult); - } - - @Deprecated public static class FingerprintManager.AuthenticationResult { - method public android.hardware.fingerprint.FingerprintManager.CryptoObject getCryptoObject(); - } - - @Deprecated public static final class FingerprintManager.CryptoObject { - ctor public FingerprintManager.CryptoObject(@NonNull java.security.Signature); - ctor public FingerprintManager.CryptoObject(@NonNull javax.crypto.Cipher); - ctor public FingerprintManager.CryptoObject(@NonNull javax.crypto.Mac); - method public javax.crypto.Cipher getCipher(); - method public javax.crypto.Mac getMac(); - method public java.security.Signature getSignature(); - } - -} - package android.media { public final class AudioFormat implements android.os.Parcelable { diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 2ff1f766ad8f..67ccd9d86c83 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"; @@ -1146,7 +1146,6 @@ package android.app { public static final class StatusBarManager.DisableInfo implements android.os.Parcelable { method public boolean areAllComponentsEnabled(); method public int describeContents(); - method public boolean isBackDisabled(); method public boolean isNavigateToHomeDisabled(); method public boolean isNotificationPeekingDisabled(); method public boolean isRecentsDisabled(); @@ -1648,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 @@ -1666,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 { @@ -1676,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); } @@ -3788,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"; @@ -10422,8 +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_read_polling_loop") public void addPollingLoopFilter(@NonNull String, boolean); method @FlaggedApi("android.nfc.nfc_observe_mode") public boolean defaultToObserveMode(); 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[]); @@ -11531,7 +11525,7 @@ package android.permission { public final class PermissionManager { method public int checkDeviceIdentifierAccess(@Nullable String, @Nullable String, @Nullable String, int, int); - method @FlaggedApi("android.permission.flags.device_aware_permission_apis_enabled") public static int checkPermission(@NonNull String, @NonNull String, @NonNull String, int); + method @FlaggedApi("android.permission.flags.device_aware_permission_apis_enabled") public int checkPermission(@NonNull String, @NonNull String, @NonNull String); method @RequiresPermission(value=android.Manifest.permission.UPDATE_APP_OPS_STATS, conditional=true) public int checkPermissionForDataDelivery(@NonNull String, @NonNull android.content.AttributionSource, @Nullable String); method @RequiresPermission(value=android.Manifest.permission.UPDATE_APP_OPS_STATS, conditional=true) public int checkPermissionForDataDeliveryFromDataSource(@NonNull String, @NonNull android.content.AttributionSource, @Nullable String); method public int checkPermissionForPreflight(@NonNull String, @NonNull android.content.AttributionSource); @@ -11710,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"; @@ -11773,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 e1e9d09f46fd..b8c32a4aa7ef 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); @@ -1711,6 +1712,15 @@ package android.hardware.display { } +package android.hardware.fingerprint { + + @Deprecated public class FingerprintManager { + method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public android.hardware.biometrics.BiometricTestSession createTestSession(int); + method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public java.util.List<android.hardware.biometrics.SensorProperties> getSensorProperties(); + } + +} + package android.hardware.hdmi { public final class HdmiControlServiceWrapper { @@ -3957,6 +3967,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/api/test-removed.txt b/core/api/test-removed.txt index 2e44176f342e..d802177e249b 100644 --- a/core/api/test-removed.txt +++ b/core/api/test-removed.txt @@ -1,10 +1 @@ // Signature format: 2.0 -package android.hardware.fingerprint { - - @Deprecated public class FingerprintManager { - method @NonNull @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public android.hardware.biometrics.BiometricTestSession createTestSession(int); - method @NonNull @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public java.util.List<android.hardware.biometrics.SensorProperties> getSensorProperties(); - } - -} - 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/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..6ad03135ea02 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) { @@ -749,6 +752,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 +765,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/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/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/StatusBarManager.java b/core/java/android/app/StatusBarManager.java index e6e46ddaa420..301fef877d6c 100644 --- a/core/java/android/app/StatusBarManager.java +++ b/core/java/android/app/StatusBarManager.java @@ -1448,7 +1448,6 @@ public class StatusBarManager { * * @hide */ - @SystemApi public boolean isBackDisabled() { return mBack; } @@ -1862,38 +1861,38 @@ public class StatusBarManager { }; @DataClass.Generated( - time = 1707345957771L, + time = 1708625947132L, codegenVersion = "1.0.23", sourceFile = "frameworks/base/core/java/android/app/StatusBarManager.java", - inputSignatures = "private boolean mStatusBarExpansion\nprivate " - + "boolean mNavigateHome\nprivate boolean mNotificationPeeking\nprivate " - + "boolean mRecents\nprivate boolean mBack\nprivate boolean " - + "mSearch\nprivate boolean mSystemIcons\nprivate boolean mClock\nprivate" - + " boolean mNotificationIcons\nprivate boolean mRotationSuggestion\n" + inputSignatures = "private boolean mStatusBarExpansion\nprivate boolean " + + "mNavigateHome\nprivate boolean mNotificationPeeking\nprivate " + + "boolean mRecents\nprivate boolean mBack\nprivate boolean mSearch\n" + + "private boolean mSystemIcons\nprivate boolean mClock\nprivate " + + "boolean mNotificationIcons\nprivate boolean mRotationSuggestion\n" + "private boolean mNotificationTicker\npublic " + "@android.annotation.SystemApi boolean isStatusBarExpansionDisabled()\n" + "public void setStatusBarExpansionDisabled(boolean)\npublic " - + "@android.annotation.SystemApi boolean isNavigateToHomeDisabled()\n" - + "public void setNavigationHomeDisabled(boolean)\npublic " - + "@android.annotation.SystemApi boolean isNotificationPeekingDisabled()\n" - + "public void setNotificationPeekingDisabled(boolean)\npublic " + + "@android.annotation.SystemApi boolean isNavigateToHomeDisabled()\npublic" + + " void setNavigationHomeDisabled(boolean)\npublic " + + "@android.annotation.SystemApi boolean isNotificationPeekingDisabled()" + + "\npublic void setNotificationPeekingDisabled(boolean)\npublic " + "@android.annotation.SystemApi boolean isRecentsDisabled()\npublic " - + "void setRecentsDisabled(boolean)\npublic @android.annotation.SystemApi " - + "boolean isBackDisabled()\npublic void setBackDisabled(boolean)\npublic " + + "void setRecentsDisabled(boolean)\npublic boolean isBackDisabled()" + + "\npublic void setBackDisabled(boolean)\npublic " + "@android.annotation.SystemApi boolean isSearchDisabled()\npublic " + "void setSearchDisabled(boolean)\npublic boolean " - + "areSystemIconsDisabled()\npublic void setSystemIconsDisabled(boolean)" - + "\npublic boolean isClockDisabled()\npublic " - + "void setClockDisabled(boolean)\npublic " - + "boolean areNotificationIconsDisabled()\npublic " - + "void setNotificationIconsDisabled(boolean)\npublic boolean " + + "areSystemIconsDisabled()\npublic void setSystemIconsDisabled(boolean)\n" + + "public boolean isClockDisabled()\npublic " + + "void setClockDisabled(boolean)\npublic boolean " + + "areNotificationIconsDisabled()\npublic void " + + "setNotificationIconsDisabled(boolean)\npublic boolean " + "isNotificationTickerDisabled()\npublic void " + "setNotificationTickerDisabled(boolean)\npublic " + "@android.annotation.TestApi boolean isRotationSuggestionDisabled()\n" + "public void setRotationSuggestionDisabled(boolean)\npublic " - + "@android.annotation.SystemApi boolean areAllComponentsEnabled()\n" - + "public void setEnableAll()\npublic boolean areAllComponentsDisabled()" - + "\npublic void setDisableAll()\npublic @android.annotation.NonNull " + + "@android.annotation.SystemApi boolean areAllComponentsEnabled()\npublic" + + " void setEnableAll()\npublic boolean areAllComponentsDisabled()\n" + + "public void setDisableAll()\npublic @android.annotation.NonNull " + "@java.lang.Override java.lang.String toString()\npublic " + "android.util.Pair<java.lang.Integer,java.lang.Integer> toFlags()\n" + "class DisableInfo extends java.lang.Object implements " 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/DevicePolicyCache.java b/core/java/android/app/admin/DevicePolicyCache.java index 29f657ec6ba7..16cb4ecc4cca 100644 --- a/core/java/android/app/admin/DevicePolicyCache.java +++ b/core/java/android/app/admin/DevicePolicyCache.java @@ -15,6 +15,9 @@ */ package android.app.admin; +import static android.app.admin.DevicePolicyManager.CONTENT_PROTECTION_DISABLED; +import static android.app.admin.DevicePolicyManager.ContentProtectionPolicy; + import android.annotation.UserIdInt; import com.android.server.LocalServices; @@ -59,6 +62,12 @@ public abstract class DevicePolicyCache { public abstract int getPermissionPolicy(@UserIdInt int userHandle); /** + * Caches {@link DevicePolicyManager#getContentProtectionPolicy(android.content.ComponentName)} + * of the given user. + */ + public abstract @ContentProtectionPolicy int getContentProtectionPolicy(@UserIdInt int userId); + + /** * True if there is an admin on the device who can grant sensor permissions. */ public abstract boolean canAdminGrantSensorsPermissions(); @@ -92,6 +101,11 @@ public abstract class DevicePolicyCache { } @Override + public @ContentProtectionPolicy int getContentProtectionPolicy(@UserIdInt int userId) { + return CONTENT_PROTECTION_DISABLED; + } + + @Override public boolean canAdminGrantSensorsPermissions() { return false; } 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 7505372fe295..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"; @@ -5068,7 +5067,6 @@ public abstract class Context { * {@link android.hardware.fingerprint.FingerprintManager} for handling management * of fingerprints. * - * @removed See {@link android.hardware.biometrics.BiometricPrompt} * @see #getSystemService(String) * @see android.hardware.fingerprint.FingerprintManager */ @@ -6567,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/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java index b0f69f56cba7..81e321d96aa6 100644 --- a/core/java/android/hardware/fingerprint/FingerprintManager.java +++ b/core/java/android/hardware/fingerprint/FingerprintManager.java @@ -83,8 +83,7 @@ import javax.crypto.Mac; /** * A class that coordinates access to the fingerprint hardware. - * - * @removed See {@link BiometricPrompt} which shows a system-provided dialog upon starting + * @deprecated See {@link BiometricPrompt} which shows a system-provided dialog upon starting * authentication. In a world where devices may have different types of biometric authentication, * it's much more realistic to have a system-provided authentication dialog since the method may * vary by vendor/device. @@ -95,6 +94,7 @@ import javax.crypto.Mac; @RequiresFeature(PackageManager.FEATURE_FINGERPRINT) public class FingerprintManager implements BiometricAuthenticator, BiometricFingerprintConstants { private static final String TAG = "FingerprintManager"; + private static final boolean DEBUG = true; private static final int MSG_ENROLL_RESULT = 100; private static final int MSG_ACQUIRED = 101; private static final int MSG_AUTHENTICATION_SUCCEEDED = 102; @@ -196,7 +196,6 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing /** * Retrieves a test session for FingerprintManager. - * * @hide */ @TestApi @@ -255,10 +254,9 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing } /** - * A wrapper class for the crypto objects supported by FingerprintManager. Currently, the + * A wrapper class for the crypto objects supported by FingerprintManager. Currently the * framework supports {@link Signature}, {@link Cipher} and {@link Mac} objects. - * - * @removed See {@link android.hardware.biometrics.BiometricPrompt.CryptoObject} + * @deprecated See {@link android.hardware.biometrics.BiometricPrompt.CryptoObject} */ @Deprecated public static final class CryptoObject extends android.hardware.biometrics.CryptoObject { @@ -332,8 +330,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing /** * Container for callback data from {@link FingerprintManager#authenticate(CryptoObject, * CancellationSignal, int, AuthenticationCallback, Handler)}. - * - * @removed See {@link android.hardware.biometrics.BiometricPrompt.AuthenticationResult} + * @deprecated See {@link android.hardware.biometrics.BiometricPrompt.AuthenticationResult} */ @Deprecated public static class AuthenticationResult { @@ -395,8 +392,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing * FingerprintManager#authenticate(CryptoObject, CancellationSignal, * int, AuthenticationCallback, Handler) } must provide an implementation of this for listening to * fingerprint events. - * - * @removed See {@link android.hardware.biometrics.BiometricPrompt.AuthenticationCallback} + * @deprecated See {@link android.hardware.biometrics.BiometricPrompt.AuthenticationCallback} */ @Deprecated public static abstract class AuthenticationCallback @@ -459,7 +455,6 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing /** * Callback structure provided for {@link #detectFingerprint(CancellationSignal, * FingerprintDetectionCallback, int, Surface)}. - * * @hide */ public interface FingerprintDetectionCallback { @@ -613,8 +608,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing * by <a href="{@docRoot}training/articles/keystore.html">Android Keystore * facility</a>. * @throws IllegalStateException if the crypto primitive is not initialized. - * - * @removed See {@link BiometricPrompt#authenticate(CancellationSignal, Executor, + * @deprecated See {@link BiometricPrompt#authenticate(CancellationSignal, Executor, * BiometricPrompt.AuthenticationCallback)} and {@link BiometricPrompt#authenticate( * BiometricPrompt.CryptoObject, CancellationSignal, Executor, * BiometricPrompt.AuthenticationCallback)} @@ -629,7 +623,6 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing /** * Per-user version of authenticate. * @deprecated use {@link #authenticate(CryptoObject, CancellationSignal, AuthenticationCallback, Handler, FingerprintAuthenticateOptions)}. - * * @hide */ @Deprecated @@ -642,7 +635,6 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing /** * Per-user and per-sensor version of authenticate. * @deprecated use {@link #authenticate(CryptoObject, CancellationSignal, AuthenticationCallback, Handler, FingerprintAuthenticateOptions)}. - * * @hide */ @Deprecated @@ -659,7 +651,6 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing /** * Version of authenticate with additional options. - * * @hide */ @RequiresPermission(anyOf = {USE_BIOMETRIC, USE_FINGERPRINT}) @@ -707,7 +698,6 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing /** * Uses the fingerprint hardware to detect for the presence of a finger, without giving details * about accept/reject/lockout. - * * @hide */ @RequiresPermission(USE_BIOMETRIC_INTERNAL) @@ -750,7 +740,6 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing * @param callback an object to receive enrollment events * @param shouldLogMetrics a flag that indicates if enrollment failure/success metrics * should be logged. - * * @hide */ @RequiresPermission(MANAGE_FINGERPRINT) @@ -821,7 +810,6 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing /** * Same as {@link #generateChallenge(int, GenerateChallengeCallback)}, but assumes the first * enumerated sensor. - * * @hide */ @RequiresPermission(MANAGE_FINGERPRINT) @@ -836,7 +824,6 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing /** * Revokes the specified challenge. - * * @hide */ @RequiresPermission(MANAGE_FINGERPRINT) @@ -862,7 +849,6 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing * @param sensorId Sensor ID that this operation takes effect for * @param userId User ID that this operation takes effect for. * @param hardwareAuthToken An opaque token returned by password confirmation. - * * @hide */ @RequiresPermission(RESET_FINGERPRINT_LOCKOUT) @@ -900,7 +886,6 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing /** * Removes all fingerprint templates for the given user. - * * @hide */ @RequiresPermission(MANAGE_FINGERPRINT) @@ -1020,7 +1005,6 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing /** * Forwards BiometricStateListener to FingerprintService * @param listener new BiometricStateListener being added - * * @hide */ public void registerBiometricStateListener(@NonNull BiometricStateListener listener) { @@ -1172,8 +1156,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing } /** - * This is triggered by SideFpsEventHandler. - * + * This is triggered by SideFpsEventHandler * @hide */ @RequiresPermission(USE_BIOMETRIC_INTERNAL) @@ -1186,8 +1169,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing * Determine if there is at least one fingerprint enrolled. * * @return true if at least one fingerprint is enrolled, false otherwise - * - * @removed See {@link BiometricPrompt} and + * @deprecated See {@link BiometricPrompt} and * {@link FingerprintManager#FINGERPRINT_ERROR_NO_FINGERPRINTS} */ @Deprecated @@ -1221,8 +1203,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing * Determine if fingerprint hardware is present and functional. * * @return true if hardware is present and functional, false otherwise. - * - * @removed See {@link BiometricPrompt} and + * @deprecated See {@link BiometricPrompt} and * {@link FingerprintManager#FINGERPRINT_ERROR_HW_UNAVAILABLE} */ @Deprecated @@ -1248,7 +1229,6 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing /** * Get statically configured sensor properties. - * * @hide */ @RequiresPermission(USE_BIOMETRIC_INTERNAL) @@ -1267,7 +1247,6 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing /** * Returns whether the device has a power button fingerprint sensor. * @return boolean indicating whether power button is fingerprint sensor - * * @hide */ public boolean isPowerbuttonFps() { 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/PermissionManager.java b/core/java/android/permission/PermissionManager.java index fd52c769e408..8495f3747573 100644 --- a/core/java/android/permission/PermissionManager.java +++ b/core/java/android/permission/PermissionManager.java @@ -1944,25 +1944,27 @@ public final class PermissionManager { * * @param permissionName The name of the permission you are checking for. * @param packageName The name of the package you are checking against. - * @param persistentDeviceId The persistent device id you are checking against. - * @param userId The user Id associated with context. + * @param persistentDeviceId The id of the physical device that you are checking permission + * against. * * @return If the package has the permission on the device, PERMISSION_GRANTED is * returned. If it does not have the permission on the device, PERMISSION_DENIED * is returned. * + * @see VirtualDevice#getPersistentDeviceId() * @see PackageManager#PERMISSION_GRANTED * @see PackageManager#PERMISSION_DENIED * * @hide */ @SystemApi + @PermissionResult @FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED) - public static int checkPermission(@NonNull String permissionName, @NonNull String packageName, - @NonNull String persistentDeviceId, @UserIdInt int userId) { + public int checkPermission(@NonNull String permissionName, @NonNull String packageName, + @NonNull String persistentDeviceId) { return sPackageNamePermissionCache.query( new PackageNamePermissionQuery(permissionName, packageName, persistentDeviceId, - userId)); + mContext.getUserId())); } /** 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 596c52dcfdf6..042af1f0fb15 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -36,6 +36,7 @@ import static android.view.flags.Flags.FLAG_SENSITIVE_CONTENT_APP_PROTECTION_API import static android.view.flags.Flags.FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY; import static android.view.flags.Flags.FLAG_VIEW_VELOCITY_API; import static android.view.flags.Flags.enableUseMeasureCacheDuringForceLayout; +import static android.view.flags.Flags.sensitiveContentAppProtection; import static android.view.flags.Flags.toolkitMetricsForFrameRateDecision; import static android.view.flags.Flags.toolkitSetFrameRateReadOnly; import static android.view.flags.Flags.viewVelocityApi; @@ -135,6 +136,7 @@ import android.service.credentials.CredentialProviderService; import android.sysprop.DisplayProperties; import android.text.InputType; import android.text.TextUtils; +import android.util.ArraySet; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.FloatProperty; @@ -3701,6 +3703,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * 1 PFLAG4_ROTARY_HAPTICS_SCROLL_SINCE_LAST_ROTARY_INPUT * 1 PFLAG4_ROTARY_HAPTICS_WAITING_FOR_SCROLL_EVENT * 11 PFLAG4_CONTENT_SENSITIVITY_MASK + * 1 PFLAG4_IS_COUNTED_AS_SENSITIVE * |-------|-------|-------|-------| */ @@ -3826,6 +3829,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback, private static final int PFLAG4_CONTENT_SENSITIVITY_MASK = (CONTENT_SENSITIVITY_AUTO | CONTENT_SENSITIVITY_SENSITIVE | CONTENT_SENSITIVITY_NOT_SENSITIVE) << PFLAG4_CONTENT_SENSITIVITY_SHIFT; + + /** + * Whether this view has been counted as a sensitive view or not. + * + * @see AttachInfo#mSensitiveViewsCount + */ + private static final int PFLAG4_IS_COUNTED_AS_SENSITIVE = 0x4000000; /* End of masks for mPrivateFlags4 */ /** @hide */ @@ -5639,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; @@ -9942,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 @@ -10387,6 +10414,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mPrivateFlags4 &= ~PFLAG4_CONTENT_SENSITIVITY_MASK; mPrivateFlags4 |= ((mode << PFLAG4_CONTENT_SENSITIVITY_SHIFT) & PFLAG4_CONTENT_SENSITIVITY_MASK); + if (sensitiveContentAppProtection()) { + updateSensitiveViewsCountIfNeeded(isAggregatedVisible()); + } } /** @@ -10418,13 +10448,44 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ @FlaggedApi(FLAG_SENSITIVE_CONTENT_APP_PROTECTION_API) public final boolean isContentSensitive() { - if (getContentSensitivity() == CONTENT_SENSITIVITY_SENSITIVE) { + final int contentSensitivity = getContentSensitivity(); + if (contentSensitivity == CONTENT_SENSITIVITY_SENSITIVE) { return true; + } else if (contentSensitivity == CONTENT_SENSITIVITY_NOT_SENSITIVE) { + return false; + } else if (sensitiveContentAppProtection()) { + return SensitiveAutofillHintsHelper + .containsSensitiveAutofillHint(getAutofillHints()); } return false; } /** + * Helper used to track sensitive views when they are added or removed from the window + * based on whether it's laid out and visible. + * + * <p>This method is called from many places (visibility changed, view laid out, view attached + * or detached to/from window, etc...) + */ + private void updateSensitiveViewsCountIfNeeded(boolean appeared) { + if (!sensitiveContentAppProtection() || mAttachInfo == null) { + return; + } + + if (appeared && isContentSensitive()) { + if ((mPrivateFlags4 & PFLAG4_IS_COUNTED_AS_SENSITIVE) == 0) { + mPrivateFlags4 |= PFLAG4_IS_COUNTED_AS_SENSITIVE; + mAttachInfo.increaseSensitiveViewsCount(); + } + } else { + if ((mPrivateFlags4 & PFLAG4_IS_COUNTED_AS_SENSITIVE) != 0) { + mPrivateFlags4 &= ~PFLAG4_IS_COUNTED_AS_SENSITIVE; + mAttachInfo.decreaseSensitiveViewsCount(); + } + } + } + + /** * Gets the mode for determining whether this view is important for content capture. * * <p>See {@link #setImportantForContentCapture(int)} and @@ -13457,6 +13518,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } else { mAutofillHints = autofillHints; } + if (sensitiveContentAppProtection()) { + if (getContentSensitivity() == CONTENT_SENSITIVITY_AUTO) { + updateSensitiveViewsCountIfNeeded(isAggregatedVisible()); + } + } } /** @@ -15248,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. @@ -15280,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(); } @@ -16681,6 +16749,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } notifyAppearedOrDisappearedForContentCaptureIfNeeded(isVisible); + updateSensitiveViewsCountIfNeeded(isVisible); if (!getSystemGestureExclusionRects().isEmpty()) { postUpdate(this::updateSystemGestureExclusionRects); @@ -22670,6 +22739,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } notifyAppearedOrDisappearedForContentCaptureIfNeeded(false); + updateSensitiveViewsCountIfNeeded(false); mAttachInfo = null; if (mOverlay != null) { @@ -31817,6 +31887,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, ScrollCaptureInternal mScrollCaptureInternal; /** + * sensitive views attached to the window + */ + int mSensitiveViewsCount; + + /** * Creates a new set of attachment information with the specified * events handler and thread. * @@ -31835,6 +31910,24 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mTreeObserver = new ViewTreeObserver(context); } + void increaseSensitiveViewsCount() { + if (mSensitiveViewsCount == 0) { + mViewRootImpl.notifySensitiveContentAppProtection(true); + } + mSensitiveViewsCount++; + } + + void decreaseSensitiveViewsCount() { + mSensitiveViewsCount--; + if (mSensitiveViewsCount == 0) { + mViewRootImpl.notifySensitiveContentAppProtection(false); + } + if (mSensitiveViewsCount < 0) { + Log.wtf(VIEW_LOG_TAG, "mSensitiveViewsCount is negative" + mSensitiveViewsCount); + mSensitiveViewsCount = 0; + } + } + @Nullable ContentCaptureManager getContentCaptureManager(@NonNull Context context) { if (mContentCaptureManager != null) { @@ -32448,6 +32541,36 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } } + private static class SensitiveAutofillHintsHelper { + /** + * List of autofill hints deemed sensitive for screen protection during screen share. + */ + private static final ArraySet<String> SENSITIVE_CONTENT_AUTOFILL_HINTS = new ArraySet<>(); + static { + SENSITIVE_CONTENT_AUTOFILL_HINTS.add(View.AUTOFILL_HINT_USERNAME); + SENSITIVE_CONTENT_AUTOFILL_HINTS.add(View.AUTOFILL_HINT_PASSWORD_AUTO); + SENSITIVE_CONTENT_AUTOFILL_HINTS.add(View.AUTOFILL_HINT_PASSWORD); + } + + /** + * Whether View's autofill hints contains a sensitive autofill hint. + * + * @see #SENSITIVE_CONTENT_AUTOFILL_HINTS + */ + static boolean containsSensitiveAutofillHint(@Nullable String[] autofillHints) { + if (autofillHints == null) { + return false; + } + + int size = autofillHints.length; + for (int i = 0; i < size; i++) { + if (SENSITIVE_CONTENT_AUTOFILL_HINTS.contains(autofillHints[i])) { + return true; + } + } + return false; + } + } /** * Returns the current scroll capture hint for this view. @@ -33508,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) { @@ -33642,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 94260b223dd2..333cbb39d9c7 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -58,6 +58,7 @@ import static android.view.ViewRootImplProto.WIDTH; import static android.view.ViewRootImplProto.WINDOW_ATTRIBUTES; import static android.view.ViewRootImplProto.WIN_FRAME; import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION; +import static android.view.flags.Flags.sensitiveContentAppProtection; import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS; import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS; import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS; @@ -94,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; @@ -166,6 +169,7 @@ import android.os.Message; import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.RemoteException; +import android.os.ServiceManager; import android.os.SystemClock; import android.os.SystemProperties; import android.os.Trace; @@ -924,6 +928,8 @@ public final class ViewRootImpl implements ViewParent, private IAccessibilityEmbeddedConnection mAccessibilityEmbeddedConnection; + private final ISensitiveContentProtectionManager mSensitiveContentProtectionService; + static final class SystemUiVisibilityInfo { int globalVisibility; int localValue; @@ -993,8 +999,6 @@ public final class ViewRootImpl implements ViewParent, */ private final boolean mViewBoundsSandboxingEnabled; - private int mLastTransformHint = Integer.MIN_VALUE; - private AccessibilityWindowAttributes mAccessibilityWindowAttributes; /* @@ -1040,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; @@ -1058,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 @@ -1114,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. @@ -1203,6 +1206,13 @@ public final class ViewRootImpl implements ViewParent, mScrollCaptureRequestTimeout = SCROLL_CAPTURE_REQUEST_TIMEOUT_MILLIS; mOnBackInvokedDispatcher = new WindowOnBackInvokedDispatcher(context); + if (sensitiveContentAppProtection()) { + mSensitiveContentProtectionService = + ISensitiveContentProtectionManager.Stub.asInterface( + ServiceManager.getService(Context.SENSITIVE_CONTENT_PROTECTION_SERVICE)); + } else { + mSensitiveContentProtectionService = null; + } } public static void addFirstDrawHandler(Runnable callback) { @@ -4154,6 +4164,29 @@ public final class ViewRootImpl implements ViewParent, mWmsRequestSyncGroup.add(this, null /* runnable */); } + /** + * Helper used to notify the service to block projection when a sensitive + * view (the view displays sensitive content) is attached to the window. + * The window manager service is also notified to unblock projection when + * no attached view (to the window) displays sensitive content. + * + * <ol> + * <li>It should only notify service to block projection when first sensitive view is + * attached to the window. + * <li>It should only notify service to unblock projection when all sensitive view are + * removed from the window. + * </ol> + */ + void notifySensitiveContentAppProtection(boolean showSensitiveContent) { + try { + // The window would be blocked during screen share if it shows sensitive content. + mSensitiveContentProtectionService.setSensitiveContentProtection( + getWindowToken(), mContext.getPackageName(), showSensitiveContent); + } catch (RemoteException ex) { + Log.e(TAG, "Unable to protect sensitive content during screen share", ex); + } + } + private void notifyContentCaptureEvents() { if (!isContentCaptureEnabled()) { if (DEBUG_CONTENT_CAPTURE) { @@ -6507,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: @@ -8884,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; @@ -8917,10 +8953,6 @@ public final class ViewRootImpl implements ViewParent, } } - mLastTransformHint = transformHint; - - mSurfaceControl.setTransformHint(transformHint); - if (mAttachInfo.mContentCaptureManager != null) { ContentCaptureSession mainSession = mAttachInfo.mContentCaptureManager .getMainContentCaptureSession(); @@ -8934,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 { @@ -11899,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 { @@ -12330,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) { @@ -12351,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(); @@ -12377,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; } @@ -12385,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(); @@ -12418,6 +12451,7 @@ public final class ViewRootImpl implements ViewParent, mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_LOW; } mHasInvalidation = true; + checkIdleness(); } /** @@ -12460,6 +12494,7 @@ public final class ViewRootImpl implements ViewParent, mHandler.sendEmptyMessageDelayed(MSG_FRAME_RATE_SETTING, FRAME_RATE_SETTING_REEVALUATE_TIME); } + checkIdleness(); } /** @@ -12565,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/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..f349ae9d8d79 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -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); } 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/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 new file mode 100644 index 000000000000..63a2474e70c1 --- /dev/null +++ b/core/java/android/window/flags/lse_desktop_experience.aconfig @@ -0,0 +1,16 @@ +package: "com.android.window.flags" + +flag { + name: "enable_scaled_resizing" + namespace: "lse_desktop_experience" + description: "Enable the resizing of un-resizable apps through scaling their bounds up/down" + 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/accessibility/dialog/AccessibilityTargetHelper.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java index 51a5ddfa8dd6..3d3db47faddb 100644 --- a/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java +++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java @@ -111,8 +111,9 @@ public final class AccessibilityTargetHelper { * @param context The context of the application. * @param shortcutType The shortcut type. * @return The list of {@link AccessibilityTarget}. + * @hide */ - static List<AccessibilityTarget> getInstalledTargets(Context context, + public static List<AccessibilityTarget> getInstalledTargets(Context context, @ShortcutType int shortcutType) { final List<AccessibilityTarget> targets = new ArrayList<>(); targets.addAll(getAccessibilityFilteredTargets(context, shortcutType)); 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/display/RefreshRateSettingsUtils.java b/core/java/com/android/internal/display/RefreshRateSettingsUtils.java index fab8984ce067..c23a5012923b 100644 --- a/core/java/com/android/internal/display/RefreshRateSettingsUtils.java +++ b/core/java/com/android/internal/display/RefreshRateSettingsUtils.java @@ -16,6 +16,8 @@ package com.android.internal.display; +import static android.hardware.display.DisplayManager.DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED; + import android.content.Context; import android.hardware.display.DisplayManager; import android.util.Log; @@ -54,4 +56,31 @@ public class RefreshRateSettingsUtils { } return maxRefreshRate; } + + /** + * Find the highest refresh rate among all the modes of all the displays. + * + * This method will acquire DisplayManager.mLock, so calling it while holding other locks + * should be done with care. + * @param context The context + * @return The highest refresh rate + */ + public static float findHighestRefreshRateAmongAllDisplays(Context context) { + final DisplayManager dm = context.getSystemService(DisplayManager.class); + final Display[] displays = dm.getDisplays(DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED); + if (displays.length == 0) { + Log.w(TAG, "No valid display devices"); + return DEFAULT_REFRESH_RATE; + } + + float maxRefreshRate = DEFAULT_REFRESH_RATE; + for (Display display : displays) { + for (Display.Mode mode : display.getSupportedModes()) { + if (mode.getRefreshRate() > maxRefreshRate) { + maxRefreshRate = mode.getRefreshRate(); + } + } + } + return maxRefreshRate; + } } diff --git a/core/java/com/android/internal/os/BatteryStatsHistory.java b/core/java/com/android/internal/os/BatteryStatsHistory.java index c5c17cffa48b..2a52264515fc 100644 --- a/core/java/com/android/internal/os/BatteryStatsHistory.java +++ b/core/java/com/android/internal/os/BatteryStatsHistory.java @@ -136,10 +136,8 @@ public class BatteryStatsHistory { private final Parcel mHistoryBuffer; private final File mSystemDir; private final HistoryStepDetailsCalculator mStepDetailsCalculator; - private final File mHistoryDir; private final Clock mClock; - private int mMaxHistoryFiles; private int mMaxHistoryBufferSize; /** @@ -150,7 +148,7 @@ public class BatteryStatsHistory { /** * A list of history files with increasing timestamps. */ - private final List<BatteryHistoryFile> mHistoryFiles = new ArrayList<>(); + private final BatteryHistoryDirectory mHistoryDir; /** * A list of small history parcels, used when BatteryStatsImpl object is created from @@ -161,7 +159,8 @@ public class BatteryStatsHistory { /** * When iterating history files, the current file index. */ - private int mCurrentFileIndex; + private BatteryHistoryFile mCurrentFile; + /** * When iterating history files, the current file parcel. */ @@ -203,7 +202,6 @@ public class BatteryStatsHistory { private byte mLastHistoryStepLevel = 0; private boolean mMutable = true; private final BatteryStatsHistory mWritableHistory; - private boolean mCleanupEnabled = true; private static class BatteryHistoryFile implements Comparable<BatteryHistoryFile> { public final long monotonicTimeMs; @@ -235,6 +233,271 @@ public class BatteryStatsHistory { } } + private static class BatteryHistoryDirectory { + private final File mDirectory; + private final MonotonicClock mMonotonicClock; + private int mMaxHistoryFiles; + private final List<BatteryHistoryFile> mHistoryFiles = new ArrayList<>(); + private final ReentrantLock mLock = new ReentrantLock(); + private boolean mCleanupNeeded; + + BatteryHistoryDirectory(File directory, MonotonicClock monotonicClock, + int maxHistoryFiles) { + mDirectory = directory; + mMonotonicClock = monotonicClock; + mMaxHistoryFiles = maxHistoryFiles; + if (mMaxHistoryFiles == 0) { + Slog.wtf(TAG, "mMaxHistoryFiles should not be zero when writing history"); + } + } + + void setMaxHistoryFiles(int maxHistoryFiles) { + mMaxHistoryFiles = maxHistoryFiles; + cleanup(); + } + + void lock() { + mLock.lock(); + } + + void unlock() { + mLock.unlock(); + if (mCleanupNeeded) { + cleanup(); + } + } + + boolean isLocked() { + return mLock.isLocked(); + } + + void load() { + mDirectory.mkdirs(); + if (!mDirectory.exists()) { + Slog.wtf(TAG, "HistoryDir does not exist:" + mDirectory.getPath()); + } + + final List<File> toRemove = new ArrayList<>(); + final Set<BatteryHistoryFile> dedup = new ArraySet<>(); + mDirectory.listFiles((dir, name) -> { + final int b = name.lastIndexOf(FILE_SUFFIX); + if (b <= 0) { + toRemove.add(new File(dir, name)); + return false; + } + try { + long monotonicTime = Long.parseLong(name.substring(0, b)); + dedup.add(new BatteryHistoryFile(mDirectory, monotonicTime)); + } catch (NumberFormatException e) { + toRemove.add(new File(dir, name)); + return false; + } + return true; + }); + if (!dedup.isEmpty()) { + mHistoryFiles.addAll(dedup); + Collections.sort(mHistoryFiles); + } + if (!toRemove.isEmpty()) { + // Clear out legacy history files, which did not follow the X-Y.bin naming format. + BackgroundThread.getHandler().post(() -> { + lock(); + try { + for (File file : toRemove) { + file.delete(); + } + } finally { + unlock(); + } + }); + } + } + + List<String> getFileNames() { + lock(); + try { + List<String> names = new ArrayList<>(); + for (BatteryHistoryFile historyFile : mHistoryFiles) { + names.add(historyFile.atomicFile.getBaseFile().getName()); + } + return names; + } finally { + unlock(); + } + } + + @Nullable + BatteryHistoryFile getFirstFile() { + lock(); + try { + if (!mHistoryFiles.isEmpty()) { + return mHistoryFiles.get(0); + } + return null; + } finally { + unlock(); + } + } + + @Nullable + BatteryHistoryFile getLastFile() { + lock(); + try { + if (!mHistoryFiles.isEmpty()) { + return mHistoryFiles.get(mHistoryFiles.size() - 1); + } + return null; + } finally { + unlock(); + } + } + + @Nullable + BatteryHistoryFile getNextFile(BatteryHistoryFile current, long startTimeMs, + long endTimeMs) { + if (!mLock.isHeldByCurrentThread()) { + throw new IllegalStateException("Iterating battery history without a lock"); + } + + int nextFileIndex = 0; + int firstFileIndex = 0; + // skip the last file because its data is in history buffer. + int lastFileIndex = mHistoryFiles.size() - 2; + for (int i = lastFileIndex; i >= 0; i--) { + BatteryHistoryFile file = mHistoryFiles.get(i); + if (current != null && file.monotonicTimeMs == current.monotonicTimeMs) { + nextFileIndex = i + 1; + } + if (file.monotonicTimeMs > endTimeMs) { + lastFileIndex = i - 1; + } + if (file.monotonicTimeMs <= startTimeMs) { + firstFileIndex = i; + break; + } + } + + if (nextFileIndex < firstFileIndex) { + nextFileIndex = firstFileIndex; + } + + if (nextFileIndex <= lastFileIndex) { + return mHistoryFiles.get(nextFileIndex); + } + + return null; + } + + BatteryHistoryFile makeBatteryHistoryFile() { + BatteryHistoryFile file = new BatteryHistoryFile(mDirectory, + mMonotonicClock.monotonicTime()); + lock(); + try { + mHistoryFiles.add(file); + } finally { + unlock(); + } + return file; + } + + void writeToParcel(Parcel out, boolean useBlobs) { + lock(); + try { + final long start = SystemClock.uptimeMillis(); + out.writeInt(mHistoryFiles.size() - 1); + for (int i = 0; i < mHistoryFiles.size() - 1; i++) { + AtomicFile file = mHistoryFiles.get(i).atomicFile; + byte[] raw = new byte[0]; + try { + raw = file.readFully(); + } catch (Exception e) { + Slog.e(TAG, "Error reading file " + file.getBaseFile().getPath(), e); + } + if (useBlobs) { + out.writeBlob(raw); + } else { + // Avoiding blobs in the check-in file for compatibility + out.writeByteArray(raw); + } + } + if (DEBUG) { + Slog.d(TAG, + "writeToParcel duration ms:" + (SystemClock.uptimeMillis() - start)); + } + } finally { + unlock(); + } + } + + int getFileCount() { + lock(); + try { + return mHistoryFiles.size(); + } finally { + unlock(); + } + } + + int getSize() { + lock(); + try { + int ret = 0; + for (int i = 0; i < mHistoryFiles.size() - 1; i++) { + ret += (int) mHistoryFiles.get(i).atomicFile.getBaseFile().length(); + } + return ret; + } finally { + unlock(); + } + } + + void reset() { + lock(); + try { + if (DEBUG) Slog.i(TAG, "********** CLEARING HISTORY!"); + for (BatteryHistoryFile file : mHistoryFiles) { + file.atomicFile.delete(); + } + mHistoryFiles.clear(); + } finally { + unlock(); + } + } + + private void cleanup() { + if (mDirectory == null) { + return; + } + + if (isLocked()) { + mCleanupNeeded = true; + return; + } + + mCleanupNeeded = false; + + lock(); + try { + // if free disk space is less than 100MB, delete oldest history file. + if (!hasFreeDiskSpace(mDirectory)) { + BatteryHistoryFile oldest = mHistoryFiles.remove(0); + oldest.atomicFile.delete(); + } + + // if there are more history files than allowed, delete oldest history files. + // mMaxHistoryFiles comes from Constants.MAX_HISTORY_FILES and + // can be updated by DeviceConfig at run time. + while (mHistoryFiles.size() > mMaxHistoryFiles) { + BatteryHistoryFile oldest = mHistoryFiles.get(0); + oldest.atomicFile.delete(); + mHistoryFiles.remove(0); + } + } finally { + unlock(); + } + } + } + /** * A delegate responsible for computing additional details for a step in battery history. */ @@ -351,7 +614,6 @@ public class BatteryStatsHistory { BatteryStatsHistory writableHistory) { mHistoryBuffer = historyBuffer; mSystemDir = systemDir; - mMaxHistoryFiles = maxHistoryFiles; mMaxHistoryBufferSize = maxHistoryBufferSize; mStepDetailsCalculator = stepDetailsCalculator; mTracer = tracer; @@ -363,66 +625,32 @@ public class BatteryStatsHistory { mMutable = false; } - mHistoryDir = new File(systemDir, HISTORY_DIR); - mHistoryDir.mkdirs(); - if (!mHistoryDir.exists()) { - Slog.wtf(TAG, "HistoryDir does not exist:" + mHistoryDir.getPath()); - } - - final List<File> toRemove = new ArrayList<>(); - final Set<BatteryHistoryFile> dedup = new ArraySet<>(); - mHistoryDir.listFiles((dir, name) -> { - final int b = name.lastIndexOf(FILE_SUFFIX); - if (b <= 0) { - toRemove.add(new File(dir, name)); - return false; - } - try { - long monotonicTime = Long.parseLong(name.substring(0, b)); - dedup.add(new BatteryHistoryFile(mHistoryDir, monotonicTime)); - } catch (NumberFormatException e) { - toRemove.add(new File(dir, name)); - return false; + if (writableHistory != null) { + mHistoryDir = writableHistory.mHistoryDir; + } else { + mHistoryDir = new BatteryHistoryDirectory(new File(systemDir, HISTORY_DIR), + monotonicClock, maxHistoryFiles); + mHistoryDir.load(); + BatteryHistoryFile activeFile = mHistoryDir.getLastFile(); + if (activeFile == null) { + activeFile = mHistoryDir.makeBatteryHistoryFile(); } - return true; - }); - if (!dedup.isEmpty()) { - mHistoryFiles.addAll(dedup); - Collections.sort(mHistoryFiles); - setActiveFile(mHistoryFiles.get(mHistoryFiles.size() - 1)); - } else if (mMutable) { - // No file found, default to have the initial file. - BatteryHistoryFile name = makeBatteryHistoryFile(); - mHistoryFiles.add(name); - setActiveFile(name); - } - if (!toRemove.isEmpty()) { - // Clear out legacy history files, which did not follow the X-Y.bin naming format. - BackgroundThread.getHandler().post(() -> { - for (File file : toRemove) { - file.delete(); - } - }); + setActiveFile(activeFile); } } - private BatteryHistoryFile makeBatteryHistoryFile() { - return new BatteryHistoryFile(mHistoryDir, mMonotonicClock.monotonicTime()); - } - - public BatteryStatsHistory(int maxHistoryFiles, int maxHistoryBufferSize, + public BatteryStatsHistory(int maxHistoryBufferSize, HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock, MonotonicClock monotonicClock) { - this(maxHistoryFiles, maxHistoryBufferSize, stepDetailsCalculator, clock, monotonicClock, + this(maxHistoryBufferSize, stepDetailsCalculator, clock, monotonicClock, new TraceDelegate(), new EventLogger()); } @VisibleForTesting - public BatteryStatsHistory(int maxHistoryFiles, int maxHistoryBufferSize, + public BatteryStatsHistory(int maxHistoryBufferSize, HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock, MonotonicClock monotonicClock, TraceDelegate traceDelegate, EventLogger eventLogger) { - mMaxHistoryFiles = maxHistoryFiles; mMaxHistoryBufferSize = maxHistoryBufferSize; mStepDetailsCalculator = stepDetailsCalculator; mTracer = traceDelegate; @@ -484,7 +712,9 @@ public class BatteryStatsHistory { * Changes the maximum number of history files to be kept. */ public void setMaxHistoryFiles(int maxHistoryFiles) { - mMaxHistoryFiles = maxHistoryFiles; + if (mHistoryDir != null) { + mHistoryDir.setMaxHistoryFiles(maxHistoryFiles); + } } /** @@ -513,7 +743,7 @@ public class BatteryStatsHistory { * Returns true if this instance only supports reading history. */ public boolean isReadOnly() { - return !mMutable || mActiveFile == null || mHistoryDir == null; + return !mMutable || mActiveFile == null/* || mHistoryDir == null*/; } /** @@ -538,25 +768,13 @@ public class BatteryStatsHistory { @GuardedBy("this") private void startNextFileLocked(long elapsedRealtimeMs) { - if (mMaxHistoryFiles == 0) { - Slog.wtf(TAG, "mMaxHistoryFiles should not be zero when writing history"); - return; - } - - if (mHistoryFiles.isEmpty()) { - Slog.wtf(TAG, "mFileNumbers should never be empty"); - return; - } - final long start = SystemClock.uptimeMillis(); writeHistory(); if (DEBUG) { Slog.d(TAG, "writeHistory took ms:" + (SystemClock.uptimeMillis() - start)); } - final BatteryHistoryFile next = makeBatteryHistoryFile(); - mHistoryFiles.add(next); - setActiveFile(next); + setActiveFile(mHistoryDir.makeBatteryHistoryFile()); try { mActiveFile.getBaseFile().createNewFile(); } catch (IOException e) { @@ -578,37 +796,7 @@ public class BatteryStatsHistory { } mWrittenPowerStatsDescriptors.clear(); - cleanupLocked(); - } - - @GuardedBy("this") - private void setCleanupEnabledLocked(boolean enabled) { - mCleanupEnabled = enabled; - if (mCleanupEnabled) { - cleanupLocked(); - } - } - - @GuardedBy("this") - private void cleanupLocked() { - if (!mCleanupEnabled || mHistoryDir == null) { - return; - } - - // if free disk space is less than 100MB, delete oldest history file. - if (!hasFreeDiskSpace()) { - BatteryHistoryFile oldest = mHistoryFiles.remove(0); - oldest.atomicFile.delete(); - } - - // if there are more history files than allowed, delete oldest history files. - // mMaxHistoryFiles comes from Constants.MAX_HISTORY_FILES and can be updated by GService - // config at run time. - while (mHistoryFiles.size() > mMaxHistoryFiles) { - BatteryHistoryFile oldest = mHistoryFiles.get(0); - oldest.atomicFile.delete(); - mHistoryFiles.remove(0); - } + mHistoryDir.cleanup(); } /** @@ -616,9 +804,7 @@ public class BatteryStatsHistory { * currently being read. */ public boolean isResetEnabled() { - synchronized (this) { - return mCleanupEnabled; - } + return mHistoryDir == null || !mHistoryDir.isLocked(); } /** @@ -627,16 +813,10 @@ public class BatteryStatsHistory { */ public void reset() { synchronized (this) { - if (DEBUG) Slog.i(TAG, "********** CLEARING HISTORY!"); - for (BatteryHistoryFile file : mHistoryFiles) { - file.atomicFile.delete(); + if (mHistoryDir != null) { + mHistoryDir.reset(); + setActiveFile(mHistoryDir.makeBatteryHistoryFile()); } - mHistoryFiles.clear(); - - BatteryHistoryFile name = makeBatteryHistoryFile(); - mHistoryFiles.add(name); - setActiveFile(name); - initHistoryBuffer(); } } @@ -646,8 +826,9 @@ public class BatteryStatsHistory { */ public long getStartTime() { synchronized (this) { - if (!mHistoryFiles.isEmpty()) { - return mHistoryFiles.get(0).monotonicTimeMs; + BatteryHistoryFile file = mHistoryDir.getFirstFile(); + if (file != null) { + return file.monotonicTimeMs; } else { return mHistoryBufferStartTime; } @@ -668,15 +849,13 @@ public class BatteryStatsHistory { return copy().iterate(startTimeMs, endTimeMs); } - mCurrentFileIndex = 0; + if (mHistoryDir != null) { + mHistoryDir.lock(); + } + mCurrentFile = null; mCurrentParcel = null; mCurrentParcelEnd = 0; mParcelIndex = 0; - if (mWritableHistory != null) { - synchronized (mWritableHistory) { - mWritableHistory.setCleanupEnabledLocked(false); - } - } return new BatteryStatsHistoryIterator(this, startTimeMs, endTimeMs); } @@ -685,10 +864,8 @@ public class BatteryStatsHistory { */ void iteratorFinished() { mHistoryBuffer.setDataPosition(mHistoryBuffer.dataSize()); - if (mWritableHistory != null) { - synchronized (mWritableHistory) { - mWritableHistory.setCleanupEnabledLocked(true); - } + if (mHistoryDir != null) { + mHistoryDir.unlock(); } } @@ -719,39 +896,27 @@ public class BatteryStatsHistory { } } - int firstFileIndex = 0; - // skip the last file because its data is in history buffer. - int lastFileIndex = mHistoryFiles.size() - 1; - for (int i = mHistoryFiles.size() - 1; i >= 0; i--) { - BatteryHistoryFile file = mHistoryFiles.get(i); - if (file.monotonicTimeMs >= endTimeMs) { - lastFileIndex = i; - } - if (file.monotonicTimeMs <= startTimeMs) { - firstFileIndex = i; - break; - } - } - - if (mCurrentFileIndex < firstFileIndex) { - mCurrentFileIndex = firstFileIndex; - } - - while (mCurrentFileIndex < lastFileIndex) { - mCurrentParcel = null; - mCurrentParcelEnd = 0; - final Parcel p = Parcel.obtain(); - AtomicFile file = mHistoryFiles.get(mCurrentFileIndex++).atomicFile; - if (readFileToParcel(p, file)) { - int bufSize = p.readInt(); - int curPos = p.dataPosition(); - mCurrentParcelEnd = curPos + bufSize; - mCurrentParcel = p; - if (curPos < mCurrentParcelEnd) { - return mCurrentParcel; + if (mHistoryDir != null) { + BatteryHistoryFile nextFile = mHistoryDir.getNextFile(mCurrentFile, startTimeMs, + endTimeMs); + while (nextFile != null) { + mCurrentParcel = null; + mCurrentParcelEnd = 0; + final Parcel p = Parcel.obtain(); + AtomicFile file = nextFile.atomicFile; + if (readFileToParcel(p, file)) { + int bufSize = p.readInt(); + int curPos = p.dataPosition(); + mCurrentParcelEnd = curPos + bufSize; + mCurrentParcel = p; + if (curPos < mCurrentParcelEnd) { + mCurrentFile = nextFile; + return mCurrentParcel; + } + } else { + p.recycle(); } - } else { - p.recycle(); + nextFile = mHistoryDir.getNextFile(nextFile, startTimeMs, endTimeMs); } } @@ -922,25 +1087,8 @@ public class BatteryStatsHistory { } private void writeToParcel(Parcel out, boolean useBlobs) { - final long start = SystemClock.uptimeMillis(); - out.writeInt(mHistoryFiles.size() - 1); - for (int i = 0; i < mHistoryFiles.size() - 1; i++) { - AtomicFile file = mHistoryFiles.get(i).atomicFile; - byte[] raw = new byte[0]; - try { - raw = file.readFully(); - } catch (Exception e) { - Slog.e(TAG, "Error reading file " + file.getBaseFile().getPath(), e); - } - if (useBlobs) { - out.writeBlob(raw); - } else { - // Avoiding blobs in the check-in file for compatibility - out.writeByteArray(raw); - } - } - if (DEBUG) { - Slog.d(TAG, "writeToParcel duration ms:" + (SystemClock.uptimeMillis() - start)); + if (mHistoryDir != null) { + mHistoryDir.writeToParcel(out, useBlobs); } } @@ -1021,22 +1169,18 @@ public class BatteryStatsHistory { * @return true if there is more than 100MB free disk space left. */ @android.ravenwood.annotation.RavenwoodReplace - private boolean hasFreeDiskSpace() { - final StatFs stats = new StatFs(mHistoryDir.getAbsolutePath()); + private static boolean hasFreeDiskSpace(File systemDir) { + final StatFs stats = new StatFs(systemDir.getAbsolutePath()); return stats.getAvailableBytes() > MIN_FREE_SPACE; } - private boolean hasFreeDiskSpace$ravenwood() { + private static boolean hasFreeDiskSpace$ravenwood(File systemDir) { return true; } @VisibleForTesting public List<String> getFilesNames() { - List<String> names = new ArrayList<>(); - for (BatteryHistoryFile historyFile : mHistoryFiles) { - names.add(historyFile.atomicFile.getBaseFile().getName()); - } - return names; + return mHistoryDir.getFileNames(); } @VisibleForTesting @@ -1048,10 +1192,7 @@ public class BatteryStatsHistory { * @return the total size of all history files and history buffer. */ public int getHistoryUsedSize() { - int ret = 0; - for (int i = 0; i < mHistoryFiles.size() - 1; i++) { - ret += mHistoryFiles.get(i).atomicFile.getBaseFile().length(); - } + int ret = mHistoryDir.getSize(); ret += mHistoryBuffer.dataSize(); if (mHistoryParcels != null) { for (int i = 0; i < mHistoryParcels.size(); i++) { @@ -1109,7 +1250,7 @@ public class BatteryStatsHistory { */ public void continueRecordingHistory() { synchronized (this) { - if (mHistoryBuffer.dataPosition() <= 0 && mHistoryFiles.size() <= 1) { + if (mHistoryBuffer.dataPosition() <= 0 && mHistoryDir.getFileCount() <= 1) { return; } diff --git a/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java b/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java index b2a6a934ba3f..83e9407fbdde 100644 --- a/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java +++ b/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java @@ -44,6 +44,7 @@ public class BatteryStatsHistoryIterator implements Iterator<BatteryStats.Histor private BatteryStats.HistoryItem mHistoryItem = new BatteryStats.HistoryItem(); private boolean mNextItemReady; private boolean mTimeInitialized; + private boolean mClosed; public BatteryStatsHistoryIterator(@NonNull BatteryStatsHistory history, long startTimeMs, long endTimeMs) { @@ -322,6 +323,9 @@ public class BatteryStatsHistoryIterator implements Iterator<BatteryStats.Histor */ @Override public void close() { - mBatteryStatsHistory.iteratorFinished(); + if (!mClosed) { + mClosed = true; + mBatteryStatsHistory.iteratorFinished(); + } } } 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/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_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_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/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/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/graphics/java/android/graphics/pdf/PdfEditor.java b/graphics/java/android/graphics/pdf/PdfEditor.java index 69e19824da26..3cd709ea10e5 100644 --- a/graphics/java/android/graphics/pdf/PdfEditor.java +++ b/graphics/java/android/graphics/pdf/PdfEditor.java @@ -25,9 +25,7 @@ import android.os.ParcelFileDescriptor; import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; - import dalvik.system.CloseGuard; - import libcore.io.IoUtils; import java.io.IOException; @@ -39,12 +37,6 @@ import java.io.IOException; */ public final class PdfEditor { - /** - * Any call the native pdfium code has to be single threaded as the library does not support - * parallel use. - */ - private static final Object sPdfiumLock = new Object(); - private final CloseGuard mCloseGuard = CloseGuard.get(); private long mNativeDocument; @@ -87,7 +79,7 @@ public final class PdfEditor { } mInput = input; - synchronized (sPdfiumLock) { + synchronized (PdfRenderer.sPdfiumLock) { mNativeDocument = nativeOpen(mInput.getFd(), size); try { mPageCount = nativeGetPageCount(mNativeDocument); @@ -120,7 +112,7 @@ public final class PdfEditor { throwIfClosed(); throwIfPageNotInDocument(pageIndex); - synchronized (sPdfiumLock) { + synchronized (PdfRenderer.sPdfiumLock) { mPageCount = nativeRemovePage(mNativeDocument, pageIndex); } } @@ -146,12 +138,12 @@ public final class PdfEditor { Point size = new Point(); getPageSize(pageIndex, size); - synchronized (sPdfiumLock) { + synchronized (PdfRenderer.sPdfiumLock) { nativeSetTransformAndClip(mNativeDocument, pageIndex, transform.ni(), 0, 0, size.x, size.y); } } else { - synchronized (sPdfiumLock) { + synchronized (PdfRenderer.sPdfiumLock) { nativeSetTransformAndClip(mNativeDocument, pageIndex, transform.ni(), clip.left, clip.top, clip.right, clip.bottom); } @@ -169,7 +161,7 @@ public final class PdfEditor { throwIfOutSizeNull(outSize); throwIfPageNotInDocument(pageIndex); - synchronized (sPdfiumLock) { + synchronized (PdfRenderer.sPdfiumLock) { nativeGetPageSize(mNativeDocument, pageIndex, outSize); } } @@ -185,7 +177,7 @@ public final class PdfEditor { throwIfOutMediaBoxNull(outMediaBox); throwIfPageNotInDocument(pageIndex); - synchronized (sPdfiumLock) { + synchronized (PdfRenderer.sPdfiumLock) { return nativeGetPageMediaBox(mNativeDocument, pageIndex, outMediaBox); } } @@ -201,7 +193,7 @@ public final class PdfEditor { throwIfMediaBoxNull(mediaBox); throwIfPageNotInDocument(pageIndex); - synchronized (sPdfiumLock) { + synchronized (PdfRenderer.sPdfiumLock) { nativeSetPageMediaBox(mNativeDocument, pageIndex, mediaBox); } } @@ -217,7 +209,7 @@ public final class PdfEditor { throwIfOutCropBoxNull(outCropBox); throwIfPageNotInDocument(pageIndex); - synchronized (sPdfiumLock) { + synchronized (PdfRenderer.sPdfiumLock) { return nativeGetPageCropBox(mNativeDocument, pageIndex, outCropBox); } } @@ -233,7 +225,7 @@ public final class PdfEditor { throwIfCropBoxNull(cropBox); throwIfPageNotInDocument(pageIndex); - synchronized (sPdfiumLock) { + synchronized (PdfRenderer.sPdfiumLock) { nativeSetPageCropBox(mNativeDocument, pageIndex, cropBox); } } @@ -246,7 +238,7 @@ public final class PdfEditor { public boolean shouldScaleForPrinting() { throwIfClosed(); - synchronized (sPdfiumLock) { + synchronized (PdfRenderer.sPdfiumLock) { return nativeScaleForPrinting(mNativeDocument); } } @@ -263,7 +255,7 @@ public final class PdfEditor { try { throwIfClosed(); - synchronized (sPdfiumLock) { + synchronized (PdfRenderer.sPdfiumLock) { nativeWrite(mNativeDocument, output.getFd()); } } finally { @@ -295,7 +287,7 @@ public final class PdfEditor { private void doClose() { if (mNativeDocument != 0) { - synchronized (sPdfiumLock) { + synchronized (PdfRenderer.sPdfiumLock) { nativeClose(mNativeDocument); } mNativeDocument = 0; diff --git a/graphics/java/android/graphics/pdf/PdfRenderer.java b/graphics/java/android/graphics/pdf/PdfRenderer.java new file mode 100644 index 000000000000..4666963b5dd4 --- /dev/null +++ b/graphics/java/android/graphics/pdf/PdfRenderer.java @@ -0,0 +1,502 @@ +/* + * Copyright (C) 2014 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.graphics.pdf; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.compat.annotation.UnsupportedAppUsage; +import android.graphics.Bitmap; +import android.graphics.Bitmap.Config; +import android.graphics.Matrix; +import android.graphics.Point; +import android.graphics.Rect; +import android.os.Build; +import android.os.ParcelFileDescriptor; +import android.system.ErrnoException; +import android.system.Os; +import android.system.OsConstants; + +import com.android.internal.util.Preconditions; + +import dalvik.system.CloseGuard; + +import libcore.io.IoUtils; + +import java.io.IOException; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * <p> + * This class enables rendering a PDF document. This class is not thread safe. + * </p> + * <p> + * If you want to render a PDF, you create a renderer and for every page you want + * to render, you open the page, render it, and close the page. After you are done + * with rendering, you close the renderer. After the renderer is closed it should not + * be used anymore. Note that the pages are rendered one by one, i.e. you can have + * only a single page opened at any given time. + * </p> + * <p> + * A typical use of the APIs to render a PDF looks like this: + * </p> + * <pre> + * // create a new renderer + * PdfRenderer renderer = new PdfRenderer(getSeekableFileDescriptor()); + * + * // let us just render all pages + * final int pageCount = renderer.getPageCount(); + * for (int i = 0; i < pageCount; i++) { + * Page page = renderer.openPage(i); + * + * // say we render for showing on the screen + * page.render(mBitmap, null, null, Page.RENDER_MODE_FOR_DISPLAY); + * + * // do stuff with the bitmap + * + * // close the page + * page.close(); + * } + * + * // close the renderer + * renderer.close(); + * </pre> + * + * <h3>Print preview and print output</h3> + * <p> + * If you are using this class to rasterize a PDF for printing or show a print + * preview, it is recommended that you respect the following contract in order + * to provide a consistent user experience when seeing a preview and printing, + * i.e. the user sees a preview that is the same as the printout. + * </p> + * <ul> + * <li> + * Respect the property whether the document would like to be scaled for printing + * as per {@link #shouldScaleForPrinting()}. + * </li> + * <li> + * When scaling a document for printing the aspect ratio should be preserved. + * </li> + * <li> + * Do not inset the content with any margins from the {@link android.print.PrintAttributes} + * as the application is responsible to render it such that the margins are respected. + * </li> + * <li> + * If document page size is greater than the printed media size the content should + * be anchored to the upper left corner of the page for left-to-right locales and + * top right corner for right-to-left locales. + * </li> + * </ul> + * + * @see #close() + */ +public final class PdfRenderer implements AutoCloseable { + /** + * Any call the native pdfium code has to be single threaded as the library does not support + * parallel use. + */ + final static Object sPdfiumLock = new Object(); + + private final CloseGuard mCloseGuard = CloseGuard.get(); + + private final Point mTempPoint = new Point(); + + private long mNativeDocument; + + private final int mPageCount; + + private ParcelFileDescriptor mInput; + + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + private Page mCurrentPage; + + /** @hide */ + @IntDef({ + Page.RENDER_MODE_FOR_DISPLAY, + Page.RENDER_MODE_FOR_PRINT + }) + @Retention(RetentionPolicy.SOURCE) + public @interface RenderMode {} + + /** + * Creates a new instance. + * <p> + * <strong>Note:</strong> The provided file descriptor must be <strong>seekable</strong>, + * i.e. its data being randomly accessed, e.g. pointing to a file. + * </p> + * <p> + * <strong>Note:</strong> This class takes ownership of the passed in file descriptor + * and is responsible for closing it when the renderer is closed. + * </p> + * <p> + * If the file is from an untrusted source it is recommended to run the renderer in a separate, + * isolated process with minimal permissions to limit the impact of security exploits. + * </p> + * + * @param input Seekable file descriptor to read from. + * + * @throws java.io.IOException If an error occurs while reading the file. + * @throws java.lang.SecurityException If the file requires a password or + * the security scheme is not supported. + */ + public PdfRenderer(@NonNull ParcelFileDescriptor input) throws IOException { + if (input == null) { + throw new NullPointerException("input cannot be null"); + } + + final long size; + try { + Os.lseek(input.getFileDescriptor(), 0, OsConstants.SEEK_SET); + size = Os.fstat(input.getFileDescriptor()).st_size; + } catch (ErrnoException ee) { + throw new IllegalArgumentException("file descriptor not seekable"); + } + mInput = input; + + synchronized (sPdfiumLock) { + mNativeDocument = nativeCreate(mInput.getFd(), size); + try { + mPageCount = nativeGetPageCount(mNativeDocument); + } catch (Throwable t) { + nativeClose(mNativeDocument); + mNativeDocument = 0; + throw t; + } + } + + mCloseGuard.open("close"); + } + + /** + * Closes this renderer. You should not use this instance + * after this method is called. + */ + public void close() { + throwIfClosed(); + throwIfPageOpened(); + doClose(); + } + + /** + * Gets the number of pages in the document. + * + * @return The page count. + */ + public int getPageCount() { + throwIfClosed(); + return mPageCount; + } + + /** + * Gets whether the document prefers to be scaled for printing. + * You should take this info account if the document is rendered + * for printing and the target media size differs from the page + * size. + * + * @return If to scale the document. + */ + public boolean shouldScaleForPrinting() { + throwIfClosed(); + + synchronized (sPdfiumLock) { + return nativeScaleForPrinting(mNativeDocument); + } + } + + /** + * Opens a page for rendering. + * + * @param index The page index. + * @return A page that can be rendered. + * + * @see android.graphics.pdf.PdfRenderer.Page#close() PdfRenderer.Page.close() + */ + public Page openPage(int index) { + throwIfClosed(); + throwIfPageOpened(); + throwIfPageNotInDocument(index); + mCurrentPage = new Page(index); + return mCurrentPage; + } + + @Override + protected void finalize() throws Throwable { + try { + if (mCloseGuard != null) { + mCloseGuard.warnIfOpen(); + } + + doClose(); + } finally { + super.finalize(); + } + } + + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + private void doClose() { + if (mCurrentPage != null) { + mCurrentPage.close(); + mCurrentPage = null; + } + + if (mNativeDocument != 0) { + synchronized (sPdfiumLock) { + nativeClose(mNativeDocument); + } + mNativeDocument = 0; + } + + if (mInput != null) { + IoUtils.closeQuietly(mInput); + mInput = null; + } + mCloseGuard.close(); + } + + private void throwIfClosed() { + if (mInput == null) { + throw new IllegalStateException("Already closed"); + } + } + + private void throwIfPageOpened() { + if (mCurrentPage != null) { + throw new IllegalStateException("Current page not closed"); + } + } + + private void throwIfPageNotInDocument(int pageIndex) { + if (pageIndex < 0 || pageIndex >= mPageCount) { + throw new IllegalArgumentException("Invalid page index"); + } + } + + /** + * This class represents a PDF document page for rendering. + */ + public final class Page implements AutoCloseable { + + private final CloseGuard mCloseGuard = CloseGuard.get(); + + /** + * Mode to render the content for display on a screen. + */ + public static final int RENDER_MODE_FOR_DISPLAY = 1; + + /** + * Mode to render the content for printing. + */ + public static final int RENDER_MODE_FOR_PRINT = 2; + + private final int mIndex; + private final int mWidth; + private final int mHeight; + + private long mNativePage; + + private Page(int index) { + Point size = mTempPoint; + synchronized (sPdfiumLock) { + mNativePage = nativeOpenPageAndGetSize(mNativeDocument, index, size); + } + mIndex = index; + mWidth = size.x; + mHeight = size.y; + mCloseGuard.open("close"); + } + + /** + * Gets the page index. + * + * @return The index. + */ + public int getIndex() { + return mIndex; + } + + /** + * Gets the page width in points (1/72"). + * + * @return The width in points. + */ + public int getWidth() { + return mWidth; + } + + /** + * Gets the page height in points (1/72"). + * + * @return The height in points. + */ + public int getHeight() { + return mHeight; + } + + /** + * Renders a page to a bitmap. + * <p> + * You may optionally specify a rectangular clip in the bitmap bounds. No rendering + * outside the clip will be performed, hence it is your responsibility to initialize + * the bitmap outside the clip. + * </p> + * <p> + * You may optionally specify a matrix to transform the content from page coordinates + * which are in points (1/72") to bitmap coordinates which are in pixels. If this + * matrix is not provided this method will apply a transformation that will fit the + * whole page to the destination clip if provided or the destination bitmap if no + * clip is provided. + * </p> + * <p> + * The clip and transformation are useful for implementing tile rendering where the + * destination bitmap contains a portion of the image, for example when zooming. + * Another useful application is for printing where the size of the bitmap holding + * the page is too large and a client can render the page in stripes. + * </p> + * <p> + * <strong>Note: </strong> The destination bitmap format must be + * {@link Config#ARGB_8888 ARGB}. + * </p> + * <p> + * <strong>Note: </strong> The optional transformation matrix must be affine as per + * {@link android.graphics.Matrix#isAffine() Matrix.isAffine()}. Hence, you can specify + * rotation, scaling, translation but not a perspective transformation. + * </p> + * + * @param destination Destination bitmap to which to render. + * @param destClip Optional clip in the bitmap bounds. + * @param transform Optional transformation to apply when rendering. + * @param renderMode The render mode. + * + * @see #RENDER_MODE_FOR_DISPLAY + * @see #RENDER_MODE_FOR_PRINT + */ + public void render(@NonNull Bitmap destination, @Nullable Rect destClip, + @Nullable Matrix transform, @RenderMode int renderMode) { + if (mNativePage == 0) { + throw new NullPointerException(); + } + + destination = Preconditions.checkNotNull(destination, "bitmap null"); + + if (destination.getConfig() != Config.ARGB_8888) { + throw new IllegalArgumentException("Unsupported pixel format"); + } + + if (destClip != null) { + if (destClip.left < 0 || destClip.top < 0 + || destClip.right > destination.getWidth() + || destClip.bottom > destination.getHeight()) { + throw new IllegalArgumentException("destBounds not in destination"); + } + } + + if (transform != null && !transform.isAffine()) { + throw new IllegalArgumentException("transform not affine"); + } + + if (renderMode != RENDER_MODE_FOR_PRINT && renderMode != RENDER_MODE_FOR_DISPLAY) { + throw new IllegalArgumentException("Unsupported render mode"); + } + + if (renderMode == RENDER_MODE_FOR_PRINT && renderMode == RENDER_MODE_FOR_DISPLAY) { + throw new IllegalArgumentException("Only single render mode supported"); + } + + final int contentLeft = (destClip != null) ? destClip.left : 0; + final int contentTop = (destClip != null) ? destClip.top : 0; + final int contentRight = (destClip != null) ? destClip.right + : destination.getWidth(); + final int contentBottom = (destClip != null) ? destClip.bottom + : destination.getHeight(); + + // If transform is not set, stretch page to whole clipped area + if (transform == null) { + int clipWidth = contentRight - contentLeft; + int clipHeight = contentBottom - contentTop; + + transform = new Matrix(); + transform.postScale((float)clipWidth / getWidth(), + (float)clipHeight / getHeight()); + transform.postTranslate(contentLeft, contentTop); + } + + // FIXME: This code is planned to be outside the UI rendering module, so it should not + // be able to access native instances from Bitmap, Matrix, etc. + final long transformPtr = transform.ni(); + + synchronized (sPdfiumLock) { + nativeRenderPage(mNativeDocument, mNativePage, destination.getNativeInstance(), + contentLeft, contentTop, contentRight, contentBottom, transformPtr, + renderMode); + } + } + + /** + * Closes this page. + * + * @see android.graphics.pdf.PdfRenderer#openPage(int) + */ + @Override + public void close() { + throwIfClosed(); + doClose(); + } + + @Override + protected void finalize() throws Throwable { + try { + if (mCloseGuard != null) { + mCloseGuard.warnIfOpen(); + } + + doClose(); + } finally { + super.finalize(); + } + } + + private void doClose() { + if (mNativePage != 0) { + synchronized (sPdfiumLock) { + nativeClosePage(mNativePage); + } + mNativePage = 0; + } + + mCloseGuard.close(); + mCurrentPage = null; + } + + private void throwIfClosed() { + if (mNativePage == 0) { + throw new IllegalStateException("Already closed"); + } + } + } + + private static native long nativeCreate(int fd, long size); + private static native void nativeClose(long documentPtr); + private static native int nativeGetPageCount(long documentPtr); + private static native boolean nativeScaleForPrinting(long documentPtr); + private static native void nativeRenderPage(long documentPtr, long pagePtr, long bitmapHandle, + int clipLeft, int clipTop, int clipRight, int clipBottom, long transformPtr, + int renderMode); + private static native long nativeOpenPageAndGetSize(long documentPtr, int pageIndex, + Point outSize); + private static native void nativeClosePage(long pagePtr); +} 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/color/desktop_mode_caption_button_color_selector_dark.xml b/libs/WindowManager/Shell/res/color/desktop_mode_caption_button_color_selector_dark.xml new file mode 100644 index 000000000000..52a59671baa1 --- /dev/null +++ b/libs/WindowManager/Shell/res/color/desktop_mode_caption_button_color_selector_dark.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. + --> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_hovered="true" + android:color="@color/desktop_mode_caption_button_on_hover_dark"/> + <item android:color="@color/desktop_mode_caption_button"/> +</selector>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/res/color/desktop_mode_caption_button_color_selector_light.xml b/libs/WindowManager/Shell/res/color/desktop_mode_caption_button_color_selector_light.xml new file mode 100644 index 000000000000..6d8a51cd6f8f --- /dev/null +++ b/libs/WindowManager/Shell/res/color/desktop_mode_caption_button_color_selector_light.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. + --> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_hovered="true" + android:color="@color/desktop_mode_caption_button_on_hover_light"/> + <item android:color="@color/desktop_mode_caption_button"/> +</selector>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/res/drawable/circular_progress.xml b/libs/WindowManager/Shell/res/drawable/circular_progress.xml new file mode 100644 index 000000000000..948264579e1d --- /dev/null +++ b/libs/WindowManager/Shell/res/drawable/circular_progress.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. + --> + +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:id="@android:id/progress"> + <rotate + android:pivotX="50%" + android:pivotY="50%" + android:fromDegrees="275" + android:toDegrees="275"> + <shape + android:shape="ring" + android:thickness="3dp" + android:innerRadius="17dp" + android:useLevel="true"> + </shape> + </rotate> + </item> +</layer-list>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/res/drawable/rounded_button.xml b/libs/WindowManager/Shell/res/drawable/rounded_button.xml new file mode 100644 index 000000000000..17a0bab56a74 --- /dev/null +++ b/libs/WindowManager/Shell/res/drawable/rounded_button.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright (C) 2024 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <corners android:radius="20dp" /> +</shape>
\ No newline at end of file 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 e4f793c2665b..d1b1af3e77ab 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 @@ -74,17 +74,11 @@ android:layout_height="40dp" android:layout_weight="1"/> - <ImageButton - android:id="@+id/maximize_window" - android:layout_width="40dp" - android:layout_height="40dp" - android:padding="9dp" - android:layout_marginEnd="8dp" - android:contentDescription="@string/maximize_button_text" - android:src="@drawable/decor_desktop_mode_maximize_button_dark" - android:scaleType="fitCenter" - android:gravity="end" - android:background="@null"/> + <com.android.wm.shell.windowdecor.MaximizeButtonView + android:id="@+id/maximize_button_view" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="end"/> <ImageButton android:id="@+id/close_window" diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_maximize_menu.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_maximize_menu.xml index 0db72f7be8e6..dbfd6e5d8d94 100644 --- a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_maximize_menu.xml +++ b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_maximize_menu.xml @@ -15,6 +15,7 @@ ~ limitations under the License. --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/maximize_menu" style="?android:attr/buttonBarStyle" android:layout_width="@dimen/desktop_mode_maximize_menu_width" android:layout_height="@dimen/desktop_mode_maximize_menu_height" diff --git a/libs/WindowManager/Shell/res/layout/maximize_menu_button.xml b/libs/WindowManager/Shell/res/layout/maximize_menu_button.xml new file mode 100644 index 000000000000..bb6efcec1a70 --- /dev/null +++ b/libs/WindowManager/Shell/res/layout/maximize_menu_button.xml @@ -0,0 +1,36 @@ +<?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. + --> + +<merge xmlns:android="http://schemas.android.com/apk/res/android"> + <ProgressBar + android:id="@+id/progress_bar" + style="?android:attr/progressBarStyleHorizontal" + android:progressDrawable="@drawable/circular_progress" + android:layout_width="40dp" + android:layout_height="40dp" + android:indeterminate="false" + android:visibility="invisible"/> + + <ImageButton + android:id="@+id/maximize_window" + android:layout_width="40dp" + android:layout_height="40dp" + android:padding="9dp" + android:contentDescription="@string/maximize_button_text" + android:src="@drawable/decor_desktop_mode_maximize_button_dark" + android:scaleType="fitCenter" + android:background="@drawable/rounded_button"/> +</merge>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/res/values/colors.xml b/libs/WindowManager/Shell/res/values/colors.xml index fae71efe3b39..758dbfd5f3c5 100644 --- a/libs/WindowManager/Shell/res/values/colors.xml +++ b/libs/WindowManager/Shell/res/values/colors.xml @@ -66,4 +66,9 @@ <color name="desktop_mode_maximize_menu_button_outline">#797869</color> <color name="desktop_mode_maximize_menu_button_outline_on_hover">#606219</color> <color name="desktop_mode_maximize_menu_button_on_hover">#E7E790</color> + <color name="desktop_mode_maximize_menu_progress_light">#33000000</color> + <color name="desktop_mode_maximize_menu_progress_dark">#33FFFFFF</color> + <color name="desktop_mode_caption_button_on_hover_light">#11000000</color> + <color name="desktop_mode_caption_button_on_hover_dark">#11FFFFFF</color> + <color name="desktop_mode_caption_button">#00000000</color> </resources> 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 369258e15454..15350fb19209 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 @@ -122,6 +122,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.Optional; @@ -247,6 +248,9 @@ public class BubbleController implements ConfigurationChangeListener, /** Saved font scale, used to detect font size changes in {@link #onConfigurationChanged}. */ private float mFontScale = 0; + /** Saved locale, used to detect local changes in {@link #onConfigurationChanged}. */ + private Locale mLocale = null; + /** Saved direction, used to detect layout direction changes @link #onConfigChanged}. */ private int mLayoutDirection = View.LAYOUT_DIRECTION_UNDEFINED; @@ -1068,6 +1072,11 @@ public class BubbleController implements ConfigurationChangeListener, mLayoutDirection = newConfig.getLayoutDirection(); mStackView.onLayoutDirectionChanged(mLayoutDirection); } + Locale newLocale = newConfig.locale; + if (newLocale != null && !newLocale.equals(mLocale)) { + mLocale = newLocale; + mStackView.updateLocale(); + } } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java index 123693db3622..74f087b6d8f8 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java @@ -517,6 +517,15 @@ public class BubbleExpandedView extends LinearLayout { } } + void updateLocale() { + if (mManageButton != null) { + mManageButton.setText(mContext.getString(R.string.manage_bubbles_text)); + } + if (mOverflowView != null) { + mOverflowView.updateLocale(); + } + } + void applyThemeAttrs() { final TypedArray ta = mContext.obtainStyledAttributes(new int[]{ android.R.attr.dialogCornerRadius, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java index b06de4f4002c..633b01bde4ca 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java @@ -242,6 +242,11 @@ public class BubbleOverflowContainerView extends LinearLayout { mEmptyStateSubtitle.setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize); } + public void updateLocale() { + mEmptyStateTitle.setText(mContext.getString(R.string.bubble_overflow_empty_title)); + mEmptyStateSubtitle.setText(mContext.getString(R.string.bubble_overflow_empty_subtitle)); + } + private final BubbleData.Listener mDataListener = new BubbleData.Listener() { @Override diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java index e7da034a7422..8fd6ffe15cfe 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java @@ -1452,6 +1452,12 @@ public class BubbleStackView extends FrameLayout } } + void updateLocale() { + if (mBubbleOverflow != null && mBubbleOverflow.getExpandedView() != null) { + mBubbleOverflow.getExpandedView().updateLocale(); + } + } + private void updateOverflow() { mBubbleOverflow.update(); mBubbleContainer.reorderView(mBubbleOverflow.getIconView(), diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/OWNERS index 8271014d290e..08c70314973e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/OWNERS +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/OWNERS @@ -1,2 +1,6 @@ # WM shell sub-module bubble owner madym@google.com +atsjenk@google.com +liranb@google.com +sukeshram@google.com +mpodolian@google.com 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/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..dcffb2d3e8fa 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( @@ -551,11 +548,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 +603,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()) } /** @@ -1233,13 +1228,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/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/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 57e964f15d50..c1406d052195 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,11 +22,12 @@ 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_HOVER_ENTER; +import static android.view.MotionEvent.ACTION_HOVER_EXIT; 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; @@ -311,8 +312,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { private class DesktopModeTouchEventListener extends GestureDetector.SimpleOnGestureListener implements View.OnClickListener, View.OnTouchListener, View.OnLongClickListener, - DragDetector.MotionEventHandler { - + View.OnGenericMotionListener , DragDetector.MotionEventHandler { + private static final int CLOSE_MAXIMIZE_MENU_DELAY_MS = 150; private final int mTaskId; private final WindowContainerToken mTaskToken; private final DragPositioningCallback mDragPositioningCallback; @@ -323,6 +324,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { private boolean mHasLongClicked; private boolean mShouldClick; private int mDragPointerId = -1; + private final Runnable mCloseMaximizeWindowRunnable; private DesktopModeTouchEventListener( RunningTaskInfo taskInfo, @@ -332,6 +334,11 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { mDragPositioningCallback = dragPositioningCallback; mDragDetector = new DragDetector(this); mGestureDetector = new GestureDetector(mContext, this); + mCloseMaximizeWindowRunnable = () -> { + final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(mTaskId); + if (decoration == null) return; + decoration.closeMaximizeMenu(); + }; } @Override @@ -387,13 +394,10 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { mDesktopTasksController.ifPresent(c -> c.moveToNextDisplay(mTaskId)); } } else if (id == R.id.maximize_window) { - if (decoration.isMaximizeMenuActive()) { - decoration.closeMaximizeMenu(); - return; - } final RunningTaskInfo taskInfo = decoration.mTaskInfo; - mDesktopTasksController.ifPresent(c -> c.toggleDesktopTaskSize(taskInfo)); decoration.closeHandleMenu(); + decoration.closeMaximizeMenu(); + mDesktopTasksController.ifPresent(c -> c.toggleDesktopTaskSize(taskInfo)); } else if (id == R.id.maximize_menu_maximize_button) { final RunningTaskInfo taskInfo = decoration.mTaskInfo; mDesktopTasksController.ifPresent(c -> c.toggleDesktopTaskSize(taskInfo)); @@ -460,6 +464,36 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { return false; } + @Override + public boolean onGenericMotion(View v, MotionEvent ev) { + final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(mTaskId); + final int id = v.getId(); + if (ev.getAction() == ACTION_HOVER_ENTER) { + if (!decoration.isMaximizeMenuActive() && id == R.id.maximize_window) { + decoration.onMaximizeWindowHoverEnter(); + } else if (id == R.id.maximize_window + || MaximizeMenu.Companion.isMaximizeMenuView(id)) { + // Re-hovering over any of the maximize menu views should keep the menu open by + // cancelling any attempts to close the menu. + mMainHandler.removeCallbacks(mCloseMaximizeWindowRunnable); + } + return true; + } else if (ev.getAction() == ACTION_HOVER_EXIT) { + if (!decoration.isMaximizeMenuActive() && id == R.id.maximize_window) { + decoration.onMaximizeWindowHoverExit(); + } else if (id == R.id.maximize_window + || MaximizeMenu.Companion.isMaximizeMenuView(id)) { + // Close menu if not hovering over maximize menu or maximize button after a + // delay to give user a chance to re-enter view or to move from one maximize + // menu view to another. + mMainHandler.postDelayed(mCloseMaximizeWindowRunnable, + CLOSE_MAXIMIZE_MENU_DELAY_MS); + } + return true; + } + return false; + } + private void moveTaskToFront(RunningTaskInfo taskInfo) { if (!taskInfo.isFocused) { mDesktopTasksController.ifPresent(c -> c.moveTaskToFront(taskInfo)); @@ -789,16 +823,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; } /** @@ -840,7 +874,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { c -> { c.onDragPositioningEndThroughStatusBar(relevantDecor.mTaskInfo, calculateFreeformBounds(ev.getDisplayId(), - FINAL_FREEFORM_SCALE)); + DesktopTasksController + .DESKTOP_MODE_INITIAL_BOUNDS_SCALE)); }); } }); @@ -990,7 +1025,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { new DesktopModeTouchEventListener(taskInfo, dragPositioningCallback); windowDecoration.setCaptionListeners( - touchEventListener, touchEventListener, touchEventListener); + touchEventListener, touchEventListener, touchEventListener, touchEventListener); windowDecoration.setExclusionRegionListener(mExclusionRegionListener); windowDecoration.setDragPositioningCallback(dragPositioningCallback); windowDecoration.setDragDetector(touchEventListener.mDragDetector); @@ -1036,6 +1071,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { return; } decoration.showResizeVeil(t, bounds); + decoration.setAnimatingTaskResize(true); } @Override @@ -1050,6 +1086,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(taskId); if (decoration == null) return; decoration.hideResizeVeil(); + decoration.setAnimatingTaskResize(false); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java index 185365b2a501..74f460bf1226 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java @@ -60,6 +60,8 @@ import com.android.wm.shell.windowdecor.viewholder.DesktopModeAppControlsWindowD import com.android.wm.shell.windowdecor.viewholder.DesktopModeFocusedWindowDecorationViewHolder; import com.android.wm.shell.windowdecor.viewholder.DesktopModeWindowDecorationViewHolder; +import kotlin.Unit; + import java.util.function.Supplier; /** @@ -79,6 +81,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin private View.OnClickListener mOnCaptionButtonClickListener; private View.OnTouchListener mOnCaptionTouchListener; private View.OnLongClickListener mOnCaptionLongClickListener; + private View.OnGenericMotionListener mOnCaptionGenericMotionListener; private DragPositioningCallback mDragPositioningCallback; private DragResizeInputListener mDragResizeListener; private DragDetector mDragDetector; @@ -152,10 +155,12 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin void setCaptionListeners( View.OnClickListener onCaptionButtonClickListener, View.OnTouchListener onCaptionTouchListener, - View.OnLongClickListener onLongClickListener) { + View.OnLongClickListener onLongClickListener, + View.OnGenericMotionListener onGenericMotionListener) { mOnCaptionButtonClickListener = onCaptionButtonClickListener; mOnCaptionTouchListener = onCaptionTouchListener; mOnCaptionLongClickListener = onLongClickListener; + mOnCaptionGenericMotionListener = onGenericMotionListener; } void setExclusionRegionListener(ExclusionRegionListener exclusionRegionListener) { @@ -225,9 +230,15 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin mOnCaptionTouchListener, mOnCaptionButtonClickListener, mOnCaptionLongClickListener, + mOnCaptionGenericMotionListener, mAppName, - mAppIconBitmap - ); + mAppIconBitmap, + () -> { + if (!isMaximizeMenuActive()) { + createMaximizeMenu(); + } + return Unit.INSTANCE; + }); } else { throw new IllegalArgumentException("Unexpected layout resource id"); } @@ -548,7 +559,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin */ void createMaximizeMenu() { mMaximizeMenu = new MaximizeMenu(mSyncQueue, mRootTaskDisplayAreaOrganizer, - mDisplayController, mTaskInfo, mOnCaptionButtonClickListener, mContext, + mDisplayController, mTaskInfo, mOnCaptionButtonClickListener, + mOnCaptionGenericMotionListener, mOnCaptionTouchListener, mContext, calculateMaximizeMenuPosition(), mSurfaceControlTransactionSupplier); mMaximizeMenu.show(); } @@ -776,6 +788,22 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin return R.id.desktop_mode_caption; } + void setAnimatingTaskResize(boolean animatingTaskResize) { + if (mRelayoutParams.mLayoutResId == R.layout.desktop_mode_focused_window_decor) return; + ((DesktopModeAppControlsWindowDecorationViewHolder) mWindowDecorViewHolder) + .setAnimatingTaskResize(animatingTaskResize); + } + + void onMaximizeWindowHoverExit() { + ((DesktopModeAppControlsWindowDecorationViewHolder) mWindowDecorViewHolder) + .onMaximizeWindowHoverExit(); + } + + void onMaximizeWindowHoverEnter() { + ((DesktopModeAppControlsWindowDecorationViewHolder) mWindowDecorViewHolder) + .onMaximizeWindowHoverEnter(); + } + @Override public String toString() { return "{" diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeButtonView.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeButtonView.kt new file mode 100644 index 000000000000..b2f8cfdbfb7a --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeButtonView.kt @@ -0,0 +1,106 @@ +/* + * 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.windowdecor + +import android.animation.AnimatorSet +import android.animation.ObjectAnimator +import android.animation.ValueAnimator +import android.content.Context +import android.content.res.ColorStateList +import android.util.AttributeSet +import android.view.LayoutInflater +import android.view.View +import android.widget.FrameLayout +import android.widget.ImageButton +import android.widget.ProgressBar +import androidx.core.animation.doOnEnd +import androidx.core.animation.doOnStart +import androidx.core.content.ContextCompat +import com.android.wm.shell.R + +private const val OPEN_MAXIMIZE_MENU_DELAY_ON_HOVER_MS = 350 +private const val MAX_DRAWABLE_ALPHA = 255 + +class MaximizeButtonView( + context: Context, + attrs: AttributeSet +) : FrameLayout(context, attrs) { + lateinit var onHoverAnimationFinishedListener: () -> Unit + private val hoverProgressAnimatorSet = AnimatorSet() + var hoverDisabled = false + + private val progressBar: ProgressBar + private val maximizeWindow: ImageButton + + init { + LayoutInflater.from(context).inflate(R.layout.maximize_menu_button, this, true) + + progressBar = requireViewById(R.id.progress_bar) + maximizeWindow = requireViewById(R.id.maximize_window) + } + + fun startHoverAnimation() { + if (hoverDisabled) return + if (hoverProgressAnimatorSet.isRunning) { + cancelHoverAnimation() + } + + maximizeWindow.background.alpha = 0 + + hoverProgressAnimatorSet.playSequentially( + ValueAnimator.ofInt(0, MAX_DRAWABLE_ALPHA) + .setDuration(50) + .apply { + addUpdateListener { + maximizeWindow.background.alpha = animatedValue as Int + } + }, + ObjectAnimator.ofInt(progressBar, "progress", 100) + .setDuration(OPEN_MAXIMIZE_MENU_DELAY_ON_HOVER_MS.toLong()) + .apply { + doOnStart { + progressBar.setProgress(0, false) + progressBar.visibility = View.VISIBLE + } + doOnEnd { + progressBar.visibility = View.INVISIBLE + onHoverAnimationFinishedListener() + } + } + ) + hoverProgressAnimatorSet.start() + } + + fun cancelHoverAnimation() { + hoverProgressAnimatorSet.removeAllListeners() + hoverProgressAnimatorSet.cancel() + progressBar.visibility = View.INVISIBLE + } + + fun setAnimationTints(darkMode: Boolean) { + if (darkMode) { + progressBar.progressTintList = ColorStateList.valueOf( + resources.getColor(R.color.desktop_mode_maximize_menu_progress_dark)) + maximizeWindow.background?.setTintList(ContextCompat.getColorStateList(context, + R.color.desktop_mode_caption_button_color_selector_dark)) + } else { + progressBar.progressTintList = ColorStateList.valueOf( + resources.getColor(R.color.desktop_mode_maximize_menu_progress_light)) + maximizeWindow.background?.setTintList(ContextCompat.getColorStateList(context, + R.color.desktop_mode_caption_button_color_selector_light)) + } + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt index 794b357c9f16..b82f7ca47ef3 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt @@ -16,6 +16,7 @@ package com.android.wm.shell.windowdecor +import android.annotation.IdRes import android.app.ActivityManager.RunningTaskInfo import android.content.Context import android.content.res.Resources @@ -27,6 +28,8 @@ import android.view.SurfaceControl import android.view.SurfaceControl.Transaction import android.view.SurfaceControlViewHost import android.view.View.OnClickListener +import android.view.View.OnGenericMotionListener +import android.view.View.OnTouchListener import android.view.WindowManager import android.view.WindowlessWindowManager import android.widget.Button @@ -49,6 +52,8 @@ class MaximizeMenu( private val displayController: DisplayController, private val taskInfo: RunningTaskInfo, private val onClickListener: OnClickListener, + private val onGenericMotionListener: OnGenericMotionListener, + private val onTouchListener: OnTouchListener, private val decorWindowContext: Context, private val menuPosition: PointF, private val transactionSupplier: Supplier<Transaction> = Supplier { Transaction() } @@ -142,15 +147,26 @@ class MaximizeMenu( private fun setupMaximizeMenu() { val maximizeMenuView = maximizeMenu?.mWindowViewHost?.view ?: return - maximizeMenuView.requireViewById<Button>( + maximizeMenuView.setOnGenericMotionListener(onGenericMotionListener) + maximizeMenuView.setOnTouchListener(onTouchListener) + + val maximizeButton = maximizeMenuView.requireViewById<Button>( R.id.maximize_menu_maximize_button - ).setOnClickListener(onClickListener) - maximizeMenuView.requireViewById<Button>( + ) + maximizeButton.setOnClickListener(onClickListener) + maximizeButton.setOnGenericMotionListener(onGenericMotionListener) + + val snapRightButton = maximizeMenuView.requireViewById<Button>( R.id.maximize_menu_snap_right_button - ).setOnClickListener(onClickListener) - maximizeMenuView.requireViewById<Button>( + ) + snapRightButton.setOnClickListener(onClickListener) + snapRightButton.setOnGenericMotionListener(onGenericMotionListener) + + val snapLeftButton = maximizeMenuView.requireViewById<Button>( R.id.maximize_menu_snap_left_button - ).setOnClickListener(onClickListener) + ) + snapLeftButton.setOnClickListener(onClickListener) + snapLeftButton.setOnGenericMotionListener(onGenericMotionListener) } /** @@ -173,4 +189,12 @@ class MaximizeMenu( private fun viewsLaidOut(): Boolean { return maximizeMenu?.mWindowViewHost?.view?.isLaidOut ?: false } + + companion object { + fun isMaximizeMenuView(@IdRes viewId: Int): Boolean { + return viewId == R.id.maximize_menu || viewId == R.id.maximize_menu_maximize_button || + viewId == R.id.maximize_menu_snap_left_button || + viewId == R.id.maximize_menu_snap_right_button + } + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt index 2309c54b6591..7e5b9bd649f2 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt @@ -21,6 +21,7 @@ import com.android.internal.R.attr.materialColorSurfaceContainerHigh import com.android.internal.R.attr.materialColorSurfaceContainerLow import com.android.internal.R.attr.materialColorSurfaceDim import com.android.wm.shell.R +import com.android.wm.shell.windowdecor.MaximizeButtonView /** * A desktop mode window decoration used when the window is floating (i.e. freeform). It hosts @@ -32,8 +33,10 @@ internal class DesktopModeAppControlsWindowDecorationViewHolder( onCaptionTouchListener: View.OnTouchListener, onCaptionButtonClickListener: View.OnClickListener, onLongClickListener: OnLongClickListener, + onCaptionGenericMotionListener: View.OnGenericMotionListener, appName: CharSequence, - appIconBitmap: Bitmap + appIconBitmap: Bitmap, + onMaximizeHoverAnimationFinishedListener: () -> Unit ) : DesktopModeWindowDecorationViewHolder(rootView) { private val captionView: View = rootView.requireViewById(R.id.desktop_mode_caption) @@ -41,6 +44,8 @@ internal class DesktopModeAppControlsWindowDecorationViewHolder( private val openMenuButton: View = rootView.requireViewById(R.id.open_menu_button) private val closeWindowButton: ImageButton = rootView.requireViewById(R.id.close_window) private val expandMenuButton: ImageButton = rootView.requireViewById(R.id.expand_menu_button) + private val maximizeButtonView: MaximizeButtonView = + rootView.requireViewById(R.id.maximize_button_view) private val maximizeWindowButton: ImageButton = rootView.requireViewById(R.id.maximize_window) private val appNameTextView: TextView = rootView.requireViewById(R.id.application_name) private val appIconImageView: ImageView = rootView.requireViewById(R.id.application_icon) @@ -55,10 +60,13 @@ internal class DesktopModeAppControlsWindowDecorationViewHolder( closeWindowButton.setOnClickListener(onCaptionButtonClickListener) maximizeWindowButton.setOnClickListener(onCaptionButtonClickListener) maximizeWindowButton.setOnTouchListener(onCaptionTouchListener) + maximizeWindowButton.setOnGenericMotionListener(onCaptionGenericMotionListener) maximizeWindowButton.onLongClickListener = onLongClickListener closeWindowButton.setOnTouchListener(onCaptionTouchListener) appNameTextView.text = appName appIconImageView.setImageBitmap(appIconBitmap) + maximizeButtonView.onHoverAnimationFinishedListener = + onMaximizeHoverAnimationFinishedListener } override fun bindData(taskInfo: RunningTaskInfo) { @@ -73,12 +81,30 @@ internal class DesktopModeAppControlsWindowDecorationViewHolder( maximizeWindowButton.imageAlpha = alpha closeWindowButton.imageAlpha = alpha expandMenuButton.imageAlpha = alpha + + maximizeButtonView.setAnimationTints(isDarkMode()) } override fun onHandleMenuOpened() {} override fun onHandleMenuClosed() {} + fun setAnimatingTaskResize(animatingTaskResize: Boolean) { + // If animating a task resize, cancel any running hover animations + if (animatingTaskResize) { + maximizeButtonView.cancelHoverAnimation() + } + maximizeButtonView.hoverDisabled = animatingTaskResize + } + + fun onMaximizeWindowHoverExit() { + maximizeButtonView.cancelHoverAnimation() + } + + fun onMaximizeWindowHoverEnter() { + maximizeButtonView.startHoverAnimation() + } + @ColorInt private fun getCaptionBackgroundColor(taskInfo: RunningTaskInfo): Int { if (isTransparentBackgroundRequested(taskInfo)) { 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..ac7380f83233 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 * ``` 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/hwui/Android.bp b/libs/hwui/Android.bp index abd84de7da3c..40239b8c2719 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -428,6 +428,7 @@ cc_defaults { "jni/MovieImpl.cpp", "jni/pdf/PdfDocument.cpp", "jni/pdf/PdfEditor.cpp", + "jni/pdf/PdfRenderer.cpp", "jni/pdf/PdfUtils.cpp", ], shared_libs: [ 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/hwui/apex/jni_runtime.cpp b/libs/hwui/apex/jni_runtime.cpp index fb0cdb034575..883f273b5d3d 100644 --- a/libs/hwui/apex/jni_runtime.cpp +++ b/libs/hwui/apex/jni_runtime.cpp @@ -70,6 +70,7 @@ extern int register_android_graphics_fonts_Font(JNIEnv* env); extern int register_android_graphics_fonts_FontFamily(JNIEnv* env); extern int register_android_graphics_pdf_PdfDocument(JNIEnv* env); extern int register_android_graphics_pdf_PdfEditor(JNIEnv* env); +extern int register_android_graphics_pdf_PdfRenderer(JNIEnv* env); extern int register_android_graphics_text_MeasuredText(JNIEnv* env); extern int register_android_graphics_text_LineBreaker(JNIEnv *env); extern int register_android_graphics_text_TextShaper(JNIEnv *env); @@ -141,6 +142,7 @@ extern int register_android_graphics_HardwareBufferRenderer(JNIEnv* env); REG_JNI(register_android_graphics_fonts_FontFamily), REG_JNI(register_android_graphics_pdf_PdfDocument), REG_JNI(register_android_graphics_pdf_PdfEditor), + REG_JNI(register_android_graphics_pdf_PdfRenderer), REG_JNI(register_android_graphics_text_MeasuredText), REG_JNI(register_android_graphics_text_LineBreaker), REG_JNI(register_android_graphics_text_TextShaper), diff --git a/libs/hwui/jni/pdf/PdfRenderer.cpp b/libs/hwui/jni/pdf/PdfRenderer.cpp new file mode 100644 index 000000000000..cc1f96197c74 --- /dev/null +++ b/libs/hwui/jni/pdf/PdfRenderer.cpp @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2014 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. + */ + +#include "PdfUtils.h" + +#include "GraphicsJNI.h" +#include "SkBitmap.h" +#include "SkMatrix.h" +#include "fpdfview.h" + +#include <vector> +#include <utils/Log.h> +#include <unistd.h> +#include <sys/types.h> +#include <unistd.h> + +namespace android { + +static const int RENDER_MODE_FOR_DISPLAY = 1; +static const int RENDER_MODE_FOR_PRINT = 2; + +static struct { + jfieldID x; + jfieldID y; +} gPointClassInfo; + +static jlong nativeOpenPageAndGetSize(JNIEnv* env, jclass thiz, jlong documentPtr, + jint pageIndex, jobject outSize) { + FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr); + + FPDF_PAGE page = FPDF_LoadPage(document, pageIndex); + if (!page) { + jniThrowException(env, "java/lang/IllegalStateException", + "cannot load page"); + return -1; + } + + double width = 0; + double height = 0; + + int result = FPDF_GetPageSizeByIndex(document, pageIndex, &width, &height); + if (!result) { + jniThrowException(env, "java/lang/IllegalStateException", + "cannot get page size"); + return -1; + } + + env->SetIntField(outSize, gPointClassInfo.x, width); + env->SetIntField(outSize, gPointClassInfo.y, height); + + return reinterpret_cast<jlong>(page); +} + +static void nativeClosePage(JNIEnv* env, jclass thiz, jlong pagePtr) { + FPDF_PAGE page = reinterpret_cast<FPDF_PAGE>(pagePtr); + FPDF_ClosePage(page); +} + +static void nativeRenderPage(JNIEnv* env, jclass thiz, jlong documentPtr, jlong pagePtr, + jlong bitmapPtr, jint clipLeft, jint clipTop, jint clipRight, jint clipBottom, + jlong transformPtr, jint renderMode) { + FPDF_PAGE page = reinterpret_cast<FPDF_PAGE>(pagePtr); + + SkBitmap skBitmap; + bitmap::toBitmap(bitmapPtr).getSkBitmap(&skBitmap); + + const int stride = skBitmap.width() * 4; + + FPDF_BITMAP bitmap = FPDFBitmap_CreateEx(skBitmap.width(), skBitmap.height(), + FPDFBitmap_BGRA, skBitmap.getPixels(), stride); + + int renderFlags = FPDF_REVERSE_BYTE_ORDER; + if (renderMode == RENDER_MODE_FOR_DISPLAY) { + renderFlags |= FPDF_LCD_TEXT; + } else if (renderMode == RENDER_MODE_FOR_PRINT) { + renderFlags |= FPDF_PRINTING; + } + + SkMatrix matrix = *reinterpret_cast<SkMatrix*>(transformPtr); + SkScalar transformValues[6]; + if (!matrix.asAffine(transformValues)) { + jniThrowException(env, "java/lang/IllegalArgumentException", + "transform matrix has perspective. Only affine matrices are allowed."); + return; + } + + FS_MATRIX transform = {transformValues[SkMatrix::kAScaleX], transformValues[SkMatrix::kASkewY], + transformValues[SkMatrix::kASkewX], transformValues[SkMatrix::kAScaleY], + transformValues[SkMatrix::kATransX], + transformValues[SkMatrix::kATransY]}; + + FS_RECTF clip = {(float) clipLeft, (float) clipTop, (float) clipRight, (float) clipBottom}; + + FPDF_RenderPageBitmapWithMatrix(bitmap, page, &transform, &clip, renderFlags); + + skBitmap.notifyPixelsChanged(); +} + +static const JNINativeMethod gPdfRenderer_Methods[] = { + {"nativeCreate", "(IJ)J", (void*) nativeOpen}, + {"nativeClose", "(J)V", (void*) nativeClose}, + {"nativeGetPageCount", "(J)I", (void*) nativeGetPageCount}, + {"nativeScaleForPrinting", "(J)Z", (void*) nativeScaleForPrinting}, + {"nativeRenderPage", "(JJJIIIIJI)V", (void*) nativeRenderPage}, + {"nativeOpenPageAndGetSize", "(JILandroid/graphics/Point;)J", (void*) nativeOpenPageAndGetSize}, + {"nativeClosePage", "(J)V", (void*) nativeClosePage} +}; + +int register_android_graphics_pdf_PdfRenderer(JNIEnv* env) { + int result = RegisterMethodsOrDie( + env, "android/graphics/pdf/PdfRenderer", gPdfRenderer_Methods, + NELEM(gPdfRenderer_Methods)); + + jclass clazz = FindClassOrDie(env, "android/graphics/Point"); + gPointClassInfo.x = GetFieldIDOrDie(env, clazz, "x", "I"); + gPointClassInfo.y = GetFieldIDOrDie(env, clazz, "y", "I"); + + return result; +}; + +}; 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/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..0fb7c95e3680 100644 --- a/nfc/api/current.txt +++ b/nfc/api/current.txt @@ -204,7 +204,7 @@ 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); diff --git a/nfc/java/android/nfc/INfcCardEmulation.aidl b/nfc/java/android/nfc/INfcCardEmulation.aidl index 65d0625f251e..64f7fa44c12f 100644 --- a/nfc/java/android/nfc/INfcCardEmulation.aidl +++ b/nfc/java/android/nfc/INfcCardEmulation.aidl @@ -32,7 +32,7 @@ interface INfcCardEmulation boolean setDefaultForNextTap(int userHandle, in ComponentName service); boolean setDefaultToObserveModeForService(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..e62e37bd4ca0 100644 --- a/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java +++ b/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java @@ -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..47ddd9de224f 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"; @@ -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/values/colors.xml b/packages/CredentialManager/res/values/colors.xml index 7cb1d01972b7..b4d2eeb3bd0f 100644 --- a/packages/CredentialManager/res/values/colors.xml +++ b/packages/CredentialManager/res/values/colors.xml @@ -22,4 +22,7 @@ <color name="dropdown_container">#F3F3FA</color> <color name="sign_in_options_container">#DADADA</color> <color name="sign_in_options_icon_color">#1B1B1B</color> + + <!-- These colors are used for Inline Suggestions. --> + <color name="inline_background">#FFFFFF</color> </resources>
\ No newline at end of file diff --git a/packages/CredentialManager/res/values/dimens.xml b/packages/CredentialManager/res/values/dimens.xml index b47a4dc2b76f..350920b23c69 100644 --- a/packages/CredentialManager/res/values/dimens.xml +++ b/packages/CredentialManager/res/values/dimens.xml @@ -28,4 +28,6 @@ <dimen name="dropdown_layout_horizontal_margin">24dp</dimen> <integer name="autofill_max_visible_datasets">5</integer> <dimen name="dropdown_touch_target_min_height">48dp</dimen> + <dimen name="horizontal_chip_padding">8dp</dimen> + <dimen name="vertical_chip_padding">6dp</dimen> </resources>
\ 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..02320a193602 100644 --- a/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/CredentialKtx.kt +++ b/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/CredentialKtx.kt @@ -127,10 +127,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, ) ) } @@ -148,10 +148,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, ) ) } @@ -170,10 +170,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/autofill/CredentialAutofillService.kt b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt index eef75c7b707b..28c42fb3f86c 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt @@ -57,6 +57,7 @@ import androidx.credentials.provider.CustomCredentialEntry import androidx.credentials.provider.PasswordCredentialEntry import androidx.credentials.provider.PublicKeyCredentialEntry import com.android.credentialmanager.GetFlowUtils +import com.android.credentialmanager.common.ui.InlinePresentationsFactory import com.android.credentialmanager.common.ui.RemoteViewsFactory import com.android.credentialmanager.getflow.ProviderDisplayInfo import com.android.credentialmanager.getflow.toProviderDisplayInfo @@ -212,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) { @@ -228,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, @@ -266,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 @@ -294,8 +297,12 @@ class CredentialAutofillService : AutofillService() { } else { inlinePresentationSpecs[inlinePresentationSpecsCount - 1] } - inlinePresentation = createInlinePresentation(primaryEntry, pendingIntent, icon, - spec!!, duplicateDisplayNamesForPasskeys) + if (spec != null) { + inlinePresentation = createInlinePresentation(primaryEntry, pendingIntent, icon, + InlinePresentationsFactory.modifyInlinePresentationSpec + (this@CredentialAutofillService, spec), + duplicateDisplayNamesForPasskeys) + } } var dropdownPresentation: RemoteViews? = null if (i < lastDropdownDatasetIndex) { @@ -325,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 } @@ -365,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() @@ -380,7 +388,7 @@ class CredentialAutofillService : AutofillService() { Field.Builder().setPresentations( presentationBuilder.build()) .build()) - .setAuthentication(bottomSheetPendingIntent.intentSender) + .setAuthentication(pendingIntent.intentSender) .build() ) } @@ -396,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 * 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/common/ui/InlinePresentationFactory.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/InlinePresentationFactory.kt new file mode 100644 index 000000000000..3ebdd204b640 --- /dev/null +++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/InlinePresentationFactory.kt @@ -0,0 +1,84 @@ +/* +* 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.credentialmanager.common.ui + + +import android.content.Context +import android.util.Size +import android.widget.inline.InlinePresentationSpec +import androidx.autofill.inline.common.TextViewStyle +import androidx.autofill.inline.common.ViewStyle +import androidx.autofill.inline.UiVersions +import androidx.autofill.inline.UiVersions.Style +import androidx.autofill.inline.v1.InlineSuggestionUi +import androidx.core.content.ContextCompat +import android.util.TypedValue +import android.graphics.Typeface + + +class InlinePresentationsFactory { + companion object { + private const val googleSansMediumFontFamily = "google-sans-medium" + private const val googleSansTextFontFamily = "google-sans-text" + // There is no min width required for now but this is needed for the spec builder + private const val minInlineWidth = 5000 + + + fun modifyInlinePresentationSpec(context: Context, + originalSpec: InlinePresentationSpec): InlinePresentationSpec { + return InlinePresentationSpec.Builder(Size(originalSpec.minSize.width, originalSpec + .minSize.height), + Size(minInlineWidth, originalSpec + .maxSize.height)) + .setStyle(UiVersions.newStylesBuilder().addStyle(getStyle(context)).build()) + .build() + } + + + fun getStyle(context: Context): Style { + val textColorPrimary = ContextCompat.getColor(context, + com.android.credentialmanager.R.color.text_primary) + val textColorSecondary = ContextCompat.getColor(context, + com.android.credentialmanager.R.color.text_secondary) + val textColorBackground = ContextCompat.getColor(context, + com.android.credentialmanager.R.color.inline_background) + val chipHorizontalPadding = context.resources.getDimensionPixelSize(com.android + .credentialmanager.R.dimen.horizontal_chip_padding) + val chipVerticalPadding = context.resources.getDimensionPixelSize(com.android + .credentialmanager.R.dimen.vertical_chip_padding) + return InlineSuggestionUi.newStyleBuilder() + .setChipStyle( + ViewStyle.Builder().setPadding(chipHorizontalPadding, + chipVerticalPadding, + chipHorizontalPadding, chipVerticalPadding).build() + ) + .setTitleStyle( + TextViewStyle.Builder().setTextColor(textColorPrimary).setTextSize + (TypedValue.COMPLEX_UNIT_DIP, 14F) + .setTypeface(googleSansMediumFontFamily, + Typeface.NORMAL).setBackgroundColor(textColorBackground) + .build() + ) + .setSubtitleStyle(TextViewStyle.Builder().setTextColor(textColorSecondary) + .setTextSize(TypedValue.COMPLEX_UNIT_DIP, 12F).setTypeface + (googleSansTextFontFamily, Typeface.NORMAL).setBackgroundColor + (textColorBackground).build()) + .build() + } + } +}
\ No newline at end of file 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/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/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/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/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/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..f5c4843e1324 100644 --- a/packages/SystemUI/aconfig/systemui.aconfig +++ b/packages/SystemUI/aconfig/systemui.aconfig @@ -546,3 +546,13 @@ flag { 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 b8c4fae975af..ef15c8461b95 100644 --- a/packages/SystemUI/compose/core/src/com/android/compose/PlatformSlider.kt +++ b/packages/SystemUI/compose/core/src/com/android/compose/PlatformSlider.kt @@ -57,9 +57,6 @@ import androidx.compose.ui.unit.dp import com.android.compose.modifiers.padding import com.android.compose.theme.LocalAndroidColorScheme -/** Indicator corner radius used when the user drags the [PlatformSlider]. */ -private val DefaultPlatformSliderDraggingCornerRadius = 8.dp - /** * Platform slider implementation that displays a slider with an [icon] and a [label] at the start. * @@ -83,10 +80,8 @@ fun PlatformSlider( valueRange: ClosedFloatingPointRange<Float> = 0f..1f, enabled: Boolean = true, interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, - colors: PlatformSliderColors = - if (isSystemInDarkTheme()) darkThemePlatformSliderColors() - else lightThemePlatformSliderColors(), - draggingCornersRadius: Dp = DefaultPlatformSliderDraggingCornerRadius, + colors: PlatformSliderColors = PlatformSliderDefaults.defaultPlatformSliderColors(), + draggingCornersRadius: Dp = PlatformSliderDefaults.DefaultPlatformSliderDraggingCornerRadius, icon: (@Composable (isDragging: Boolean) -> Unit)? = null, label: (@Composable (isDragging: Boolean) -> Unit)? = null, ) { @@ -109,7 +104,7 @@ fun PlatformSlider( val paddingStart by animateDpAsState( targetValue = - if ((!isDragging && value == 0f) || icon == null) { + if ((!isDragging && value == valueRange.start) || icon == null) { 16.dp } else { 0.dp @@ -125,6 +120,7 @@ fun PlatformSlider( valueRange = valueRange, onValueChangeFinished = onValueChangeFinished, interactionSource = interactionSource, + enabled = enabled, track = { Track( sliderState = it, @@ -156,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) @@ -286,6 +285,17 @@ data class PlatformSliderColors( val disabledLabelColor: Color, ) +object PlatformSliderDefaults { + + /** Indicator corner radius used when the user drags the [PlatformSlider]. */ + val DefaultPlatformSliderDraggingCornerRadius = 8.dp + + @Composable + fun defaultPlatformSliderColors(): PlatformSliderColors = + if (isSystemInDarkTheme()) darkThemePlatformSliderColors() + else lightThemePlatformSliderColors() +} + /** [PlatformSliderColors] for the light theme */ @Composable private fun lightThemePlatformSliderColors() = diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/volume/VolumeSlidersModule.kt b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/volume/VolumeSlidersModule.kt new file mode 100644 index 000000000000..b4cb0983f213 --- /dev/null +++ b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/volume/VolumeSlidersModule.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.volume.panel.component.volume + +import dagger.Module + +@Module interface VolumeSlidersModule 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..609f314bb540 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 @@ -274,7 +274,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 +309,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, @@ -681,19 +681,20 @@ 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. view.setPadding(paddingInPx) - view }, // For reusing composition in lazy lists. onReset = {}, @@ -795,7 +796,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 @@ -858,12 +859,13 @@ data class ContentPaddingInPx(val start: Float, val top: Float) { } 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 diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenSceneBlueprintModule.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenSceneBlueprintModule.kt index 3677cab890f5..53f400fac7e5 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenSceneBlueprintModule.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenSceneBlueprintModule.kt @@ -20,6 +20,8 @@ import com.android.systemui.keyguard.ui.composable.blueprint.CommunalBlueprintMo import com.android.systemui.keyguard.ui.composable.blueprint.DefaultBlueprintModule import com.android.systemui.keyguard.ui.composable.blueprint.ShortcutsBesideUdfpsBlueprintModule import com.android.systemui.keyguard.ui.composable.blueprint.SplitShadeBlueprintModule +import com.android.systemui.keyguard.ui.composable.blueprint.SplitShadeWeatherClockBlueprintModule +import com.android.systemui.keyguard.ui.composable.blueprint.WeatherClockBlueprintModule import com.android.systemui.keyguard.ui.composable.section.OptionalSectionModule import dagger.Module @@ -31,6 +33,8 @@ import dagger.Module OptionalSectionModule::class, ShortcutsBesideUdfpsBlueprintModule::class, SplitShadeBlueprintModule::class, + SplitShadeWeatherClockBlueprintModule::class, + WeatherClockBlueprintModule::class, ], ) interface LockscreenSceneBlueprintModule diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt index a07ab4a11731..452dc03facfd 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt @@ -33,7 +33,7 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor import com.android.systemui.keyguard.ui.composable.LockscreenLongPress import com.android.systemui.keyguard.ui.composable.section.AmbientIndicationSection import com.android.systemui.keyguard.ui.composable.section.BottomAreaSection -import com.android.systemui.keyguard.ui.composable.section.ClockSection +import com.android.systemui.keyguard.ui.composable.section.DefaultClockSection import com.android.systemui.keyguard.ui.composable.section.LockSection import com.android.systemui.keyguard.ui.composable.section.NotificationSection import com.android.systemui.keyguard.ui.composable.section.SettingsMenuSection @@ -56,7 +56,7 @@ class DefaultBlueprint constructor( private val viewModel: LockscreenContentViewModel, private val statusBarSection: StatusBarSection, - private val clockSection: ClockSection, + private val clockSection: DefaultClockSection, private val smartSpaceSection: SmartSpaceSection, private val notificationSection: NotificationSection, private val lockSection: LockSection, diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt index b035e4220a5b..71c60c70a655 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt @@ -33,7 +33,7 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor import com.android.systemui.keyguard.ui.composable.LockscreenLongPress import com.android.systemui.keyguard.ui.composable.section.AmbientIndicationSection import com.android.systemui.keyguard.ui.composable.section.BottomAreaSection -import com.android.systemui.keyguard.ui.composable.section.ClockSection +import com.android.systemui.keyguard.ui.composable.section.DefaultClockSection import com.android.systemui.keyguard.ui.composable.section.LockSection import com.android.systemui.keyguard.ui.composable.section.NotificationSection import com.android.systemui.keyguard.ui.composable.section.SettingsMenuSection @@ -56,7 +56,7 @@ class ShortcutsBesideUdfpsBlueprint constructor( private val viewModel: LockscreenContentViewModel, private val statusBarSection: StatusBarSection, - private val clockSection: ClockSection, + private val clockSection: DefaultClockSection, private val smartSpaceSection: SmartSpaceSection, private val notificationSection: NotificationSection, private val lockSection: LockSection, diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/SplitShadeBlueprint.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/SplitShadeBlueprint.kt index 44fe8831729c..af836b68544c 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/SplitShadeBlueprint.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/SplitShadeBlueprint.kt @@ -39,7 +39,7 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor import com.android.systemui.keyguard.ui.composable.LockscreenLongPress import com.android.systemui.keyguard.ui.composable.section.AmbientIndicationSection import com.android.systemui.keyguard.ui.composable.section.BottomAreaSection -import com.android.systemui.keyguard.ui.composable.section.ClockSection +import com.android.systemui.keyguard.ui.composable.section.DefaultClockSection import com.android.systemui.keyguard.ui.composable.section.LockSection import com.android.systemui.keyguard.ui.composable.section.NotificationSection import com.android.systemui.keyguard.ui.composable.section.SettingsMenuSection @@ -63,7 +63,7 @@ class SplitShadeBlueprint constructor( private val viewModel: LockscreenContentViewModel, private val statusBarSection: StatusBarSection, - private val clockSection: ClockSection, + private val clockSection: DefaultClockSection, private val smartSpaceSection: SmartSpaceSection, private val notificationSection: NotificationSection, private val lockSection: LockSection, diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/WeatherClockBlueprint.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/WeatherClockBlueprint.kt new file mode 100644 index 000000000000..e2e7a950cdfd --- /dev/null +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/WeatherClockBlueprint.kt @@ -0,0 +1,409 @@ +/* + * 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.composable.blueprint + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.Layout +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.dimensionResource +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.IntRect +import androidx.compose.ui.unit.dp +import com.android.compose.animation.scene.SceneScope +import com.android.compose.modifiers.padding +import com.android.systemui.Flags +import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor.Companion.SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID +import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor.Companion.WEATHER_CLOCK_BLUEPRINT_ID +import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor +import com.android.systemui.keyguard.ui.composable.LockscreenLongPress +import com.android.systemui.keyguard.ui.composable.section.AmbientIndicationSection +import com.android.systemui.keyguard.ui.composable.section.BottomAreaSection +import com.android.systemui.keyguard.ui.composable.section.LockSection +import com.android.systemui.keyguard.ui.composable.section.NotificationSection +import com.android.systemui.keyguard.ui.composable.section.SettingsMenuSection +import com.android.systemui.keyguard.ui.composable.section.SmartSpaceSection +import com.android.systemui.keyguard.ui.composable.section.StatusBarSection +import com.android.systemui.keyguard.ui.composable.section.WeatherClockSection +import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel +import com.android.systemui.res.R +import com.android.systemui.shade.LargeScreenHeaderHelper +import dagger.Binds +import dagger.Module +import dagger.multibindings.IntoSet +import java.util.Optional +import javax.inject.Inject + +class WeatherClockBlueprint +@Inject +constructor( + private val viewModel: LockscreenContentViewModel, + private val statusBarSection: StatusBarSection, + private val weatherClockSection: WeatherClockSection, + private val smartSpaceSection: SmartSpaceSection, + private val notificationSection: NotificationSection, + private val lockSection: LockSection, + private val ambientIndicationSectionOptional: Optional<AmbientIndicationSection>, + private val bottomAreaSection: BottomAreaSection, + private val settingsMenuSection: SettingsMenuSection, + private val clockInteractor: KeyguardClockInteractor, +) : ComposableLockscreenSceneBlueprint { + + override val id: String = WEATHER_CLOCK_BLUEPRINT_ID + @Composable + override fun SceneScope.Content(modifier: Modifier) { + val isUdfpsVisible = viewModel.isUdfpsVisible + val burnIn = rememberBurnIn(clockInteractor) + val resources = LocalContext.current.resources + + LockscreenLongPress( + viewModel = viewModel.longPress, + modifier = modifier, + ) { onSettingsMenuPlaced -> + Layout( + content = { + // Constrained to above the lock icon. + Column( + modifier = Modifier.fillMaxWidth(), + ) { + with(statusBarSection) { StatusBar(modifier = Modifier.fillMaxWidth()) } + // TODO: Add weather clock for small and large clock + with(smartSpaceSection) { + SmartSpace( + burnInParams = burnIn.parameters, + onTopChanged = burnIn.onSmartspaceTopChanged, + modifier = + Modifier.fillMaxWidth() + .padding( + top = { viewModel.getSmartSpacePaddingTop(resources) }, + ) + .padding( + bottom = + dimensionResource( + R.dimen.keyguard_status_view_bottom_margin + ), + ), + ) + } + + if (viewModel.areNotificationsVisible) { + with(notificationSection) { + Notifications( + modifier = Modifier.fillMaxWidth().weight(weight = 1f) + ) + } + } + + if (!isUdfpsVisible && ambientIndicationSectionOptional.isPresent) { + with(ambientIndicationSectionOptional.get()) { + AmbientIndication(modifier = Modifier.fillMaxWidth()) + } + } + } + + with(lockSection) { LockIcon() } + + // Aligned to bottom and constrained to below the lock icon. + Column(modifier = Modifier.fillMaxWidth()) { + if (isUdfpsVisible && ambientIndicationSectionOptional.isPresent) { + with(ambientIndicationSectionOptional.get()) { + AmbientIndication(modifier = Modifier.fillMaxWidth()) + } + } + + with(bottomAreaSection) { + IndicationArea(modifier = Modifier.fillMaxWidth()) + } + } + + // Aligned to bottom and NOT constrained by the lock icon. + with(bottomAreaSection) { + Shortcut(isStart = true, applyPadding = true) + Shortcut(isStart = false, applyPadding = true) + } + with(settingsMenuSection) { SettingsMenu(onSettingsMenuPlaced) } + }, + modifier = Modifier.fillMaxSize(), + ) { measurables, constraints -> + check(measurables.size == 6) + val aboveLockIconMeasurable = measurables[0] + val lockIconMeasurable = measurables[1] + val belowLockIconMeasurable = measurables[2] + val startShortcutMeasurable = measurables[3] + val endShortcutMeasurable = measurables[4] + val settingsMenuMeasurable = measurables[5] + + val noMinConstraints = + constraints.copy( + minWidth = 0, + minHeight = 0, + ) + val lockIconPlaceable = lockIconMeasurable.measure(noMinConstraints) + val lockIconBounds = + IntRect( + left = lockIconPlaceable[BlueprintAlignmentLines.LockIcon.Left], + top = lockIconPlaceable[BlueprintAlignmentLines.LockIcon.Top], + right = lockIconPlaceable[BlueprintAlignmentLines.LockIcon.Right], + bottom = lockIconPlaceable[BlueprintAlignmentLines.LockIcon.Bottom], + ) + + val aboveLockIconPlaceable = + aboveLockIconMeasurable.measure( + noMinConstraints.copy(maxHeight = lockIconBounds.top) + ) + val belowLockIconPlaceable = + belowLockIconMeasurable.measure( + noMinConstraints.copy( + maxHeight = + (constraints.maxHeight - lockIconBounds.bottom).coerceAtLeast(0) + ) + ) + val startShortcutPleaceable = startShortcutMeasurable.measure(noMinConstraints) + val endShortcutPleaceable = endShortcutMeasurable.measure(noMinConstraints) + val settingsMenuPlaceable = settingsMenuMeasurable.measure(noMinConstraints) + + layout(constraints.maxWidth, constraints.maxHeight) { + aboveLockIconPlaceable.place( + x = 0, + y = 0, + ) + lockIconPlaceable.place( + x = lockIconBounds.left, + y = lockIconBounds.top, + ) + belowLockIconPlaceable.place( + x = 0, + y = constraints.maxHeight - belowLockIconPlaceable.height, + ) + startShortcutPleaceable.place( + x = 0, + y = constraints.maxHeight - startShortcutPleaceable.height, + ) + endShortcutPleaceable.place( + x = constraints.maxWidth - endShortcutPleaceable.width, + y = constraints.maxHeight - endShortcutPleaceable.height, + ) + settingsMenuPlaceable.place( + x = (constraints.maxWidth - settingsMenuPlaceable.width) / 2, + y = constraints.maxHeight - settingsMenuPlaceable.height, + ) + } + } + } + } +} + +class SplitShadeWeatherClockBlueprint +@Inject +constructor( + private val viewModel: LockscreenContentViewModel, + private val statusBarSection: StatusBarSection, + private val smartSpaceSection: SmartSpaceSection, + private val notificationSection: NotificationSection, + private val lockSection: LockSection, + private val ambientIndicationSectionOptional: Optional<AmbientIndicationSection>, + private val bottomAreaSection: BottomAreaSection, + private val settingsMenuSection: SettingsMenuSection, + private val clockInteractor: KeyguardClockInteractor, + private val largeScreenHeaderHelper: LargeScreenHeaderHelper, + private val weatherClockSection: WeatherClockSection, +) : ComposableLockscreenSceneBlueprint { + override val id: String = SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID + + @Composable + override fun SceneScope.Content(modifier: Modifier) { + val isUdfpsVisible = viewModel.isUdfpsVisible + val burnIn = rememberBurnIn(clockInteractor) + val resources = LocalContext.current.resources + + LockscreenLongPress( + viewModel = viewModel.longPress, + modifier = modifier, + ) { onSettingsMenuPlaced -> + Layout( + content = { + // Constrained to above the lock icon. + Column( + modifier = Modifier.fillMaxSize(), + ) { + with(statusBarSection) { StatusBar(modifier = Modifier.fillMaxWidth()) } + Row( + modifier = Modifier.fillMaxSize(), + ) { + // TODO: Add weather clock for small and large clock + Column( + modifier = Modifier.fillMaxHeight().weight(weight = 1f), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + with(smartSpaceSection) { + SmartSpace( + burnInParams = burnIn.parameters, + onTopChanged = burnIn.onSmartspaceTopChanged, + modifier = + Modifier.fillMaxWidth() + .padding( + top = { + viewModel.getSmartSpacePaddingTop(resources) + }, + ) + .padding( + bottom = + dimensionResource( + R.dimen + .keyguard_status_view_bottom_margin + ) + ), + ) + } + } + with(notificationSection) { + val splitShadeTopMargin: Dp = + if (Flags.centralizedStatusBarHeightFix()) { + largeScreenHeaderHelper.getLargeScreenHeaderHeight().dp + } else { + dimensionResource( + id = R.dimen.large_screen_shade_header_height + ) + } + Notifications( + modifier = + Modifier.fillMaxHeight() + .weight(weight = 1f) + .padding(top = splitShadeTopMargin) + ) + } + } + + if (!isUdfpsVisible && ambientIndicationSectionOptional.isPresent) { + with(ambientIndicationSectionOptional.get()) { + AmbientIndication(modifier = Modifier.fillMaxWidth()) + } + } + } + + with(lockSection) { LockIcon() } + + // Aligned to bottom and constrained to below the lock icon. + Column(modifier = Modifier.fillMaxWidth()) { + if (isUdfpsVisible && ambientIndicationSectionOptional.isPresent) { + with(ambientIndicationSectionOptional.get()) { + AmbientIndication(modifier = Modifier.fillMaxWidth()) + } + } + + with(bottomAreaSection) { + IndicationArea(modifier = Modifier.fillMaxWidth()) + } + } + + // Aligned to bottom and NOT constrained by the lock icon. + with(bottomAreaSection) { + Shortcut(isStart = true, applyPadding = true) + Shortcut(isStart = false, applyPadding = true) + } + with(settingsMenuSection) { SettingsMenu(onSettingsMenuPlaced) } + }, + modifier = Modifier.fillMaxSize(), + ) { measurables, constraints -> + check(measurables.size == 6) + val aboveLockIconMeasurable = measurables[0] + val lockIconMeasurable = measurables[1] + val belowLockIconMeasurable = measurables[2] + val startShortcutMeasurable = measurables[3] + val endShortcutMeasurable = measurables[4] + val settingsMenuMeasurable = measurables[5] + + val noMinConstraints = + constraints.copy( + minWidth = 0, + minHeight = 0, + ) + val lockIconPlaceable = lockIconMeasurable.measure(noMinConstraints) + val lockIconBounds = + IntRect( + left = lockIconPlaceable[BlueprintAlignmentLines.LockIcon.Left], + top = lockIconPlaceable[BlueprintAlignmentLines.LockIcon.Top], + right = lockIconPlaceable[BlueprintAlignmentLines.LockIcon.Right], + bottom = lockIconPlaceable[BlueprintAlignmentLines.LockIcon.Bottom], + ) + + val aboveLockIconPlaceable = + aboveLockIconMeasurable.measure( + noMinConstraints.copy(maxHeight = lockIconBounds.top) + ) + val belowLockIconPlaceable = + belowLockIconMeasurable.measure( + noMinConstraints.copy( + maxHeight = + (constraints.maxHeight - lockIconBounds.bottom).coerceAtLeast(0) + ) + ) + val startShortcutPleaceable = startShortcutMeasurable.measure(noMinConstraints) + val endShortcutPleaceable = endShortcutMeasurable.measure(noMinConstraints) + val settingsMenuPlaceable = settingsMenuMeasurable.measure(noMinConstraints) + + layout(constraints.maxWidth, constraints.maxHeight) { + aboveLockIconPlaceable.place( + x = 0, + y = 0, + ) + lockIconPlaceable.place( + x = lockIconBounds.left, + y = lockIconBounds.top, + ) + belowLockIconPlaceable.place( + x = 0, + y = constraints.maxHeight - belowLockIconPlaceable.height, + ) + startShortcutPleaceable.place( + x = 0, + y = constraints.maxHeight - startShortcutPleaceable.height, + ) + endShortcutPleaceable.place( + x = constraints.maxWidth - endShortcutPleaceable.width, + y = constraints.maxHeight - endShortcutPleaceable.height, + ) + settingsMenuPlaceable.place( + x = (constraints.maxWidth - settingsMenuPlaceable.width) / 2, + y = constraints.maxHeight - settingsMenuPlaceable.height, + ) + } + } + } + } +} + +@Module +interface WeatherClockBlueprintModule { + @Binds + @IntoSet + fun blueprint(blueprint: WeatherClockBlueprint): ComposableLockscreenSceneBlueprint +} + +@Module +interface SplitShadeWeatherClockBlueprintModule { + @Binds + @IntoSet + fun blueprint(blueprint: SplitShadeWeatherClockBlueprint): ComposableLockscreenSceneBlueprint +} diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/ClockSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt index fa07bafda82c..335c915411ee 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/ClockSection.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt @@ -18,6 +18,7 @@ package com.android.systemui.keyguard.ui.composable.section import android.view.ViewGroup import android.widget.FrameLayout +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect @@ -38,14 +39,17 @@ import com.android.systemui.keyguard.ui.composable.modifier.onTopPlacementChange import com.android.systemui.keyguard.ui.viewmodel.AodBurnInViewModel import com.android.systemui.keyguard.ui.viewmodel.BurnInParameters import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel +import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController import javax.inject.Inject -class ClockSection +/** Provides small clock and large clock composables for the default clock face. */ +class DefaultClockSection @Inject constructor( private val viewModel: KeyguardClockViewModel, private val clockInteractor: KeyguardClockInteractor, private val aodBurnInViewModel: AodBurnInViewModel, + private val lockscreenSmartspaceController: LockscreenSmartspaceController, ) { @Composable @@ -151,6 +155,7 @@ constructor( (newClockView.parent as? ViewGroup)?.removeView(newClockView) it.addView(newClockView) }, + modifier = Modifier.fillMaxSize() ) } } 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/keyguard/ui/composable/section/WeatherClockSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/WeatherClockSection.kt new file mode 100644 index 000000000000..2e7bc2a28c65 --- /dev/null +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/WeatherClockSection.kt @@ -0,0 +1,60 @@ +/* + * 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.composable.section + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import com.android.compose.animation.scene.SceneScope +import javax.inject.Inject + +/** Provides small clock and large clock composables for the weather clock layout. */ +class WeatherClockSection @Inject constructor() { + @Composable + fun SceneScope.Time( + modifier: Modifier = Modifier, + ) { + // TODO: compose view + } + + @Composable + fun SceneScope.Date( + modifier: Modifier = Modifier, + ) { + // TODO: compose view + } + + @Composable + fun SceneScope.Weather( + modifier: Modifier = Modifier, + ) { + // TODO: compose view + } + + @Composable + fun SceneScope.DndAlarmStatus( + modifier: Modifier = Modifier, + ) { + // TODO: compose view + } + + @Composable + fun SceneScope.Temperature( + modifier: Modifier = Modifier, + ) { + // TODO: compose view + } +} 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/VolumeSlidersModule.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/VolumeSlidersModule.kt new file mode 100644 index 000000000000..453ff026a8a0 --- /dev/null +++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/VolumeSlidersModule.kt @@ -0,0 +1,43 @@ +/* + * 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.volume + +import com.android.systemui.volume.panel.component.shared.model.VolumePanelComponents +import com.android.systemui.volume.panel.component.volume.ui.composable.VolumeSlidersComponent +import com.android.systemui.volume.panel.domain.AlwaysAvailableCriteria +import com.android.systemui.volume.panel.domain.ComponentAvailabilityCriteria +import com.android.systemui.volume.panel.shared.model.VolumePanelUiComponent +import dagger.Binds +import dagger.Module +import dagger.multibindings.IntoMap +import dagger.multibindings.StringKey + +@Module +interface VolumeSlidersModule { + + @Binds + @IntoMap + @StringKey(VolumePanelComponents.VOLUME_SLIDERS) + fun bindVolumePanelUiComponent(component: VolumeSlidersComponent): VolumePanelUiComponent + + @Binds + @IntoMap + @StringKey(VolumePanelComponents.VOLUME_SLIDERS) + fun bindComponentAvailabilityCriteria( + criteria: AlwaysAvailableCriteria + ): ComponentAvailabilityCriteria +} 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 new file mode 100644 index 000000000000..4d810dfce89d --- /dev/null +++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/ColumnVolumeSliders.kt @@ -0,0 +1,200 @@ +/* + * 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.volume.ui.composable + +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.EnterTransition +import androidx.compose.animation.ExitTransition +import androidx.compose.animation.ExperimentalAnimationApi +import androidx.compose.animation.core.tween +import androidx.compose.animation.core.updateTransition +import androidx.compose.animation.expandVertically +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.scaleIn +import androidx.compose.animation.scaleOut +import androidx.compose.animation.shrinkVertically +import androidx.compose.animation.slideInVertically +import androidx.compose.animation.slideOutVertically +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.padding +import androidx.compose.foundation.layout.size +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.IconButtonDefaults +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.unit.dp +import com.android.compose.PlatformSliderColors +import com.android.systemui.res.R +import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.SliderViewModel + +private const val EXPAND_DURATION_MILLIS = 500 +private const val COLLAPSE_DURATION_MILLIS = 300 + +/** Volume sliders laid out in a collapsable column */ +@OptIn(ExperimentalAnimationApi::class) +@Composable +fun ColumnVolumeSliders( + viewModels: List<SliderViewModel>, + sliderColors: PlatformSliderColors, + isExpandable: Boolean, + modifier: Modifier = Modifier, +) { + require(viewModels.isNotEmpty()) + var isExpanded: Boolean by remember(isExpandable) { mutableStateOf(!isExpandable) } + val transition = updateTransition(isExpanded, label = "CollapsableSliders") + Column(modifier = modifier) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(8.dp), + ) { + val sliderViewModel: SliderViewModel = viewModels.first() + val sliderState by viewModels.first().slider.collectAsState() + VolumeSlider( + modifier = Modifier.weight(1f), + state = sliderState, + onValueChangeFinished = { sliderViewModel.onValueChangeFinished(sliderState, it) }, + sliderColors = sliderColors, + ) + + if (isExpandable) { + ExpandButton( + isExpanded = isExpanded, + onExpandedChanged = { isExpanded = it }, + sliderColors, + Modifier, + ) + } + } + transition.AnimatedVisibility( + visible = { it }, + enter = + expandVertically( + animationSpec = tween(durationMillis = EXPAND_DURATION_MILLIS), + expandFrom = Alignment.CenterVertically, + ), + exit = + shrinkVertically( + animationSpec = tween(durationMillis = COLLAPSE_DURATION_MILLIS), + shrinkTowards = Alignment.CenterVertically, + ), + ) { + Column(modifier = Modifier.fillMaxWidth()) { + for (index in 1..viewModels.lastIndex) { + val sliderViewModel: SliderViewModel = viewModels[index] + val sliderState by sliderViewModel.slider.collectAsState() + transition.AnimatedVisibility( + visible = { it }, + enter = enterTransition(index = index, totalCount = viewModels.size), + exit = exitTransition(index = index, totalCount = viewModels.size) + ) { + VolumeSlider( + modifier = Modifier.fillMaxWidth().padding(top = 16.dp), + state = sliderState, + onValueChangeFinished = { + sliderViewModel.onValueChangeFinished(sliderState, it) + }, + sliderColors = sliderColors, + ) + } + } + } + } + } +} + +@Composable +private fun ExpandButton( + isExpanded: Boolean, + onExpandedChanged: (Boolean) -> Unit, + sliderColors: PlatformSliderColors, + modifier: Modifier = Modifier, +) { + IconButton( + modifier = modifier.size(64.dp), + onClick = { onExpandedChanged(!isExpanded) }, + colors = + IconButtonDefaults.filledIconButtonColors( + containerColor = sliderColors.indicatorColor, + contentColor = sliderColors.iconColor + ), + ) { + Icon( + painter = + painterResource( + if (isExpanded) { + R.drawable.ic_filled_arrow_down + } else { + R.drawable.ic_filled_arrow_up + } + ), + contentDescription = null, + ) + } +} + +private fun enterTransition(index: Int, totalCount: Int): EnterTransition { + val enterDelay = ((totalCount - index + 1) * 10).coerceAtLeast(0) + val enterDuration = (EXPAND_DURATION_MILLIS - enterDelay).coerceAtLeast(100) + return slideInVertically( + initialOffsetY = { (it * 0.25).toInt() }, + animationSpec = tween(durationMillis = enterDuration, delayMillis = enterDelay), + ) + + scaleIn( + initialScale = 0.9f, + animationSpec = tween(durationMillis = enterDuration, delayMillis = enterDelay), + ) + + expandVertically( + initialHeight = { (it * 0.65).toInt() }, + animationSpec = tween(durationMillis = enterDuration, delayMillis = enterDelay), + clip = false, + expandFrom = Alignment.CenterVertically, + ) + + fadeIn( + animationSpec = tween(durationMillis = enterDuration, delayMillis = enterDelay), + ) +} + +private fun exitTransition(index: Int, totalCount: Int): ExitTransition { + val exitDuration = (COLLAPSE_DURATION_MILLIS - (totalCount - index + 1) * 10).coerceAtLeast(100) + return slideOutVertically( + targetOffsetY = { (it * 0.25).toInt() }, + animationSpec = tween(durationMillis = exitDuration), + ) + + scaleOut( + targetScale = 0.9f, + animationSpec = tween(durationMillis = exitDuration), + ) + + shrinkVertically( + targetHeight = { (it * 0.65).toInt() }, + animationSpec = tween(durationMillis = exitDuration), + clip = false, + shrinkTowards = Alignment.CenterVertically, + ) + + fadeOut(animationSpec = tween(durationMillis = exitDuration)) +} diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/GridVolumeSliders.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/GridVolumeSliders.kt new file mode 100644 index 000000000000..910ee7285bdb --- /dev/null +++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/GridVolumeSliders.kt @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.volume.panel.component.volume.ui.composable + +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import com.android.compose.PlatformSliderColors +import com.android.compose.grid.VerticalGrid +import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.SliderViewModel + +@Composable +fun GridVolumeSliders( + viewModels: List<SliderViewModel>, + sliderColors: PlatformSliderColors, + modifier: Modifier = Modifier, +) { + require(viewModels.isNotEmpty()) + VerticalGrid( + modifier = modifier, + columns = 2, + verticalSpacing = 16.dp, + horizontalSpacing = 24.dp, + ) { + for (sliderViewModel in viewModels) { + val sliderState = sliderViewModel.slider.collectAsState().value + VolumeSlider( + modifier = Modifier.fillMaxWidth(), + state = sliderState, + onValueChangeFinished = { sliderViewModel.onValueChangeFinished(sliderState, it) }, + sliderColors = sliderColors, + ) + } + } +} 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 new file mode 100644 index 000000000000..18a62dca3769 --- /dev/null +++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlider.kt @@ -0,0 +1,87 @@ +/* + * 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.volume.ui.composable + +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 +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableFloatStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import com.android.compose.PlatformSlider +import com.android.compose.PlatformSliderColors +import com.android.systemui.common.ui.compose.Icon +import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.SliderState + +@Composable +fun VolumeSlider( + state: SliderState, + onValueChangeFinished: (Float) -> Unit, + modifier: Modifier = Modifier, + sliderColors: PlatformSliderColors, +) { + var value by remember(state.value) { mutableFloatStateOf(state.value) } + PlatformSlider( + modifier = modifier, + value = value, + valueRange = state.valueRange, + onValueChange = { value = it }, + onValueChangeFinished = { onValueChangeFinished(value) }, + enabled = state.isEnabled, + icon = { isDragging -> + if (isDragging) { + Text(text = value.toInt().toString()) + } else { + state.icon?.let { Icon(icon = it) } + } + }, + colors = sliderColors, + label = { + Column(modifier = Modifier.animateContentSize()) { + Text( + modifier = Modifier.basicMarquee(), + text = state.label, + style = MaterialTheme.typography.titleMedium, + maxLines = 1, + ) + + state.disabledMessage?.let { message -> + AnimatedVisibility( + !state.isEnabled, + enter = expandVertically { it }, + exit = shrinkVertically { it }, + ) { + 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 new file mode 100644 index 000000000000..1ca18deeaac2 --- /dev/null +++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlidersComponent.kt @@ -0,0 +1,59 @@ +/* + * 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.volume.ui.composable + +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.ui.Modifier +import com.android.compose.PlatformSliderDefaults +import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.SliderViewModel +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 +@Inject +constructor( + private val viewModel: AudioVolumeComponentViewModel, +) : ComposeVolumePanelUiComponent { + + @Composable + override fun VolumePanelComposeScope.Content(modifier: Modifier) { + val sliderViewModels: List<SliderViewModel> by viewModel.sliderViewModels.collectAsState() + if (sliderViewModels.isEmpty()) { + return + } + if (isLargeScreen) { + GridVolumeSliders( + viewModels = sliderViewModels, + sliderColors = PlatformSliderDefaults.defaultPlatformSliderColors(), + modifier = modifier.fillMaxWidth(), + ) + } else { + ColumnVolumeSliders( + viewModels = sliderViewModels, + sliderColors = PlatformSliderDefaults.defaultPlatformSliderColors(), + 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 400072ebb896..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 @@ -17,12 +17,13 @@ package com.android.systemui.volume.panel.ui.composable import androidx.compose.animation.AnimatedVisibility -import androidx.compose.animation.animateContentSize 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.Modifier import androidx.compose.ui.unit.dp @@ -34,7 +35,7 @@ fun VolumePanelComposeScope.VerticalVolumePanelContent( modifier: Modifier = Modifier, ) { Column( - modifier = modifier.animateContentSize(), + 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 259f3498d4c3..503463171ae7 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt @@ -44,12 +44,18 @@ import com.android.systemui.biometrics.ui.viewmodel.DefaultUdfpsTouchOverlayView import com.android.systemui.biometrics.ui.viewmodel.DeviceEntryUdfpsTouchOverlayViewModel 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.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.plugins.statusbar.StatusBarStateController +import com.android.systemui.power.data.repository.FakePowerRepository +import com.android.systemui.power.domain.interactor.PowerInteractor +import com.android.systemui.power.shared.model.WakeSleepReason +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 +import com.android.systemui.statusbar.phone.ScreenOffAnimationController import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager import com.android.systemui.statusbar.phone.SystemUIDialogManager import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController @@ -58,6 +64,10 @@ import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.user.domain.interactor.SelectedUserInteractor import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Rule import org.junit.Test @@ -68,6 +78,7 @@ import org.mockito.ArgumentMatchers.eq import org.mockito.Captor import org.mockito.Mock import org.mockito.Mockito.mock +import org.mockito.Mockito.never import org.mockito.Mockito.verify import org.mockito.Mockito.`when` as whenever import org.mockito.junit.MockitoJUnit @@ -120,6 +131,9 @@ class UdfpsControllerOverlayTest : SysuiTestCase() { @Mock private lateinit var shadeInteractor: ShadeInteractor @Captor private lateinit var layoutParamsCaptor: ArgumentCaptor<WindowManager.LayoutParams> @Mock private lateinit var udfpsOverlayInteractor: UdfpsOverlayInteractor + private lateinit var powerRepository: FakePowerRepository + private lateinit var powerInteractor: PowerInteractor + private lateinit var testScope: TestScope private val onTouch = { _: View, _: MotionEvent, _: Boolean -> true } private var overlayParams: UdfpsOverlayParams = UdfpsOverlayParams() @@ -127,6 +141,15 @@ class UdfpsControllerOverlayTest : SysuiTestCase() { @Before fun setup() { + testScope = TestScope(StandardTestDispatcher()) + powerRepository = FakePowerRepository() + powerInteractor = + PowerInteractor( + powerRepository, + mock(FalsingCollector::class.java), + mock(ScreenOffAnimationController::class.java), + statusBarStateController, + ) 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)) @@ -178,6 +201,8 @@ class UdfpsControllerOverlayTest : SysuiTestCase() { { defaultUdfpsTouchOverlayViewModel }, shadeInteractor, udfpsOverlayInteractor, + powerInteractor, + testScope, ) block() } @@ -277,6 +302,66 @@ class UdfpsControllerOverlayTest : SysuiTestCase() { } } + @Test + fun showUdfpsOverlay_awake() = + testScope.runTest { + withReason(REASON_AUTH_KEYGUARD) { + mSetFlagsRule.enableFlags(Flags.FLAG_UDFPS_VIEW_PERFORMANCE) + powerRepository.updateWakefulness( + rawState = WakefulnessState.AWAKE, + lastWakeReason = WakeSleepReason.POWER_BUTTON, + lastSleepReason = WakeSleepReason.OTHER, + ) + controllerOverlay.show(udfpsController, overlayParams) + runCurrent() + verify(windowManager).addView(any(), any()) + } + } + + @Test + fun showUdfpsOverlay_whileGoingToSleep() = + testScope.runTest { + withReason(REASON_AUTH_KEYGUARD) { + mSetFlagsRule.enableFlags(Flags.FLAG_UDFPS_VIEW_PERFORMANCE) + powerRepository.updateWakefulness( + rawState = WakefulnessState.STARTING_TO_SLEEP, + lastWakeReason = WakeSleepReason.POWER_BUTTON, + lastSleepReason = WakeSleepReason.OTHER, + ) + controllerOverlay.show(udfpsController, overlayParams) + runCurrent() + verify(windowManager, never()).addView(any(), any()) + + // we hide to end the job that listens for the finishedGoingToSleep signal + controllerOverlay.hide() + } + } + + @Test + fun showUdfpsOverlay_afterFinishedGoingToSleep() = + testScope.runTest { + withReason(REASON_AUTH_KEYGUARD) { + mSetFlagsRule.enableFlags(Flags.FLAG_UDFPS_VIEW_PERFORMANCE) + powerRepository.updateWakefulness( + rawState = WakefulnessState.STARTING_TO_SLEEP, + lastWakeReason = WakeSleepReason.POWER_BUTTON, + lastSleepReason = WakeSleepReason.OTHER, + ) + controllerOverlay.show(udfpsController, overlayParams) + runCurrent() + verify(windowManager, never()).addView(any(), any()) + + powerRepository.updateWakefulness( + rawState = WakefulnessState.ASLEEP, + lastWakeReason = WakeSleepReason.POWER_BUTTON, + lastSleepReason = WakeSleepReason.OTHER, + ) + runCurrent() + verify(windowManager) + .addView(eq(controllerOverlay.getTouchOverlay()), layoutParamsCaptor.capture()) + } + } + private fun showUdfpsOverlay() { val didShow = controllerOverlay.show(udfpsController, overlayParams) 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 529403a710b5..561cdbbf66ce 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java @@ -86,6 +86,7 @@ import com.android.systemui.biometrics.ui.viewmodel.DefaultUdfpsTouchOverlayView import com.android.systemui.biometrics.ui.viewmodel.DeviceEntryUdfpsTouchOverlayViewModel; 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.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor; import com.android.systemui.dump.DumpManager; import com.android.systemui.flags.FeatureFlags; @@ -94,10 +95,15 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInterac import com.android.systemui.log.SessionTracker; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.power.data.repository.FakePowerRepository; +import com.android.systemui.power.domain.interactor.PowerInteractor; +import com.android.systemui.power.shared.model.WakeSleepReason; +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; import com.android.systemui.statusbar.VibratorHelper; +import com.android.systemui.statusbar.phone.ScreenOffAnimationController; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.systemui.statusbar.phone.SystemUIDialogManager; import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController; @@ -125,6 +131,8 @@ import org.mockito.junit.MockitoRule; import java.util.ArrayList; import java.util.List; +import kotlinx.coroutines.CoroutineScope; + @SmallTest @RunWith(AndroidJUnit4.class) @RunWithLooper(setAsMainLooper = true) @@ -238,6 +246,8 @@ public class UdfpsControllerTest extends SysuiTestCase { private ScreenLifecycle.Observer mScreenObserver; private FingerprintSensorPropertiesInternal mOpticalProps; private FingerprintSensorPropertiesInternal mUltrasonicProps; + private PowerInteractor mPowerInteractor; + private FakePowerRepository mPowerRepository; @Mock private InputManager mInputManager; @Mock @@ -253,6 +263,19 @@ public class UdfpsControllerTest extends SysuiTestCase { @Before public void setUp() { + mPowerRepository = new FakePowerRepository(); + mPowerInteractor = new PowerInteractor( + mPowerRepository, + mock(FalsingCollector.class), + mock(ScreenOffAnimationController.class), + mStatusBarStateController + ); + mPowerRepository.updateWakefulness( + WakefulnessState.AWAKE, + WakeSleepReason.POWER_BUTTON, + WakeSleepReason.OTHER, + /* powerButtonLaunchGestureTriggered */ false + ); mContext.getOrCreateTestableResources() .addOverride(com.android.internal.R.bool.config_ignoreUdfpsVote, false); @@ -346,7 +369,9 @@ public class UdfpsControllerTest extends SysuiTestCase { mKeyguardTransitionInteractor, mDeviceEntryUdfpsTouchOverlayViewModel, mDefaultUdfpsTouchOverlayViewModel, - mUdfpsOverlayInteractor + mUdfpsOverlayInteractor, + mPowerInteractor, + mock(CoroutineScope.class) ); verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture()); mOverlayController = mOverlayCaptor.getValue(); 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 a8fe16b12e1b..92396e0bcdef 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt @@ -20,6 +20,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.communal.domain.interactor.communalInteractor +import com.android.systemui.communal.domain.interactor.setCommunalAvailable import com.android.systemui.communal.shared.model.CommunalSceneKey import com.android.systemui.coroutines.collectLastValue import com.android.systemui.dock.DockManager @@ -33,6 +34,7 @@ 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.launch import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.advanceTimeBy import kotlinx.coroutines.test.runCurrent @@ -50,7 +52,7 @@ class CommunalSceneStartableTest : SysuiTestCase() { private lateinit var underTest: CommunalSceneStartable @Before - fun setUp() = + fun setUp() { with(kosmos) { underTest = CommunalSceneStartable( @@ -61,7 +63,15 @@ class CommunalSceneStartableTest : SysuiTestCase() { bgScope = applicationCoroutineScope, ) .apply { start() } + + // Make communal available so that communalInteractor.desiredScene accurately reflects + // scene changes instead of just returning Blank. + with(kosmos.testScope) { + launch { setCommunalAvailable(true) } + testScheduler.runCurrent() + } } + } @Test fun keyguardGoesAway_forceBlankScene() = @@ -83,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 { @@ -115,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) } } @@ -249,4 +233,10 @@ class CommunalSceneStartableTest : SysuiTestCase() { fakeDockManager.setDockEvent(DockManager.STATE_DOCKED) runCurrent() } + + private suspend fun TestScope.enableCommunal() = + with(kosmos) { + setCommunalAvailable(true) + runCurrent() + } } 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 ce96d75da666..cd296524c17c 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 @@ -455,6 +455,9 @@ class CommunalInteractorTest : SysuiTestCase() { @Test fun listensToSceneChange() = testScope.runTest { + kosmos.setCommunalAvailable(true) + runCurrent() + var desiredScene = collectLastValue(underTest.desiredScene) runCurrent() assertThat(desiredScene()).isEqualTo(CommunalSceneKey.Blank) @@ -479,6 +482,30 @@ class CommunalInteractorTest : SysuiTestCase() { } @Test + fun desiredScene_communalNotAvailable_returnsBlank() = + testScope.runTest { + kosmos.setCommunalAvailable(true) + runCurrent() + + val desiredScene by collectLastValue(underTest.desiredScene) + + underTest.onSceneChanged(CommunalSceneKey.Communal) + assertThat(desiredScene).isEqualTo(CommunalSceneKey.Communal) + + kosmos.setCommunalAvailable(false) + runCurrent() + + // Scene returns blank when communal is not available. + assertThat(desiredScene).isEqualTo(CommunalSceneKey.Blank) + + kosmos.setCommunalAvailable(true) + runCurrent() + + // After re-enabling, scene goes back to Communal. + assertThat(desiredScene).isEqualTo(CommunalSceneKey.Communal) + } + + @Test fun transitionProgress_onTargetScene_fullProgress() = testScope.runTest { val targetScene = CommunalSceneKey.Blank @@ -604,8 +631,28 @@ class CommunalInteractorTest : SysuiTestCase() { } @Test + fun isCommunalShowing() = + testScope.runTest { + kosmos.setCommunalAvailable(true) + runCurrent() + + var isCommunalShowing = collectLastValue(underTest.isCommunalShowing) + runCurrent() + assertThat(isCommunalShowing()).isEqualTo(false) + + underTest.onSceneChanged(CommunalSceneKey.Communal) + + isCommunalShowing = collectLastValue(underTest.isCommunalShowing) + runCurrent() + assertThat(isCommunalShowing()).isEqualTo(true) + } + + @Test fun isCommunalShowing_whenSceneContainerDisabled() = testScope.runTest { + kosmos.setCommunalAvailable(true) + runCurrent() + // Verify default is false val isCommunalShowing by collectLastValue(underTest.isCommunalShowing) runCurrent() diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalTutorialInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalTutorialInteractorTest.kt index 5211c55ac911..8b785927ba5e 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalTutorialInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalTutorialInteractorTest.kt @@ -16,7 +16,6 @@ package com.android.systemui.communal.domain.interactor -import android.content.pm.UserInfo import android.provider.Settings.Secure.HUB_MODE_TUTORIAL_COMPLETED import android.provider.Settings.Secure.HUB_MODE_TUTORIAL_NOT_STARTED import android.provider.Settings.Secure.HUB_MODE_TUTORIAL_STARTED @@ -61,7 +60,6 @@ class CommunalTutorialInteractorTest : SysuiTestCase() { communalInteractor = kosmos.communalInteractor userRepository = kosmos.fakeUserRepository - userRepository.setUserInfos(listOf(MAIN_USER_INFO)) kosmos.fakeFeatureFlagsClassic.set(Flags.COMMUNAL_SERVICE_ENABLED, true) mSetFlagsRule.enableFlags(FLAG_COMMUNAL_HUB) @@ -72,7 +70,7 @@ class CommunalTutorialInteractorTest : SysuiTestCase() { fun tutorialUnavailable_whenKeyguardNotVisible() = testScope.runTest { val isTutorialAvailable by collectLastValue(underTest.isTutorialAvailable) - setCommunalAvailable(true) + kosmos.setCommunalAvailable(true) communalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_NOT_STARTED) keyguardRepository.setKeyguardShowing(false) assertThat(isTutorialAvailable).isFalse() @@ -82,10 +80,7 @@ class CommunalTutorialInteractorTest : SysuiTestCase() { fun tutorialUnavailable_whenTutorialIsCompleted() = testScope.runTest { val isTutorialAvailable by collectLastValue(underTest.isTutorialAvailable) - setCommunalAvailable(true) - keyguardRepository.setKeyguardShowing(true) - keyguardRepository.setKeyguardOccluded(false) - communalInteractor.onSceneChanged(CommunalSceneKey.Communal) + goToCommunal() communalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED) assertThat(isTutorialAvailable).isFalse() } @@ -94,7 +89,7 @@ class CommunalTutorialInteractorTest : SysuiTestCase() { fun tutorialUnavailable_whenCommunalNotAvailable() = testScope.runTest { val isTutorialAvailable by collectLastValue(underTest.isTutorialAvailable) - setCommunalAvailable(false) + kosmos.setCommunalAvailable(false) communalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_NOT_STARTED) keyguardRepository.setKeyguardShowing(true) assertThat(isTutorialAvailable).isFalse() @@ -104,10 +99,7 @@ class CommunalTutorialInteractorTest : SysuiTestCase() { fun tutorialAvailable_whenTutorialNotStarted() = testScope.runTest { val isTutorialAvailable by collectLastValue(underTest.isTutorialAvailable) - setCommunalAvailable(true) - keyguardRepository.setKeyguardShowing(true) - keyguardRepository.setKeyguardOccluded(false) - communalInteractor.onSceneChanged(CommunalSceneKey.Blank) + kosmos.setCommunalAvailable(true) communalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_NOT_STARTED) assertThat(isTutorialAvailable).isTrue() } @@ -116,10 +108,7 @@ class CommunalTutorialInteractorTest : SysuiTestCase() { fun tutorialAvailable_whenTutorialIsStarted() = testScope.runTest { val isTutorialAvailable by collectLastValue(underTest.isTutorialAvailable) - setCommunalAvailable(true) - keyguardRepository.setKeyguardShowing(true) - keyguardRepository.setKeyguardOccluded(false) - communalInteractor.onSceneChanged(CommunalSceneKey.Communal) + goToCommunal() communalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_STARTED) assertThat(isTutorialAvailable).isTrue() } @@ -129,10 +118,9 @@ class CommunalTutorialInteractorTest : SysuiTestCase() { testScope.runTest { val tutorialSettingState by collectLastValue(communalTutorialRepository.tutorialSettingState) - userRepository.setSelectedUserInfo(MAIN_USER_INFO) communalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_NOT_STARTED) - communalInteractor.onSceneChanged(CommunalSceneKey.Communal) + goToCommunal() assertThat(tutorialSettingState).isEqualTo(HUB_MODE_TUTORIAL_STARTED) } @@ -142,10 +130,10 @@ class CommunalTutorialInteractorTest : SysuiTestCase() { testScope.runTest { val tutorialSettingState by collectLastValue(communalTutorialRepository.tutorialSettingState) - userRepository.setSelectedUserInfo(MAIN_USER_INFO) + communalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_STARTED) - communalInteractor.onSceneChanged(CommunalSceneKey.Communal) + goToCommunal() assertThat(tutorialSettingState).isEqualTo(HUB_MODE_TUTORIAL_STARTED) } @@ -155,10 +143,9 @@ class CommunalTutorialInteractorTest : SysuiTestCase() { testScope.runTest { val tutorialSettingState by collectLastValue(communalTutorialRepository.tutorialSettingState) - userRepository.setSelectedUserInfo(MAIN_USER_INFO) communalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED) - communalInteractor.onSceneChanged(CommunalSceneKey.Communal) + goToCommunal() assertThat(tutorialSettingState).isEqualTo(HUB_MODE_TUTORIAL_COMPLETED) } @@ -168,7 +155,7 @@ class CommunalTutorialInteractorTest : SysuiTestCase() { testScope.runTest { val tutorialSettingState by collectLastValue(communalTutorialRepository.tutorialSettingState) - userRepository.setSelectedUserInfo(MAIN_USER_INFO) + kosmos.setCommunalAvailable(true) communalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_NOT_STARTED) communalInteractor.onSceneChanged(CommunalSceneKey.Blank) @@ -181,8 +168,7 @@ class CommunalTutorialInteractorTest : SysuiTestCase() { testScope.runTest { val tutorialSettingState by collectLastValue(communalTutorialRepository.tutorialSettingState) - userRepository.setSelectedUserInfo(MAIN_USER_INFO) - communalInteractor.onSceneChanged(CommunalSceneKey.Communal) + goToCommunal() communalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_STARTED) communalInteractor.onSceneChanged(CommunalSceneKey.Blank) @@ -195,8 +181,7 @@ class CommunalTutorialInteractorTest : SysuiTestCase() { testScope.runTest { val tutorialSettingState by collectLastValue(communalTutorialRepository.tutorialSettingState) - userRepository.setSelectedUserInfo(MAIN_USER_INFO) - communalInteractor.onSceneChanged(CommunalSceneKey.Communal) + goToCommunal() communalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED) communalInteractor.onSceneChanged(CommunalSceneKey.Blank) @@ -204,17 +189,8 @@ class CommunalTutorialInteractorTest : SysuiTestCase() { assertThat(tutorialSettingState).isEqualTo(HUB_MODE_TUTORIAL_COMPLETED) } - private suspend fun setCommunalAvailable(available: Boolean) { - if (available) { - keyguardRepository.setIsEncryptedOrLockdown(false) - userRepository.setSelectedUserInfo(MAIN_USER_INFO) - keyguardRepository.setKeyguardShowing(true) - } else { - keyguardRepository.setIsEncryptedOrLockdown(true) - } - } - - private companion object { - val MAIN_USER_INFO = UserInfo(0, "primary", UserInfo.FLAG_MAIN) + private suspend fun goToCommunal() { + kosmos.setCommunalAvailable(true) + communalInteractor.onSceneChanged(CommunalSceneKey.Communal) } } 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/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/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/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/LockscreenToDozingTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModelTest.kt new file mode 100644 index 000000000000..28f5eba28763 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModelTest.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 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 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/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/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/policy/BaseHeadsUpManagerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java index 87d25ddcc75c..6456669c09b6 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; @@ -83,8 +73,8 @@ public class BaseHeadsUpManagerTest extends SysuiTestCase { 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())); @@ -110,143 +100,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 +110,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 +118,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 +132,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 +149,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 +161,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 +172,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 +185,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 +199,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 +212,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 +223,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 +267,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 +276,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 +289,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 +330,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 +358,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 +377,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 +395,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 +409,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 +426,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 +463,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 +510,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 +532,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 +569,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/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/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_call.xml b/packages/SystemUI/res/drawable/ic_call.xml new file mode 100644 index 000000000000..859506ad5e7c --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_call.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. + --> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="960" + android:viewportHeight="960" + android:tint="?attr/colorControlNormal"> + <path + android:fillColor="@android:color/white" + android:pathData="M798,840Q673,840 551,785.5Q429,731 329,631Q229,531 174.5,409Q120,287 120,162Q120,144 132,132Q144,120 162,120L324,120Q338,120 349,129.5Q360,139 362,152L388,292Q390,308 387,319Q384,330 376,338L279,436Q299,473 326.5,507.5Q354,542 387,574Q418,605 452,631.5Q486,658 524,680L618,586Q627,577 641.5,572.5Q656,568 670,570L808,598Q822,602 831,612.5Q840,623 840,636L840,798Q840,816 828,828Q816,840 798,840ZM241,360L307,294Q307,294 307,294Q307,294 307,294L290,200Q290,200 290,200Q290,200 290,200L201,200Q201,200 201,200Q201,200 201,200Q206,241 215,281Q224,321 241,360ZM599,718Q638,735 678.5,745Q719,755 760,758Q760,758 760,758Q760,758 760,758L760,670Q760,670 760,670Q760,670 760,670L666,651Q666,651 666,651Q666,651 666,651L599,718ZM241,360Q241,360 241,360Q241,360 241,360Q241,360 241,360Q241,360 241,360L241,360Q241,360 241,360Q241,360 241,360L241,360Q241,360 241,360Q241,360 241,360L241,360ZM599,718L599,718Q599,718 599,718Q599,718 599,718L599,718Q599,718 599,718Q599,718 599,718L599,718Q599,718 599,718Q599,718 599,718Q599,718 599,718Q599,718 599,718Z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_filled_arrow_down.xml b/packages/SystemUI/res/drawable/ic_filled_arrow_down.xml new file mode 100644 index 000000000000..c85965fd0e58 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_filled_arrow_down.xml @@ -0,0 +1,25 @@ +<?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:viewportWidth="24" + android:viewportHeight="24" + android:width="24dp" + android:height="24dp"> + <path + android:pathData="M7 10l5 5 5 -5z" + android:fillColor="#FF000000"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_filled_arrow_up.xml b/packages/SystemUI/res/drawable/ic_filled_arrow_up.xml new file mode 100644 index 000000000000..8ee7e1330531 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_filled_arrow_up.xml @@ -0,0 +1,25 @@ +<?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:viewportWidth="24" + android:viewportHeight="24" + android:width="24dp" + android:height="24dp"> + <path + android:pathData="M7 14l5-5 5 5z" + android:fillColor="#FF000000"/> +</vector> 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/drawable/ic_music_note_off.xml b/packages/SystemUI/res/drawable/ic_music_note_off.xml new file mode 100644 index 000000000000..d583576911dd --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_music_note_off.xml @@ -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. + --> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportHeight="960" + android:viewportWidth="960"> + <path + android:fillColor="#FF000000" + android:pathData="M792,904L56,168L112,112L848,848L792,904ZM560,446L480,366L480,120L720,120L720,280L560,280L560,446ZM400,840Q334,840 287,793Q240,746 240,680Q240,614 287,567Q334,520 400,520Q423,520 442.5,525.5Q462,531 480,542L480,480L560,560L560,680Q560,746 513,793Q466,840 400,840Z" /> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_volume_off.xml b/packages/SystemUI/res/drawable/ic_volume_off.xml new file mode 100644 index 000000000000..209f684436ee --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_volume_off.xml @@ -0,0 +1,27 @@ +<!-- + ~ 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="24dp" + android:height="24dp" + android:viewportWidth="960" + android:viewportHeight="960" + android:tint="?attr/colorControlNormal" + android:autoMirrored="true"> + <path + android:fillColor="@android:color/white" + android:pathData="M792,904L671,783Q646,799 618,810.5Q590,822 560,829L560,747Q574,742 587.5,737Q601,732 613,725L480,592L480,800L280,600L120,600L120,360L248,360L56,168L112,112L848,848L792,904ZM784,672L726,614Q743,583 751.5,549Q760,515 760,479Q760,385 705,311Q650,237 560,211L560,129Q684,157 762,254.5Q840,352 840,479Q840,532 825.5,581Q811,630 784,672ZM650,538L560,448L560,318Q607,340 633.5,384Q660,428 660,480Q660,495 657.5,509.5Q655,524 650,538ZM480,368L376,264L480,160L480,368ZM400,606L400,512L328,440L328,440L200,440L200,520L314,520L400,606ZM364,476L364,476L364,476L364,476L364,476L364,476L364,476L364,476Z"/> +</vector>
\ No newline at end of file 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..32b1cadd1c6c 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -898,8 +898,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 +1518,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 +1742,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 +1825,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 +1870,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 53ad344189d8..ea0e3092a781 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1513,6 +1513,11 @@ <string name="volume_ringer_status_vibrate">Vibrate</string> <string name="volume_ringer_status_silent">Mute</string> + <!-- Media device casting volume slider label [CHAR_LIMIT=20] --> + <string name="media_device_cast">Cast</string> + <!-- A message shown when the notification volume changing is disabled because of the muted ring stream [CHAR_LIMIT=40]--> + <string name="stream_notification_unavailable">Unavailable because ring is muted</string> + <!-- Shown in the header of quick settings to indicate to the user that their phone ringer is on vibrate. [CHAR_LIMIT=NONE] --> <!-- Shown in the header of quick settings to indicate to the user that their phone ringer is on silent (muted). [CHAR_LIMIT=NONE] --> @@ -2231,6 +2236,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..05e07a788892 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) } + } } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java index 476497dea9c4..10d1891c8405 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java @@ -19,6 +19,7 @@ package com.android.keyguard; import static com.android.systemui.Flags.pinInputFieldStyledFocusState; import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow; +import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; import android.graphics.drawable.StateListDrawable; import android.util.TypedValue; @@ -150,18 +151,22 @@ public abstract class KeyguardPinBasedInputViewController<T extends KeyguardPinB } private void setKeyboardBasedFocusOutline(boolean isAnyKeyboardConnected) { - StateListDrawable background = (StateListDrawable) mPasswordEntry.getBackground(); - GradientDrawable stateDrawable = (GradientDrawable) background.getStateDrawable(0); + Drawable background = mPasswordEntry.getBackground(); + if (!(background instanceof StateListDrawable)) return; + Drawable stateDrawable = ((StateListDrawable) background).getStateDrawable(0); + if (!(stateDrawable instanceof GradientDrawable gradientDrawable)) return; + int color = getResources().getColor(R.color.bouncer_password_focus_color); if (!isAnyKeyboardConnected) { - stateDrawable.setStroke(0, color); + gradientDrawable.setStroke(0, color); } else { int strokeWidthInDP = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 3, getResources().getDisplayMetrics()); - stateDrawable.setStroke(strokeWidthInDP, color); + gradientDrawable.setStroke(strokeWidthInDP, color); } } + @Override protected void onViewDetached() { super.onViewDetached(); 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/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/accessibility/floatingmenu/MenuView.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java index 27f9106fde7c..6299739c4461 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java @@ -464,9 +464,6 @@ class MenuView extends FrameLayout implements Bundle fragmentArgs = new Bundle(); fragmentArgs.putStringArray("targets", targets.toArray(new String[0])); args.putBundle(":settings:show_fragment_args", fragmentArgs); - // TODO: b/318748373 - The fragment should set its own title using the targets - args.putString( - ":settings:show_fragment_title", "Accessibility Shortcut"); intent.replaceExtras(args); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); return intent; 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/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java index 716209d18a01..2c3ebe901850 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java @@ -80,6 +80,7 @@ import com.android.systemui.biometrics.ui.viewmodel.DeviceEntryUdfpsTouchOverlay import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor; import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor; import com.android.systemui.dagger.SysUISingleton; +import com.android.systemui.dagger.qualifiers.Application; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor; import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor; @@ -90,6 +91,7 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInterac import com.android.systemui.log.SessionTracker; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.power.domain.interactor.PowerInteractor; import com.android.systemui.shade.domain.interactor.ShadeInteractor; import com.android.systemui.shared.system.SysUiStatsLog; import com.android.systemui.statusbar.LockscreenShadeTransitionController; @@ -116,6 +118,7 @@ import java.util.concurrent.Executor; import javax.inject.Inject; +import kotlinx.coroutines.CoroutineScope; import kotlinx.coroutines.ExperimentalCoroutinesApi; /** @@ -173,6 +176,8 @@ public class UdfpsController implements DozeReceiver, Dumpable { mDefaultUdfpsTouchOverlayViewModel; @NonNull private final AlternateBouncerInteractor mAlternateBouncerInteractor; @NonNull private final UdfpsOverlayInteractor mUdfpsOverlayInteractor; + @NonNull private final PowerInteractor mPowerInteractor; + @NonNull private final CoroutineScope mScope; @NonNull private final InputManager mInputManager; @NonNull private final UdfpsKeyguardAccessibilityDelegate mUdfpsKeyguardAccessibilityDelegate; @NonNull private final SelectedUserInteractor mSelectedUserInteractor; @@ -296,7 +301,9 @@ public class UdfpsController implements DozeReceiver, Dumpable { mDeviceEntryUdfpsTouchOverlayViewModel, mDefaultUdfpsTouchOverlayViewModel, mShadeInteractor, - mUdfpsOverlayInteractor + mUdfpsOverlayInteractor, + mPowerInteractor, + mScope ))); } @@ -678,7 +685,9 @@ public class UdfpsController implements DozeReceiver, Dumpable { @NonNull KeyguardTransitionInteractor keyguardTransitionInteractor, Lazy<DeviceEntryUdfpsTouchOverlayViewModel> deviceEntryUdfpsTouchOverlayViewModel, Lazy<DefaultUdfpsTouchOverlayViewModel> defaultUdfpsTouchOverlayViewModel, - @NonNull UdfpsOverlayInteractor udfpsOverlayInteractor) { + @NonNull UdfpsOverlayInteractor udfpsOverlayInteractor, + @NonNull PowerInteractor powerInteractor, + @Application CoroutineScope scope) { mContext = context; mExecution = execution; mVibrator = vibrator; @@ -720,6 +729,8 @@ public class UdfpsController implements DozeReceiver, Dumpable { mShadeInteractor = shadeInteractor; mAlternateBouncerInteractor = alternateBouncerInteractor; mUdfpsOverlayInteractor = udfpsOverlayInteractor; + mPowerInteractor = powerInteractor; + mScope = scope; mInputManager = inputManager; mUdfpsKeyguardAccessibilityDelegate = udfpsKeyguardAccessibilityDelegate; mSelectedUserInteractor = selectedUserInteractor; diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt index a209eae5673b..921e39532f58 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt @@ -44,6 +44,7 @@ import android.view.accessibility.AccessibilityManager.TouchExplorationStateChan import androidx.annotation.LayoutRes import androidx.annotation.VisibleForTesting import com.android.keyguard.KeyguardUpdateMonitor +import com.android.systemui.Flags.udfpsViewPerformance import com.android.systemui.animation.ActivityTransitionAnimator import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams @@ -53,10 +54,13 @@ import com.android.systemui.biometrics.ui.viewmodel.DefaultUdfpsTouchOverlayView import com.android.systemui.biometrics.ui.viewmodel.DeviceEntryUdfpsTouchOverlayViewModel import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor +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.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 @@ -67,7 +71,13 @@ import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.user.domain.interactor.SelectedUserInteractor import dagger.Lazy +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.Job +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.launch private const val TAG = "UdfpsControllerOverlay" @@ -82,36 +92,45 @@ const val SETTING_REMOVE_ENROLLMENT_UI = "udfps_overlay_remove_enrollment_ui" @ExperimentalCoroutinesApi @UiThread class UdfpsControllerOverlay @JvmOverloads constructor( - private val context: Context, - private val inflater: LayoutInflater, - private val windowManager: WindowManager, - private val accessibilityManager: AccessibilityManager, - private val statusBarStateController: StatusBarStateController, - private val statusBarKeyguardViewManager: StatusBarKeyguardViewManager, - private val keyguardUpdateMonitor: KeyguardUpdateMonitor, - private val dialogManager: SystemUIDialogManager, - private val dumpManager: DumpManager, - private val transitionController: LockscreenShadeTransitionController, - private val configurationController: ConfigurationController, - private val keyguardStateController: KeyguardStateController, - private val unlockedScreenOffAnimationController: UnlockedScreenOffAnimationController, - private var udfpsDisplayModeProvider: UdfpsDisplayModeProvider, - val requestId: Long, - @RequestReason val requestReason: Int, - private val controllerCallback: IUdfpsOverlayControllerCallback, - private val onTouch: (View, MotionEvent, Boolean) -> Boolean, - private val activityTransitionAnimator: ActivityTransitionAnimator, - private val primaryBouncerInteractor: PrimaryBouncerInteractor, - private val alternateBouncerInteractor: AlternateBouncerInteractor, - private val isDebuggable: Boolean = Build.IS_DEBUGGABLE, - private val udfpsKeyguardAccessibilityDelegate: UdfpsKeyguardAccessibilityDelegate, - private val transitionInteractor: KeyguardTransitionInteractor, - private val selectedUserInteractor: SelectedUserInteractor, - private val deviceEntryUdfpsTouchOverlayViewModel: Lazy<DeviceEntryUdfpsTouchOverlayViewModel>, - private val defaultUdfpsTouchOverlayViewModel: Lazy<DefaultUdfpsTouchOverlayViewModel>, - private val shadeInteractor: ShadeInteractor, - private val udfpsOverlayInteractor: UdfpsOverlayInteractor, + private val context: Context, + private val inflater: LayoutInflater, + private val windowManager: WindowManager, + private val accessibilityManager: AccessibilityManager, + private val statusBarStateController: StatusBarStateController, + private val statusBarKeyguardViewManager: StatusBarKeyguardViewManager, + private val keyguardUpdateMonitor: KeyguardUpdateMonitor, + private val dialogManager: SystemUIDialogManager, + private val dumpManager: DumpManager, + private val transitionController: LockscreenShadeTransitionController, + private val configurationController: ConfigurationController, + private val keyguardStateController: KeyguardStateController, + private val unlockedScreenOffAnimationController: UnlockedScreenOffAnimationController, + private var udfpsDisplayModeProvider: UdfpsDisplayModeProvider, + val requestId: Long, + @RequestReason val requestReason: Int, + private val controllerCallback: IUdfpsOverlayControllerCallback, + private val onTouch: (View, MotionEvent, Boolean) -> Boolean, + private val activityTransitionAnimator: ActivityTransitionAnimator, + private val primaryBouncerInteractor: PrimaryBouncerInteractor, + private val alternateBouncerInteractor: AlternateBouncerInteractor, + private val isDebuggable: Boolean = Build.IS_DEBUGGABLE, + private val udfpsKeyguardAccessibilityDelegate: UdfpsKeyguardAccessibilityDelegate, + private val transitionInteractor: KeyguardTransitionInteractor, + private val selectedUserInteractor: SelectedUserInteractor, + private val deviceEntryUdfpsTouchOverlayViewModel: + Lazy<DeviceEntryUdfpsTouchOverlayViewModel>, + private val defaultUdfpsTouchOverlayViewModel: Lazy<DefaultUdfpsTouchOverlayViewModel>, + private val shadeInteractor: ShadeInteractor, + private val udfpsOverlayInteractor: UdfpsOverlayInteractor, + private val powerInteractor: PowerInteractor, + @Application private val scope: CoroutineScope, ) { + private val isFinishedGoingToSleep: Flow<Unit> = + powerInteractor.detailedWakefulness + .filter { it.internalWakefulnessState == WakefulnessState.ASLEEP } + .map { } // map to Unit + private var listenForAsleepJob: Job? = null + private var addViewRunnable: Runnable? = null private var overlayViewLegacy: UdfpsView? = null private set private var overlayTouchView: UdfpsTouchOverlay? = null @@ -192,7 +211,8 @@ class UdfpsControllerOverlay @JvmOverloads constructor( if (requestReason.isImportantForAccessibility()) { importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_NO } - windowManager.addView(this, coreLayoutParams.updateDimensions(null)) + + addViewNowOrLater(this, null) when (requestReason) { REASON_AUTH_KEYGUARD -> UdfpsTouchOverlayBinder.bind( @@ -225,7 +245,7 @@ class UdfpsControllerOverlay @JvmOverloads constructor( importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_NO } - windowManager.addView(this, coreLayoutParams.updateDimensions(animation)) + addViewNowOrLater(this, animation) sensorRect = sensorBounds } } @@ -257,6 +277,41 @@ class UdfpsControllerOverlay @JvmOverloads constructor( return false } + private fun addViewNowOrLater(view: View, animation: UdfpsAnimationViewController<*>?) { + if (udfpsViewPerformance()) { + addViewRunnable = kotlinx.coroutines.Runnable { + windowManager.addView( + view, + coreLayoutParams.updateDimensions(animation) + ) + } + if (powerInteractor.detailedWakefulness.value.internalWakefulnessState + != WakefulnessState.STARTING_TO_SLEEP) { + addViewIfPending() + } else { + listenForAsleepJob?.cancel() + listenForAsleepJob = scope.launch { + isFinishedGoingToSleep.collect { + addViewIfPending() + } + } + } + } else { + windowManager.addView( + view, + coreLayoutParams.updateDimensions(animation) + ) + } + } + + private fun addViewIfPending() { + addViewRunnable?.let { + listenForAsleepJob?.cancel() + it.run() + } + addViewRunnable = null + } + fun inflateUdfpsAnimation( view: UdfpsView, controller: UdfpsController @@ -368,6 +423,7 @@ class UdfpsControllerOverlay @JvmOverloads constructor( overlayViewLegacy = null overlayTouchView = null overlayTouchListener = null + listenForAsleepJob?.cancel() return wasShowing } @@ -412,7 +468,8 @@ class UdfpsControllerOverlay @JvmOverloads constructor( if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) { if (!shouldRotate(animation)) { Log.v( - TAG, "Skip rotating UDFPS bounds " + Surface.rotationToString(rot) + + TAG, + "Skip rotating UDFPS bounds " + Surface.rotationToString(rot) + " animation=$animation" + " isGoingToSleep=${keyguardUpdateMonitor.isGoingToSleep}" + " isOccluded=${keyguardStateController.isOccluded}" 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 5397837423ff..5d525413a919 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 @@ -129,8 +129,13 @@ constructor( /** * Target scene as requested by the underlying [SceneTransitionLayout] or through * [onSceneChanged]. + * + * If [isCommunalAvailable] is false, will return [CommunalSceneKey.Blank] */ - val desiredScene: StateFlow<CommunalSceneKey> = communalRepository.desiredScene + val desiredScene: Flow<CommunalSceneKey> = + communalRepository.desiredScene.combine(isCommunalAvailable) { scene, available -> + if (available) scene else CommunalSceneKey.Blank + } /** Transition state of the hub mode. */ val transitionState: StateFlow<ObservableCommunalTransitionState> = diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt index 8a7b5ebedb7a..3ec9a268f80c 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt @@ -34,7 +34,7 @@ abstract class BaseCommunalViewModel( private val communalInteractor: CommunalInteractor, val mediaHost: MediaHost, ) { - val currentScene: StateFlow<CommunalSceneKey> = communalInteractor.desiredScene + val currentScene: Flow<CommunalSceneKey> = communalInteractor.desiredScene /** Whether widgets are currently being re-ordered. */ open val reorderingWidgets: StateFlow<Boolean> = MutableStateFlow(false) 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/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/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/KeyguardBlueprintInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt index 56d64a298bc0..bc3f0cce2fc7 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt @@ -15,12 +15,15 @@ * */ +@file:OptIn(ExperimentalCoroutinesApi::class) + package com.android.systemui.keyguard.domain.interactor import android.content.Context import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.keyguard.data.repository.KeyguardBlueprintRepository +import com.android.systemui.keyguard.shared.ComposeLockscreen import com.android.systemui.keyguard.shared.model.KeyguardBlueprint import com.android.systemui.keyguard.ui.view.layout.blueprints.DefaultKeyguardBlueprint import com.android.systemui.keyguard.ui.view.layout.blueprints.SplitShadeKeyguardBlueprint @@ -29,7 +32,9 @@ import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.Intra import com.android.systemui.statusbar.policy.SplitShadeStateController import javax.inject.Inject import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.launch @@ -41,6 +46,7 @@ constructor( @Application private val applicationScope: CoroutineScope, private val context: Context, private val splitShadeStateController: SplitShadeStateController, + private val clockInteractor: KeyguardClockInteractor, ) { /** The current blueprint for the lockscreen. */ @@ -58,6 +64,7 @@ constructor( .onStart { emit(Unit) } .collect { updateBlueprint() } } + applicationScope.launch { clockInteractor.currentClock.collect { updateBlueprint() } } } /** @@ -67,12 +74,17 @@ constructor( private fun updateBlueprint() { val useSplitShade = splitShadeStateController.shouldUseSplitNotificationShade(context.resources) + // TODO(b/326098079): Make ID a constant value. + val useWeatherClockLayout = + clockInteractor.currentClock.value?.config?.id == "DIGITAL_CLOCK_WEATHER" && + ComposeLockscreen.isEnabled val blueprintId = - if (useSplitShade) { - SplitShadeKeyguardBlueprint.ID - } else { - DefaultKeyguardBlueprint.DEFAULT + when { + useWeatherClockLayout && useSplitShade -> SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID + useWeatherClockLayout -> WEATHER_CLOCK_BLUEPRINT_ID + useSplitShade -> SplitShadeKeyguardBlueprint.ID + else -> DefaultKeyguardBlueprint.DEFAULT } transitionToBlueprint(blueprintId) @@ -107,4 +119,13 @@ constructor( fun getCurrentBlueprint(): KeyguardBlueprint { return keyguardBlueprintRepository.blueprint.value } + + companion object { + /** + * These values live here because classes in the composable package do not exist in some + * systems. + */ + const val WEATHER_CLOCK_BLUEPRINT_ID = "weather-clock" + const val SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID = "split-shade-weather-clock" + } } 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/blueprints/KeyguardBlueprintModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/KeyguardBlueprintModule.kt index 4f1a754adbd5..b4e57cc93962 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/KeyguardBlueprintModule.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/KeyguardBlueprintModule.kt @@ -17,10 +17,13 @@ package com.android.systemui.keyguard.ui.view.layout.blueprints -import com.android.systemui.communal.ui.view.layout.blueprints.DefaultCommunalBlueprint +import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor.Companion.SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID +import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor.Companion.WEATHER_CLOCK_BLUEPRINT_ID import com.android.systemui.keyguard.shared.model.KeyguardBlueprint +import com.android.systemui.keyguard.shared.model.KeyguardSection import dagger.Binds import dagger.Module +import dagger.Provides import dagger.multibindings.IntoSet @Module @@ -43,9 +46,25 @@ abstract class KeyguardBlueprintModule { shortcutsBesideUdfpsLockscreenBlueprint: ShortcutsBesideUdfpsKeyguardBlueprint ): KeyguardBlueprint - @Binds - @IntoSet - abstract fun bindDefaultCommunalBlueprint( - defaultCommunalBlueprint: DefaultCommunalBlueprint - ): KeyguardBlueprint + companion object { + /** This is a place holder for weather clock in compose. */ + @Provides + @IntoSet + fun bindWeatherClockBlueprintPlaceHolder(): KeyguardBlueprint { + return object : KeyguardBlueprint { + override val id: String = WEATHER_CLOCK_BLUEPRINT_ID + override val sections: List<KeyguardSection> = listOf() + } + } + + /** This is a place holder for weather clock in compose. */ + @Provides + @IntoSet + fun bindSplitShadeWeatherClockBlueprintPlaceHolder(): KeyguardBlueprint { + return object : KeyguardBlueprint { + override val id: String = SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID + override val sections: List<KeyguardSection> = listOf() + } + } + } } 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/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/LockscreenToDozingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModel.kt index 4c0cd2f58eb7..b60c52b1c3df 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( @@ -45,4 +51,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/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java index cc3729b5b4d1..8b7c85b65824 100644 --- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java @@ -119,6 +119,16 @@ public class LogModule { return factory.create("LSShadeTransitionLog", 50); } + /** */ + @Provides + @SysUISingleton + @SensitiveNotificationProtectionLog + public static LogBuffer provideSensitiveNotificationProtectionLogBuffer( + LogBufferFactory factory + ) { + return factory.create("SensitiveNotificationProtectionLog", 10); + } + /** Provides a logging buffer for shade window messages. */ @Provides @SysUISingleton diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/SensitiveNotificationProtectionLog.kt b/packages/SystemUI/src/com/android/systemui/log/dagger/SensitiveNotificationProtectionLog.kt new file mode 100644 index 000000000000..54e87cde4686 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/SensitiveNotificationProtectionLog.kt @@ -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.systemui.log.dagger + +import javax.inject.Qualifier + +/** A [com.android.systemui.log.LogBuffer] for SensitiveNotificationProtection. */ +@Qualifier +@MustBeDocumented +@Retention(AnnotationRetention.RUNTIME) +annotation class SensitiveNotificationProtectionLog 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/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/controls/ui/controller/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManager.kt index 3b989d935cbd..dbd71f3e3a04 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManager.kt @@ -58,6 +58,7 @@ import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.statusbar.policy.SplitShadeStateController import com.android.systemui.util.animation.UniqueObjectHostView +import com.android.systemui.util.kotlin.BooleanFlowOperators.and import com.android.systemui.util.settings.SecureSettings import javax.inject.Inject import kotlinx.coroutines.CoroutineScope @@ -583,12 +584,14 @@ constructor( UserHandle.USER_ALL ) - // Listen to the communal UI state. + // Listen to the communal UI state. Make sure that communal UI is showing and hub itself is + // available, ie. not disabled and able to be shown. coroutineScope.launch { - communalInteractor.isCommunalShowing.collect { value -> - isCommunalShowing = value - updateDesiredLocation(forceNoAnimation = true) - } + and(communalInteractor.isCommunalShowing, communalInteractor.isCommunalAvailable) + .collect { value -> + isCommunalShowing = value + updateDesiredLocation() + } } } @@ -1150,12 +1153,16 @@ constructor( when { mediaFlags.isSceneContainerEnabled() -> desiredLocation dreamOverlayActive && dreamMediaComplicationActive -> LOCATION_DREAM_OVERLAY + + // UMO should show in communal unless the shade is expanding or visible. + isCommunalShowing && qsExpansion == 0.0f -> LOCATION_COMMUNAL_HUB (qsExpansion > 0.0f || inSplitShade) && !onLockscreen -> LOCATION_QS qsExpansion > 0.4f && onLockscreen -> LOCATION_QS onLockscreen && isSplitShadeExpanding() -> LOCATION_QS onLockscreen && isTransformingToFullShadeAndInQQS() -> LOCATION_QQS - // TODO(b/311234666): revisit logic once interactions between the hub and - // shade/keyguard state are finalized + + // Communal does not have its own StatusBarState so it should always have higher + // priority for the UMO over the lockscreen. isCommunalShowing -> LOCATION_COMMUNAL_HUB onLockscreen && allowMediaPlayerOnLockScreen -> LOCATION_LOCKSCREEN else -> LOCATION_QQS 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/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/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/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..d5bbaa5be53c 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java @@ -1539,6 +1539,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump @Override public void setOpenCloseListener(OpenCloseListener openCloseListener) { + SceneContainerFlag.assertInLegacyMode(); mOpenCloseListener = openCloseListener; } 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/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java index 3908edec7da5..ca19f71bd391 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java @@ -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(); + } } } 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/NotifCoordinators.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt index bd659d294223..b9d1dde82eeb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt @@ -53,6 +53,7 @@ class NotifCoordinatorsImpl @Inject constructor( mediaCoordinator: MediaCoordinator, preparationCoordinator: PreparationCoordinator, remoteInputCoordinator: RemoteInputCoordinator, + rowAlertTimeCoordinator: RowAlertTimeCoordinator, rowAppearanceCoordinator: RowAppearanceCoordinator, stackCoordinator: StackCoordinator, shadeEventCoordinator: ShadeEventCoordinator, @@ -69,9 +70,7 @@ class NotifCoordinatorsImpl @Inject constructor( private val mCoordinators: MutableList<Coordinator> = ArrayList() private val mOrderedSections: MutableList<NotifSectioner> = ArrayList() - /** - * Creates all the coordinators. - */ + /** Creates all the coordinators. */ init { // Attach core coordinators. mCoreCoordinators.add(dataStoreCoordinator) @@ -89,6 +88,7 @@ class NotifCoordinatorsImpl @Inject constructor( mCoordinators.add(groupCountCoordinator) mCoordinators.add(groupWhenCoordinator) mCoordinators.add(mediaCoordinator) + mCoordinators.add(rowAlertTimeCoordinator) mCoordinators.add(rowAppearanceCoordinator) mCoordinators.add(stackCoordinator) mCoordinators.add(shadeEventCoordinator) 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 new file mode 100644 index 000000000000..4a7b7ca51ba2 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAlertTimeCoordinator.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.statusbar.notification.collection.coordinator + +import android.util.ArrayMap +import com.android.systemui.statusbar.notification.collection.GroupEntry +import com.android.systemui.statusbar.notification.collection.ListEntry +import com.android.systemui.statusbar.notification.collection.NotifPipeline +import com.android.systemui.statusbar.notification.collection.NotificationEntry +import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope +import com.android.systemui.statusbar.notification.collection.render.NotifRowController +import javax.inject.Inject +import kotlin.math.max + +/** + * A small coordinator which ensures the "alerted" bell shows not just for recently alerted entries, + * but also on the summary for every such entry. + */ +@CoordinatorScope +class RowAlertTimeCoordinator @Inject constructor() : Coordinator { + + private val latestAlertTimeBySummary = ArrayMap<NotificationEntry, Long>() + + override fun attach(pipeline: NotifPipeline) { + pipeline.addOnBeforeFinalizeFilterListener(::onBeforeFinalizeFilterListener) + pipeline.addOnAfterRenderEntryListener(::onAfterRenderEntry) + } + + private fun onBeforeFinalizeFilterListener(entries: List<ListEntry>) { + latestAlertTimeBySummary.clear() + entries.asSequence().filterIsInstance<GroupEntry>().forEach { groupEntry -> + val summary = checkNotNull(groupEntry.summary) + latestAlertTimeBySummary[summary] = groupEntry.calculateLatestAlertTime() + } + } + + private fun onAfterRenderEntry(entry: NotificationEntry, controller: NotifRowController) { + // Show the "alerted" bell icon based on the latest group member for summaries + val lastAudiblyAlerted = latestAlertTimeBySummary[entry] ?: entry.lastAudiblyAlertedMs + controller.setLastAudibleMs(lastAudiblyAlerted) + } + + private fun GroupEntry.calculateLatestAlertTime(): Long { + 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/collection/coordinator/RowAppearanceCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinator.kt index f2b84827f3a3..df694bb67684 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinator.kt @@ -75,7 +75,5 @@ class RowAppearanceCoordinator @Inject internal constructor( (mAutoExpandFirstNotification && entry == entryToExpand)) // Show/hide the feedback icon controller.setFeedbackIcon(mAssistantFeedbackController.getFeedbackIcon(entry)) - // Show the "alerted" bell icon - controller.setLastAudibleMs(entry.lastAudiblyAlertedMs) } } 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/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java index d828ad70f5c4..decb244947ff 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java @@ -849,6 +849,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView public void setNotificationGroupWhen(long whenMillis) { if (mIsSummaryWithChildren) { mChildrenContainer.setNotificationGroupWhen(whenMillis); + mPublicLayout.setNotificationWhen(whenMillis); } else { Log.w(TAG, "setNotificationGroupWhen( whenMillis: " + whenMillis + ")" + " mIsSummaryWithChildren: false" @@ -2704,6 +2705,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } private void onAttachedChildrenCountChanged() { + final boolean wasSummary = mIsSummaryWithChildren; mIsSummaryWithChildren = mChildrenContainer != null && mChildrenContainer.getNotificationChildCount() > 0; if (mIsSummaryWithChildren) { @@ -2714,6 +2716,10 @@ public class ExpandableNotificationRow extends ActivatableNotificationView isConversation()); } } + if (!mIsSummaryWithChildren && wasSummary) { + // Reset the 'when' once the row stops being a summary + mPublicLayout.setNotificationWhen(mEntry.getSbn().getNotification().when); + } getShowingLayout().updateBackgroundColor(false /* animate */); mPrivateLayout.updateExpandButtons(isExpandable()); updateChildrenAppearance(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java index 402ea51bebb6..374248252d1f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java @@ -59,6 +59,7 @@ import com.android.systemui.statusbar.notification.collection.render.GroupMember import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier; import com.android.systemui.statusbar.notification.row.shared.AsyncHybridViewInflation; import com.android.systemui.statusbar.notification.row.wrapper.NotificationCustomViewWrapper; +import com.android.systemui.statusbar.notification.row.wrapper.NotificationHeaderViewWrapper; import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper; import com.android.systemui.statusbar.policy.InflatedSmartReplyState; import com.android.systemui.statusbar.policy.InflatedSmartReplyViewHolder; @@ -2314,6 +2315,13 @@ public class NotificationContentView extends FrameLayout implements Notification return false; } + public void setNotificationWhen(long whenMillis) { + NotificationViewWrapper wrapper = getNotificationViewWrapper(); + if (wrapper instanceof NotificationHeaderViewWrapper headerViewWrapper) { + headerViewWrapper.setNotificationWhen(whenMillis); + } + } + private static class RemoteInputViewData { @Nullable RemoteInputView mView; @Nullable RemoteInputViewController mController; 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/viewbinder/SharedNotificationContainerBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt index 5191053b6f72..566c0303b286 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt @@ -75,6 +75,24 @@ object SharedNotificationContainerBinder { } } + // Required to capture keyguard media changes and ensure the notification count is correct + val layoutChangeListener = + object : View.OnLayoutChangeListener { + override fun onLayoutChange( + view: View, + left: Int, + top: Int, + right: Int, + bottom: Int, + oldLeft: Int, + oldTop: Int, + oldRight: Int, + oldBottom: Int + ) { + viewModel.notificationStackChanged() + } + } + val burnInParams = MutableStateFlow(BurnInParameters()) val viewState = ViewStateAccessor( @@ -170,6 +188,7 @@ object SharedNotificationContainerBinder { } insets } + view.addOnLayoutChangeListener(layoutChangeListener) return object : DisposableHandle { override fun dispose() { @@ -177,6 +196,7 @@ object SharedNotificationContainerBinder { disposableHandleMainImmediate.dispose() controller.setOnHeightChangedRunnable(null) view.setOnApplyWindowInsetsListener(null) + view.removeOnLayoutChangeListener(layoutChangeListener) } } } 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/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/domain/interactor/MobileIconInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt index 6b303263d4b0..5e38715fefa2 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> @@ -306,6 +309,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/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/policy/SensitiveNotificationProtectionControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerImpl.java index 6956a7d8a8e3..18ec68bd89eb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerImpl.java @@ -51,6 +51,7 @@ import javax.inject.Inject; public class SensitiveNotificationProtectionControllerImpl implements SensitiveNotificationProtectionController { private static final String LOG_TAG = "SNPC"; + private final SensitiveNotificationProtectionControllerLogger mLogger; private final ArraySet<String> mExemptPackages = new ArraySet<>(); private final ListenerSet<Runnable> mListeners = new ListenerSet<>(); private volatile MediaProjectionInfo mProjection; @@ -66,6 +67,7 @@ public class SensitiveNotificationProtectionControllerImpl if (mDisableScreenShareProtections) { Log.w(LOG_TAG, "Screen share protections disabled, ignoring projectionstart"); + mLogger.logProjectionStart(false, info.getPackageName()); return; } @@ -73,6 +75,7 @@ public class SensitiveNotificationProtectionControllerImpl // Launch cookie only set (non-null) if sharing single app/task updateProjectionStateAndNotifyListeners( (info.getLaunchCookie() == null) ? info : null); + mLogger.logProjectionStart(isSensitiveStateActive(), info.getPackageName()); } finally { Trace.endSection(); } @@ -82,6 +85,7 @@ public class SensitiveNotificationProtectionControllerImpl public void onStop(MediaProjectionInfo info) { Trace.beginSection("SNPC.onProjectionStop"); try { + mLogger.logProjectionStop(); updateProjectionStateAndNotifyListeners(null); } finally { Trace.endSection(); @@ -96,7 +100,10 @@ public class SensitiveNotificationProtectionControllerImpl MediaProjectionManager mediaProjectionManager, IActivityManager activityManager, @Main Handler mainHandler, - @Background Executor bgExecutor) { + @Background Executor bgExecutor, + SensitiveNotificationProtectionControllerLogger logger) { + mLogger = logger; + if (!screenshareNotificationHiding()) { return; } @@ -202,8 +209,6 @@ public class SensitiveNotificationProtectionControllerImpl return false; } - // TODO(b/316955558): Add disabled by developer option - return !mExemptPackages.contains(projection.getPackageName()); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerLogger.kt new file mode 100644 index 000000000000..70c5239f0ec6 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerLogger.kt @@ -0,0 +1,45 @@ +/* + * 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 com.android.systemui.log.LogBuffer +import com.android.systemui.log.core.LogLevel +import com.android.systemui.log.dagger.SensitiveNotificationProtectionLog +import javax.inject.Inject + +/** Logger for [SensitiveNotificationProtectionController]. */ +class SensitiveNotificationProtectionControllerLogger +@Inject +constructor(@SensitiveNotificationProtectionLog private val buffer: LogBuffer) { + fun logProjectionStart(protectionEnabled: Boolean, pkg: String) { + buffer.log( + TAG, + LogLevel.DEBUG, + { + bool1 = protectionEnabled + str1 = pkg + }, + { "Projection started - protection enabled:$bool1, pkg=$str1" } + ) + } + + fun logProjectionStop() { + buffer.log(TAG, LogLevel.DEBUG, {}, { "Projection ended - protection disabled" }) + } +} + +private const val TAG = "SNPC" 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/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/shared/model/VolumePanelComponents.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/shared/model/VolumePanelComponents.kt index f11ac5e1a8e4..9d801fc9bfa1 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/shared/model/VolumePanelComponents.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/shared/model/VolumePanelComponents.kt @@ -22,6 +22,7 @@ object VolumePanelComponents { const val MEDIA_OUTPUT: VolumePanelComponentKey = "media_output" const val BOTTOM_BAR: VolumePanelComponentKey = "bottom_bar" + const val VOLUME_SLIDERS: VolumePanelComponentKey = "volume_sliders" const val CAPTIONING: VolumePanelComponentKey = "captioning" const val ANC: VolumePanelComponentKey = "anc" } 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/volume/panel/component/volume/domain/interactor/VolumeSliderInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/domain/interactor/VolumeSliderInteractor.kt index 52736c6cb08b..0c91bbf60f1b 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/domain/interactor/VolumeSliderInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/domain/interactor/VolumeSliderInteractor.kt @@ -24,7 +24,7 @@ import javax.inject.Inject class VolumeSliderInteractor @Inject constructor() { /** mimic percentage volume setting */ - private val displayValueRange: ClosedFloatingPointRange<Float> = 0f..100f + val displayValueRange: ClosedFloatingPointRange<Float> = 0f..100f /** * Translates [volume], that belongs to [volumeRange] to the value that belongs to diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModel.kt new file mode 100644 index 000000000000..faf743475579 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModel.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.volume.slider.ui.viewmodel + +import android.content.Context +import android.media.AudioManager +import com.android.settingslib.volume.domain.interactor.AudioVolumeInteractor +import com.android.settingslib.volume.shared.model.AudioStream +import com.android.settingslib.volume.shared.model.AudioStreamModel +import com.android.systemui.common.shared.model.Icon +import com.android.systemui.res.R +import com.android.systemui.volume.panel.component.volume.domain.interactor.VolumeSliderInteractor +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.launch + +/** Models a particular slider state. */ +class AudioStreamSliderViewModel +@AssistedInject +constructor( + @Assisted private val audioStreamWrapper: FactoryAudioStreamWrapper, + @Assisted private val coroutineScope: CoroutineScope, + private val context: Context, + private val audioVolumeInteractor: AudioVolumeInteractor, + private val volumeSliderInteractor: VolumeSliderInteractor, +) : SliderViewModel { + + private val audioStream = audioStreamWrapper.audioStream + private val iconsByStream = + mapOf( + AudioStream(AudioManager.STREAM_MUSIC) to R.drawable.ic_music_note, + AudioStream(AudioManager.STREAM_VOICE_CALL) to R.drawable.ic_call, + AudioStream(AudioManager.STREAM_RING) to R.drawable.ic_ring_volume, + AudioStream(AudioManager.STREAM_NOTIFICATION) to R.drawable.ic_volume_ringer, + AudioStream(AudioManager.STREAM_ALARM) to R.drawable.ic_volume_alarm, + ) + private val mutedIconsByStream = + mapOf( + AudioStream(AudioManager.STREAM_MUSIC) to R.drawable.ic_volume_off, + AudioStream(AudioManager.STREAM_VOICE_CALL) to R.drawable.ic_volume_off, + AudioStream(AudioManager.STREAM_RING) to R.drawable.ic_volume_off, + AudioStream(AudioManager.STREAM_NOTIFICATION) to R.drawable.ic_volume_off, + AudioStream(AudioManager.STREAM_ALARM) to R.drawable.ic_volume_off, + ) + private val labelsByStream = + mapOf( + AudioStream(AudioManager.STREAM_MUSIC) to R.string.stream_music, + AudioStream(AudioManager.STREAM_VOICE_CALL) to R.string.stream_voice_call, + AudioStream(AudioManager.STREAM_RING) to R.string.stream_ring, + AudioStream(AudioManager.STREAM_NOTIFICATION) to R.string.stream_notification, + AudioStream(AudioManager.STREAM_ALARM) to R.string.stream_alarm, + ) + private val disabledTextByStream = + mapOf( + AudioStream(AudioManager.STREAM_NOTIFICATION) to + R.string.stream_notification_unavailable, + ) + + private var value = 0f + override val slider: StateFlow<SliderState> = + combine( + audioVolumeInteractor.getAudioStream(audioStream), + audioVolumeInteractor.canChangeVolume(audioStream), + ) { model, isEnabled -> + model.toState(value, isEnabled) + } + .stateIn(coroutineScope, SharingStarted.Eagerly, EmptyState) + + override fun onValueChangeFinished(state: SliderState, newValue: Float) { + val audioViewModel = state as? State + audioViewModel ?: return + coroutineScope.launch { + value = newValue + val volume = + volumeSliderInteractor.translateValueToVolume( + newValue, + audioViewModel.audioStreamModel.volumeRange + ) + audioVolumeInteractor.setVolume(audioStream, volume) + } + } + + private fun AudioStreamModel.toState(value: Float, isEnabled: Boolean): State { + return State( + value = + volumeSliderInteractor.processVolumeToValue( + volume, + volumeRange, + value, + isMuted, + ), + valueRange = volumeSliderInteractor.displayValueRange, + icon = getIcon(this), + label = labelsByStream[audioStream]?.let(context::getString) + ?: error("No label for the stream: $audioStream"), + disabledMessage = disabledTextByStream[audioStream]?.let(context::getString), + isEnabled = isEnabled, + audioStreamModel = this, + ) + } + + private fun getIcon(model: AudioStreamModel): Icon { + val isMutedOrNoVolume = model.isMuted || model.volume == model.minVolume + val iconRes = + if (isMutedOrNoVolume) { + mutedIconsByStream + } else { + iconsByStream + }[audioStream] + ?: error("No icon for the stream: $audioStream") + return Icon.Resource(iconRes, null) + } + + private val AudioStreamModel.volumeRange: IntRange + get() = minVolume..maxVolume + + private data class State( + override val value: Float, + override val valueRange: ClosedFloatingPointRange<Float>, + override val icon: Icon, + override val label: String, + override val disabledMessage: String?, + override val isEnabled: Boolean, + val audioStreamModel: AudioStreamModel, + ) : SliderState + + private data object EmptyState : SliderState { + override val value: Float = 0f + override val valueRange: ClosedFloatingPointRange<Float> = 0f..1f + override val icon: Icon? = null + override val label: String = "" + override val disabledMessage: String? = null + override val isEnabled: Boolean = true + } + + @AssistedFactory + interface Factory { + + fun create( + audioStream: FactoryAudioStreamWrapper, + coroutineScope: CoroutineScope, + ): AudioStreamSliderViewModel + } + + /** + * AudioStream is a value class that compiles into a primitive. This fail AssistedFactory build + * when using [AudioStream] directly because it expects another type. + */ + class FactoryAudioStreamWrapper(val audioStream: AudioStream) +} diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/CastVolumeSliderViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/CastVolumeSliderViewModel.kt new file mode 100644 index 000000000000..ae93826c0c17 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/CastVolumeSliderViewModel.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.volume.panel.component.volume.slider.ui.viewmodel + +import android.content.Context +import com.android.settingslib.volume.domain.model.RoutingSession +import com.android.systemui.common.shared.model.Icon +import com.android.systemui.res.R +import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaOutputInteractor +import com.android.systemui.volume.panel.component.volume.domain.interactor.CastVolumeInteractor +import com.android.systemui.volume.panel.component.volume.domain.interactor.VolumeSliderInteractor +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.launch + +class CastVolumeSliderViewModel +@AssistedInject +constructor( + @Assisted private val routingSession: RoutingSession, + @Assisted private val coroutineScope: CoroutineScope, + private val context: Context, + mediaOutputInteractor: MediaOutputInteractor, + private val volumeSliderInteractor: VolumeSliderInteractor, + private val castVolumeInteractor: CastVolumeInteractor, +) : SliderViewModel { + + private val volumeRange = 0..routingSession.routingSessionInfo.volumeMax + private val value = MutableStateFlow(0f) + + override val slider: StateFlow<SliderState> = + combine(value, mediaOutputInteractor.currentConnectedDevice) { value, _ -> + getCurrentState(value) + } + .stateIn(coroutineScope, SharingStarted.Eagerly, getCurrentState(value.value)) + + override fun onValueChangeFinished(state: SliderState, newValue: Float) { + coroutineScope.launch { + value.value = newValue + castVolumeInteractor.setVolume( + routingSession, + volumeSliderInteractor.translateValueToVolume(newValue, volumeRange), + ) + } + } + + private fun getCurrentState(value: Float): State { + return State( + value = + volumeSliderInteractor.processVolumeToValue( + volume = routingSession.routingSessionInfo.volume, + volumeRange = volumeRange, + currentValue = value, + isMuted = false, + ), + valueRange = volumeSliderInteractor.displayValueRange, + icon = Icon.Resource(R.drawable.ic_cast, null), + label = context.getString(R.string.media_device_cast), + isEnabled = true, + ) + } + + private data class State( + override val value: Float, + override val valueRange: ClosedFloatingPointRange<Float>, + override val icon: Icon, + override val label: String, + override val isEnabled: Boolean, + ) : SliderState { + override val disabledMessage: String? + get() = null + } + + @AssistedFactory + interface Factory { + + fun create( + routingSession: RoutingSession, + coroutineScope: CoroutineScope, + ): CastVolumeSliderViewModel + } +} diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/SliderState.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/SliderState.kt new file mode 100644 index 000000000000..6e9794b02143 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/SliderState.kt @@ -0,0 +1,33 @@ +/* + * 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.volume.slider.ui.viewmodel + +import com.android.systemui.common.shared.model.Icon + +/** + * Models a state of a volume slider. + * + * @property disabledMessage is shown when [isEnabled] is false + */ +sealed interface SliderState { + val value: Float + val valueRange: ClosedFloatingPointRange<Float> + val icon: Icon? + val label: String + val disabledMessage: String? + val isEnabled: Boolean +} diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/SliderViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/SliderViewModel.kt new file mode 100644 index 000000000000..0c4b3222e34d --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/SliderViewModel.kt @@ -0,0 +1,27 @@ +/* + * 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.volume.slider.ui.viewmodel + +import kotlinx.coroutines.flow.StateFlow + +/** Controls the behaviour of a volume slider. */ +interface SliderViewModel { + + val slider: StateFlow<SliderState> + + fun onValueChangeFinished(state: SliderState, newValue: Float) +} diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/ui/viewmodel/AudioVolumeComponentViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/ui/viewmodel/AudioVolumeComponentViewModel.kt new file mode 100644 index 000000000000..2824323775d3 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/ui/viewmodel/AudioVolumeComponentViewModel.kt @@ -0,0 +1,93 @@ +/* + * 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.volume.ui.viewmodel + +import android.media.AudioManager +import com.android.settingslib.volume.shared.model.AudioStream +import com.android.systemui.volume.panel.component.volume.domain.interactor.CastVolumeInteractor +import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.AudioStreamSliderViewModel +import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.CastVolumeSliderViewModel +import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.SliderViewModel +import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope +import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.flow.transformLatest + +/** + * Controls the behaviour of the whole audio + * [com.android.systemui.volume.panel.shared.model.VolumePanelUiComponent]. + */ +@OptIn(ExperimentalCoroutinesApi::class) +@VolumePanelScope +class AudioVolumeComponentViewModel +@Inject +constructor( + @VolumePanelScope private val scope: CoroutineScope, + castVolumeInteractor: CastVolumeInteractor, + private val streamSliderViewModelFactory: AudioStreamSliderViewModel.Factory, + private val castVolumeSliderViewModelFactory: CastVolumeSliderViewModel.Factory, +) { + + private val remoteSessionsViewModels: Flow<List<SliderViewModel>> = + castVolumeInteractor.remoteRoutingSessions.transformLatest { routingSessions -> + coroutineScope { + emit( + routingSessions.map { routingSession -> + castVolumeSliderViewModelFactory.create(routingSession, this) + } + ) + } + } + private val streamViewModels: Flow<List<SliderViewModel>> = + flowOf( + listOf( + AudioStream(AudioManager.STREAM_MUSIC), + AudioStream(AudioManager.STREAM_VOICE_CALL), + AudioStream(AudioManager.STREAM_RING), + AudioStream(AudioManager.STREAM_NOTIFICATION), + AudioStream(AudioManager.STREAM_ALARM), + ) + ) + .transformLatest { streams -> + coroutineScope { + emit( + streams.map { stream -> + streamSliderViewModelFactory.create( + AudioStreamSliderViewModel.FactoryAudioStreamWrapper(stream), + this, + ) + } + ) + } + } + + val sliderViewModels: StateFlow<List<SliderViewModel>> = + combine(remoteSessionsViewModels, streamViewModels) { + remoteSessionsViewModels, + streamViewModels -> + remoteSessionsViewModels + streamViewModels + } + .stateIn(scope, SharingStarted.Eagerly, emptyList()) +} diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/dagger/VolumePanelComponent.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/dagger/VolumePanelComponent.kt index df4972aeafea..f31ee865eaac 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/panel/dagger/VolumePanelComponent.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/panel/dagger/VolumePanelComponent.kt @@ -20,6 +20,7 @@ import com.android.systemui.volume.panel.component.anc.AncModule import com.android.systemui.volume.panel.component.bottombar.BottomBarModule import com.android.systemui.volume.panel.component.captioning.CaptioningModule import com.android.systemui.volume.panel.component.mediaoutput.MediaOutputModule +import com.android.systemui.volume.panel.component.volume.VolumeSlidersModule import com.android.systemui.volume.panel.dagger.factory.VolumePanelComponentFactory import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope import com.android.systemui.volume.panel.domain.DomainModule @@ -48,6 +49,7 @@ import kotlinx.coroutines.CoroutineScope // Components modules BottomBarModule::class, AncModule::class, + VolumeSlidersModule::class, CaptioningModule::class, MediaOutputModule::class, ] diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/domain/DomainModule.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/domain/DomainModule.kt index 0d65c429eac6..57ea9972012f 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/panel/domain/DomainModule.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/panel/domain/DomainModule.kt @@ -52,6 +52,7 @@ interface DomainModule { return setOf( VolumePanelComponents.ANC, VolumePanelComponents.CAPTIONING, + VolumePanelComponents.VOLUME_SLIDERS, VolumePanelComponents.MEDIA_OUTPUT, VolumePanelComponents.BOTTOM_BAR, ) diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuItemAccessibilityDelegateTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuItemAccessibilityDelegateTest.java index c2ed7d4a9d3c..976cd5bd21c4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuItemAccessibilityDelegateTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuItemAccessibilityDelegateTest.java @@ -21,6 +21,7 @@ import static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.ACTIO import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; @@ -89,6 +90,7 @@ public class MenuItemAccessibilityDelegateTest extends SysuiTestCase { mMenuView = spy(new MenuView(mContext, stubMenuViewModel, stubMenuViewAppearance, mSecureSettings)); mMenuView.setTranslationY(halfScreenHeight); + doNothing().when(mMenuView).gotoEditScreen(); mMenuViewLayer = spy(new MenuViewLayer( mContext, stubWindowManager, mAccessibilityManager, diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java index ce4db8febb6c..3862b0f5cf74 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java @@ -160,6 +160,7 @@ public class MenuViewLayerTest extends SysuiTestCase { new MenuView(mSpyContext, mMenuViewModel, menuViewAppearance, mSecureSettings)); // Ensure tests don't actually update metrics. doNothing().when(mMenuView).incrementTexMetric(any(), anyInt()); + doNothing().when(mMenuView).gotoEditScreen(); mMenuViewLayer = spy(new MenuViewLayer(mSpyContext, mStubWindowManager, mStubAccessibilityManager, mMenuViewModel, menuViewAppearance, mMenuView, diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java index 7c97f53d539d..1ce65258ef4d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java @@ -21,6 +21,7 @@ import static android.app.UiModeManager.MODE_NIGHT_YES; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; @@ -80,6 +81,7 @@ public class MenuViewTest extends SysuiTestCase { mUiModeManager.setNightMode(MODE_NIGHT_YES); mSpyContext = spy(mContext); + doNothing().when(mSpyContext).startActivity(any()); final SecureSettings secureSettings = TestUtils.mockSecureSettings(); final MenuViewModel stubMenuViewModel = new MenuViewModel(mContext, mAccessibilityManager, secureSettings); @@ -179,8 +181,6 @@ public class MenuViewTest extends SysuiTestCase { @Test @EnableFlags(Flags.FLAG_FLOATING_MENU_DRAG_TO_EDIT) public void gotoEditScreen_sendsIntent() { - // Notably, this shouldn't crash the settings app, - // because the button target args are configured. mMenuView.gotoEditScreen(); verify(mSpyContext).startActivity(any()); } 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/KeyguardBlueprintInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorTest.kt index 9df00d3682a4..b0d8de359cd7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorTest.kt @@ -19,17 +19,23 @@ package com.android.systemui.keyguard.domain.interactor 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.keyguard.data.repository.KeyguardBlueprintRepository +import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor.Companion.SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID +import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor.Companion.WEATHER_CLOCK_BLUEPRINT_ID import com.android.systemui.keyguard.ui.view.layout.blueprints.DefaultKeyguardBlueprint import com.android.systemui.keyguard.ui.view.layout.blueprints.SplitShadeKeyguardBlueprint import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition.Config import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition.Type +import com.android.systemui.plugins.clocks.ClockConfig +import com.android.systemui.plugins.clocks.ClockController import com.android.systemui.statusbar.policy.SplitShadeStateController import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.whenever import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runCurrent @@ -38,6 +44,7 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock +import org.mockito.Mockito.never import org.mockito.Mockito.reset import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations @@ -54,6 +61,8 @@ class KeyguardBlueprintInteractorTest : SysuiTestCase() { @Mock private lateinit var splitShadeStateController: SplitShadeStateController @Mock private lateinit var keyguardBlueprintRepository: KeyguardBlueprintRepository + @Mock private lateinit var clockInteractor: KeyguardClockInteractor + @Mock private lateinit var clockController: ClockController @Before fun setup() { @@ -61,6 +70,8 @@ class KeyguardBlueprintInteractorTest : SysuiTestCase() { testScope = TestScope(StandardTestDispatcher()) whenever(keyguardBlueprintRepository.configurationChange).thenReturn(configurationFlow) whenever(keyguardBlueprintRepository.refreshTransition).thenReturn(refreshTransition) + whenever(clockInteractor.currentClock).thenReturn(MutableStateFlow(clockController)) + clockInteractor.currentClock underTest = KeyguardBlueprintInteractor( @@ -68,6 +79,7 @@ class KeyguardBlueprintInteractorTest : SysuiTestCase() { testScope.backgroundScope, mContext, splitShadeStateController, + clockInteractor, ) } @@ -102,6 +114,77 @@ class KeyguardBlueprintInteractorTest : SysuiTestCase() { } @Test + fun composeLockscreenOff_DoesAppliesSplitShadeWeatherClockBlueprint() { + testScope.runTest { + mSetFlagsRule.disableFlags(Flags.FLAG_COMPOSE_LOCKSCREEN) + whenever(clockController.config) + .thenReturn( + ClockConfig( + id = "DIGITAL_CLOCK_WEATHER", + name = "clock", + description = "clock", + ) + ) + whenever(splitShadeStateController.shouldUseSplitNotificationShade(any())) + .thenReturn(true) + + reset(keyguardBlueprintRepository) + configurationFlow.tryEmit(Unit) + runCurrent() + + verify(keyguardBlueprintRepository, never()) + .applyBlueprint(SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID) + } + } + + @Test + fun testDoesAppliesSplitShadeWeatherClockBlueprint() { + testScope.runTest { + mSetFlagsRule.enableFlags(Flags.FLAG_COMPOSE_LOCKSCREEN) + whenever(clockController.config) + .thenReturn( + ClockConfig( + id = "DIGITAL_CLOCK_WEATHER", + name = "clock", + description = "clock", + ) + ) + whenever(splitShadeStateController.shouldUseSplitNotificationShade(any())) + .thenReturn(true) + + reset(keyguardBlueprintRepository) + configurationFlow.tryEmit(Unit) + runCurrent() + + verify(keyguardBlueprintRepository) + .applyBlueprint(SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID) + } + } + + @Test + fun testAppliesWeatherClockBlueprint() { + testScope.runTest { + mSetFlagsRule.enableFlags(Flags.FLAG_COMPOSE_LOCKSCREEN) + whenever(clockController.config) + .thenReturn( + ClockConfig( + id = "DIGITAL_CLOCK_WEATHER", + name = "clock", + description = "clock", + ) + ) + whenever(splitShadeStateController.shouldUseSplitNotificationShade(any())) + .thenReturn(false) + + reset(keyguardBlueprintRepository) + configurationFlow.tryEmit(Unit) + runCurrent() + + verify(keyguardBlueprintRepository).applyBlueprint(WEATHER_CLOCK_BLUEPRINT_ID) + } + } + + @Test fun testRefreshBlueprint() { underTest.refreshBlueprint() verify(keyguardBlueprintRepository).refreshBlueprint() 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/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModelTest.kt b/packages/SystemUI/tests/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/tests/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/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/controls/ui/controller/MediaHierarchyManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManagerTest.kt index 85291b814b3c..45f49f01a43e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManagerTest.kt @@ -24,8 +24,10 @@ import android.view.ViewGroup import android.widget.FrameLayout import androidx.test.filters.SmallTest import com.android.keyguard.KeyguardViewController +import com.android.systemui.Flags import com.android.systemui.SysuiTestCase import com.android.systemui.communal.domain.interactor.communalInteractor +import com.android.systemui.communal.domain.interactor.setCommunalAvailable import com.android.systemui.communal.shared.model.CommunalSceneKey import com.android.systemui.controls.controller.ControlsControllerImplTest.Companion.eq import com.android.systemui.dreams.DreamOverlayStateController @@ -508,6 +510,10 @@ class MediaHierarchyManagerTest : SysuiTestCase() { @Test fun testCommunalLocation() = testScope.runTest { + mSetFlagsRule.enableFlags(Flags.FLAG_COMMUNAL_HUB) + kosmos.setCommunalAvailable(true) + runCurrent() + communalInteractor.onSceneChanged(CommunalSceneKey.Communal) runCurrent() verify(mediaCarouselController) @@ -533,6 +539,66 @@ class MediaHierarchyManagerTest : SysuiTestCase() { } @Test + fun testCommunalLocation_showsOverLockscreen() = + testScope.runTest { + mSetFlagsRule.enableFlags(Flags.FLAG_COMMUNAL_HUB) + kosmos.setCommunalAvailable(true) + runCurrent() + + // Device is on lock screen. + whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD) + + // UMO goes to communal even over the lock screen. + communalInteractor.onSceneChanged(CommunalSceneKey.Communal) + runCurrent() + verify(mediaCarouselController) + .onDesiredLocationChanged( + eq(MediaHierarchyManager.LOCATION_COMMUNAL_HUB), + nullable(), + eq(false), + anyLong(), + anyLong() + ) + } + + @Test + fun testCommunalLocation_showsUntilQsExpands() = + testScope.runTest { + mSetFlagsRule.enableFlags(Flags.FLAG_COMMUNAL_HUB) + kosmos.setCommunalAvailable(true) + runCurrent() + + // Device is on lock screen. + whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD) + + communalInteractor.onSceneChanged(CommunalSceneKey.Communal) + runCurrent() + verify(mediaCarouselController) + .onDesiredLocationChanged( + eq(MediaHierarchyManager.LOCATION_COMMUNAL_HUB), + nullable(), + eq(false), + anyLong(), + anyLong() + ) + clearInvocations(mediaCarouselController) + + // Start opening the shade. + mediaHierarchyManager.qsExpansion = 0.1f + runCurrent() + + // UMO goes to the shade instead. + verify(mediaCarouselController) + .onDesiredLocationChanged( + eq(MediaHierarchyManager.LOCATION_QS), + any(MediaHostState::class.java), + eq(false), + anyLong(), + anyLong() + ) + } + + @Test fun testQsExpandedChanged_noQqsMedia() { // When we are looking at QQS with active media whenever(statusBarStateController.state).thenReturn(StatusBarState.SHADE) 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/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/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/GlanceableHubContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt index 1dc5f7dbf6fe..665fc750c742 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt @@ -26,17 +26,20 @@ import android.view.View import android.view.WindowManager import android.widget.FrameLayout import androidx.test.filters.SmallTest +import com.android.systemui.Flags import com.android.systemui.SysuiTestCase import com.android.systemui.communal.data.repository.FakeCommunalRepository import com.android.systemui.communal.data.repository.fakeCommunalRepository import com.android.systemui.communal.domain.interactor.CommunalInteractor import com.android.systemui.communal.domain.interactor.communalInteractor +import com.android.systemui.communal.domain.interactor.setCommunalAvailable import com.android.systemui.communal.shared.model.CommunalSceneKey import com.android.systemui.communal.ui.viewmodel.CommunalViewModel import com.android.systemui.compose.ComposeFacade import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.testDispatcher +import com.android.systemui.kosmos.testScope import com.android.systemui.res.R import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.testKosmos @@ -45,6 +48,7 @@ import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.launch import kotlinx.coroutines.test.UnconfinedTestDispatcher import org.junit.After import org.junit.Assert.assertThrows @@ -114,6 +118,14 @@ class GlanceableHubContainerControllerTest : SysuiTestCase() { BOTTOM_SWIPE_REGION_WIDTH ) + // Make communal available so that communalInteractor.desiredScene accurately reflects + // scene changes instead of just returning Blank. + mSetFlagsRule.enableFlags(Flags.FLAG_COMMUNAL_HUB) + with(kosmos.testScope) { + launch { kosmos.setCommunalAvailable(true) } + testScheduler.runCurrent() + } + initAndAttachContainerView() } 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/notification/collection/coordinator/RowAlertTimeCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAlertTimeCoordinatorTest.kt new file mode 100644 index 000000000000..7daadb07f89a --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAlertTimeCoordinatorTest.kt @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.statusbar.notification.collection.coordinator + +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper.RunWithLooper +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder +import com.android.systemui.statusbar.notification.collection.NotifPipeline +import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder +import com.android.systemui.statusbar.notification.collection.listbuilder.OnAfterRenderEntryListener +import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeFinalizeFilterListener +import com.android.systemui.statusbar.notification.collection.render.NotifRowController +import com.android.systemui.util.mockito.mock +import com.android.systemui.util.mockito.withArgCaptor +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito.verify +import org.mockito.Mockito.verifyNoMoreInteractions +import org.mockito.MockitoAnnotations.initMocks + +@SmallTest +@RunWith(AndroidTestingRunner::class) +@RunWithLooper +class RowAlertTimeCoordinatorTest : SysuiTestCase() { + private lateinit var coordinator: RowAlertTimeCoordinator + private lateinit var beforeFinalizeFilterListener: OnBeforeFinalizeFilterListener + private lateinit var afterRenderEntryListener: OnAfterRenderEntryListener + + @Mock private lateinit var pipeline: NotifPipeline + + @Before + fun setUp() { + initMocks(this) + coordinator = RowAlertTimeCoordinator() + coordinator.attach(pipeline) + beforeFinalizeFilterListener = withArgCaptor { + verify(pipeline).addOnBeforeFinalizeFilterListener(capture()) + } + afterRenderEntryListener = withArgCaptor { + verify(pipeline).addOnAfterRenderEntryListener(capture()) + } + } + + @Test + fun testSetLastAudiblyAlerted() { + val entry1 = NotificationEntryBuilder().setLastAudiblyAlertedMs(10).build() + val entry2 = NotificationEntryBuilder().setLastAudiblyAlertedMs(20).build() + val summary = NotificationEntryBuilder().setLastAudiblyAlertedMs(5).build() + val child1 = NotificationEntryBuilder().setLastAudiblyAlertedMs(0).build() + val child2 = NotificationEntryBuilder().setLastAudiblyAlertedMs(8).build() + val group = + GroupEntryBuilder() + .setKey("group") + .setSummary(summary) + .addChild(child1) + .addChild(child2) + .build() + + val entries = listOf(entry1, summary, child1, child2, entry2) + + beforeFinalizeFilterListener.onBeforeFinalizeFilter(listOf(entry1, group, entry2)) + val actualTimesSet = + entries.associateWith { + val rowController = mock<NotifRowController>() + afterRenderEntryListener.onAfterRenderEntry(it, rowController) + withArgCaptor<Long> { + verify(rowController).setLastAudibleMs(capture()) + verifyNoMoreInteractions(rowController) + } + } + val expectedTimesSet = + mapOf( + entry1 to 10L, + entry2 to 20L, + summary to 8L, + child1 to 0L, + child2 to 8L, + ) + assertThat(actualTimesSet).containsExactlyEntriesIn(expectedTimesSet) + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinatorTest.kt index fa669fc222f5..a66f8ce1a92c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinatorTest.kt @@ -76,7 +76,7 @@ class RowAppearanceCoordinatorTest : SysuiTestCase() { verify(pipeline).addOnAfterRenderEntryListener(capture()) } whenever(assistantFeedbackController.getFeedbackIcon(any())).thenReturn(FeedbackIcon(1, 2)) - entry1 = NotificationEntryBuilder().setSection(section1).setLastAudiblyAlertedMs(17).build() + entry1 = NotificationEntryBuilder().setSection(section1).build() entry2 = NotificationEntryBuilder().setSection(section2).build() } @@ -103,12 +103,6 @@ class RowAppearanceCoordinatorTest : SysuiTestCase() { } @Test - fun testSetLastAudiblyAlerted() { - afterRenderEntryListener.onAfterRenderEntry(entry1, controller1) - verify(controller1).setLastAudibleMs(eq(17.toLong())) - } - - @Test fun testSetFeedbackIcon() { afterRenderEntryListener.onAfterRenderEntry(entry1, controller1) verify(controller1).setFeedbackIcon(eq(FeedbackIcon(1, 2))) 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/statusbar/policy/SensitiveNotificationProtectionControllerFlagDisabledTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerFlagDisabledTest.kt index 759235655eca..933b5b519672 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerFlagDisabledTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerFlagDisabledTest.kt @@ -24,6 +24,7 @@ import android.testing.AndroidTestingRunner import androidx.test.filters.SmallTest import com.android.server.notification.Flags import com.android.systemui.SysuiTestCase +import com.android.systemui.log.logcatLogBuffer import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.settings.FakeGlobalSettings import com.android.systemui.util.time.FakeSystemClock @@ -38,6 +39,8 @@ import org.mockito.MockitoAnnotations @RunWith(AndroidTestingRunner::class) @DisableFlags(Flags.FLAG_SCREENSHARE_NOTIFICATION_HIDING) class SensitiveNotificationProtectionControllerFlagDisabledTest : SysuiTestCase() { + private val logger = SensitiveNotificationProtectionControllerLogger(logcatLogBuffer()) + @Mock private lateinit var handler: Handler @Mock private lateinit var activityManager: IActivityManager @Mock private lateinit var mediaProjectionManager: MediaProjectionManager @@ -54,7 +57,8 @@ class SensitiveNotificationProtectionControllerFlagDisabledTest : SysuiTestCase( mediaProjectionManager, activityManager, handler, - FakeExecutor(FakeSystemClock()) + FakeExecutor(FakeSystemClock()), + logger ) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt index a2af38f77f41..4b4e315f5533 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt @@ -34,6 +34,7 @@ import android.testing.TestableLooper.RunWithLooper import androidx.test.filters.SmallTest import com.android.server.notification.Flags import com.android.systemui.SysuiTestCase +import com.android.systemui.log.logcatLogBuffer import com.android.systemui.statusbar.RankingBuilder import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder @@ -63,6 +64,8 @@ import org.mockito.MockitoAnnotations @RunWithLooper @EnableFlags(Flags.FLAG_SCREENSHARE_NOTIFICATION_HIDING) class SensitiveNotificationProtectionControllerTest : SysuiTestCase() { + private val logger = SensitiveNotificationProtectionControllerLogger(logcatLogBuffer()) + @Mock private lateinit var activityManager: IActivityManager @Mock private lateinit var mediaProjectionManager: MediaProjectionManager @Mock private lateinit var mediaProjectionInfo: MediaProjectionInfo @@ -93,7 +96,8 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() { mediaProjectionManager, activityManager, mockExecutorHandler(executor), - executor + executor, + logger ) // Process pending work (getting global setting and list of exemptions) 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/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/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/communal/domain/interactor/CommunalInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt index f74cf71f9e7b..6ac702eb2446 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt @@ -62,9 +62,11 @@ suspend fun Kosmos.setCommunalAvailable(available: Boolean) { fakeFeatureFlagsClassic.set(Flags.COMMUNAL_SERVICE_ENABLED, available) if (available) { fakeUserRepository.asMainUser() - with(fakeKeyguardRepository) { - setIsEncryptedOrLockdown(false) - setKeyguardShowing(true) - } + } else { + fakeUserRepository.asDefaultUser() + } + with(fakeKeyguardRepository) { + setIsEncryptedOrLockdown(!available) + setKeyguardShowing(available) } } 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/domain/interactor/KeyguardBlueprintInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorKosmos.kt index d9a3192ce821..8b0bba1320e4 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorKosmos.kt @@ -29,5 +29,6 @@ val Kosmos.keyguardBlueprintInteractor by applicationScope = applicationCoroutineScope, context = applicationContext, splitShadeStateController = splitShadeStateController, + clockInteractor = keyguardClockInteractor, ) } 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/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/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt index 931a59d30d7b..3e9ae4d2e354 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt @@ -119,6 +119,13 @@ class FakeUserRepository @Inject constructor() : UserRepository { yield() } + /** Resets the current user to the default of [DEFAULT_SELECTED_USER_INFO]. */ + suspend fun asDefaultUser(): UserInfo { + setUserInfos(listOf(DEFAULT_SELECTED_USER_INFO)) + setSelectedUserInfo(DEFAULT_SELECTED_USER_INFO) + return DEFAULT_SELECTED_USER_INFO + } + /** Makes the current user [MAIN_USER]. */ suspend fun asMainUser(): UserInfo { setUserInfos(listOf(MAIN_USER)) 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/autofill/java/com/android/server/autofill/ui/InlineFillUi.java b/services/autofill/java/com/android/server/autofill/ui/InlineFillUi.java index c734680009c6..ffc80ee7d710 100644 --- a/services/autofill/java/com/android/server/autofill/ui/InlineFillUi.java +++ b/services/autofill/java/com/android/server/autofill/ui/InlineFillUi.java @@ -16,6 +16,8 @@ package com.android.server.autofill.ui; +import static android.service.autofill.FillResponse.FLAG_CREDENTIAL_MANAGER_RESPONSE; + import static com.android.server.autofill.Helper.sVerbose; import android.annotation.NonNull; @@ -24,6 +26,7 @@ import android.annotation.UserIdInt; import android.content.IntentSender; import android.service.autofill.Dataset; import android.service.autofill.FillResponse; +import android.service.autofill.Flags; import android.service.autofill.InlinePresentation; import android.text.TextUtils; import android.util.Pair; @@ -141,10 +144,12 @@ public final class InlineFillUi { return new InlineFillUi(inlineFillUiInfo, inlineAuthentication, maxInputLengthForAutofill); } else if (response.getDatasets() != null) { + boolean ignoreHostSpec = Flags.autofillCredmanIntegration() && ( + (response.getFlags() & FLAG_CREDENTIAL_MANAGER_RESPONSE) != 0); SparseArray<Pair<Dataset, InlineSuggestion>> inlineSuggestions = InlineSuggestionFactory.createInlineSuggestions(inlineFillUiInfo, InlineSuggestionInfo.SOURCE_AUTOFILL, response.getDatasets(), - uiCallback); + uiCallback, ignoreHostSpec); return new InlineFillUi(inlineFillUiInfo, inlineSuggestions, maxInputLengthForAutofill); } @@ -160,7 +165,8 @@ public final class InlineFillUi { @NonNull InlineSuggestionUiCallback uiCallback) { SparseArray<Pair<Dataset, InlineSuggestion>> inlineSuggestions = InlineSuggestionFactory.createInlineSuggestions(inlineFillUiInfo, - InlineSuggestionInfo.SOURCE_PLATFORM, datasets, uiCallback); + InlineSuggestionInfo.SOURCE_PLATFORM, datasets, + uiCallback, /* ignoreHostSpec= */ false); return new InlineFillUi(inlineFillUiInfo, inlineSuggestions); } @@ -254,7 +260,7 @@ public final class InlineFillUi { if (!TextUtils.isEmpty(mFilterText) && mFilterText.length() > mMaxInputLengthForAutofill) { if (sVerbose) { Slog.v(TAG, "Not showing inline suggestion when user entered more than " - + mMaxInputLengthForAutofill + " characters"); + + mMaxInputLengthForAutofill + " characters"); } return new InlineSuggestionsResponse(inlineSuggestions); } diff --git a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java index 52109ba44917..d3b950112f91 100644 --- a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java +++ b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java @@ -16,6 +16,7 @@ package com.android.server.autofill.ui; +import static android.service.autofill.FillResponse.FLAG_CREDENTIAL_MANAGER_RESPONSE; import static android.view.inputmethod.InlineSuggestionInfo.TYPE_SUGGESTION; import static com.android.server.autofill.Helper.sDebug; @@ -25,6 +26,7 @@ import android.annotation.Nullable; import android.content.IntentSender; import android.service.autofill.Dataset; import android.service.autofill.FillResponse; +import android.service.autofill.Flags; import android.service.autofill.InlinePresentation; import android.util.Pair; import android.util.Slog; @@ -47,11 +49,14 @@ final class InlineSuggestionFactory { @NonNull InlineFillUi.InlineSuggestionUiCallback uiCallback) { InlinePresentation inlineAuthentication = response.getInlinePresentation(); final int requestId = response.getRequestId(); + boolean ignoreHostSpec = Flags.autofillCredmanIntegration() && ( + (response.getFlags() & FLAG_CREDENTIAL_MANAGER_RESPONSE) != 0); return createInlineSuggestion(inlineFillUiInfo, InlineSuggestionInfo.SOURCE_AUTOFILL, InlineSuggestionInfo.TYPE_ACTION, () -> uiCallback.authenticate(requestId, AutofillManager.AUTHENTICATION_ID_DATASET_ID_UNDEFINED), - mergedInlinePresentation(inlineFillUiInfo.mInlineRequest, 0, inlineAuthentication), + mergedInlinePresentation(inlineFillUiInfo.mInlineRequest, 0, inlineAuthentication, + ignoreHostSpec), createInlineSuggestionTooltip(inlineFillUiInfo.mInlineRequest, inlineFillUiInfo, InlineSuggestionInfo.SOURCE_AUTOFILL, response.getInlineTooltipPresentation()), @@ -67,7 +72,7 @@ final class InlineSuggestionFactory { @NonNull InlineFillUi.InlineFillUiInfo inlineFillUiInfo, @NonNull @InlineSuggestionInfo.Source String suggestionSource, @NonNull List<Dataset> datasets, - @NonNull InlineFillUi.InlineSuggestionUiCallback uiCallback) { + @NonNull InlineFillUi.InlineSuggestionUiCallback uiCallback, boolean ignoreHostSpec) { if (sDebug) Slog.d(TAG, "createInlineSuggestions(source=" + suggestionSource + ") called"); final InlineSuggestionsRequest request = inlineFillUiInfo.mInlineRequest; @@ -107,7 +112,8 @@ final class InlineSuggestionFactory { InlineSuggestion inlineSuggestion = createInlineSuggestion( inlineFillUiInfo, suggestionSource, suggestionType, () -> uiCallback.autofill(dataset, index), - mergedInlinePresentation(request, datasetIndex, inlinePresentation), + mergedInlinePresentation(request, datasetIndex, inlinePresentation, + ignoreHostSpec), inlineSuggestionTooltip, uiCallback); response.append(datasetIndex, Pair.create(dataset, inlineSuggestion)); @@ -141,16 +147,18 @@ final class InlineSuggestionFactory { */ private static InlinePresentation mergedInlinePresentation( @NonNull InlineSuggestionsRequest request, - int index, @NonNull InlinePresentation inlinePresentation) { + int index, @NonNull InlinePresentation inlinePresentation, boolean ignoreHostSpec) { final List<InlinePresentationSpec> specs = request.getInlinePresentationSpecs(); if (specs.isEmpty()) { return inlinePresentation; } InlinePresentationSpec specFromHost = specs.get(Math.min(specs.size() - 1, index)); + InlinePresentationSpec specToUse = + ignoreHostSpec ? inlinePresentation.getInlinePresentationSpec() : specFromHost; InlinePresentationSpec mergedInlinePresentation = new InlinePresentationSpec.Builder( inlinePresentation.getInlinePresentationSpec().getMinSize(), inlinePresentation.getInlinePresentationSpec().getMaxSize()).setStyle( - specFromHost.getStyle()).build(); + specToUse.getStyle()).build(); return new InlinePresentation(inlinePresentation.getSlice(), mergedInlinePresentation, inlinePresentation.isPinned()); @@ -211,7 +219,7 @@ final class InlineSuggestionFactory { inlineFillUiInfo, tooltipInline, () -> { /* no operation */ }, uiCallback); final InlineSuggestionInfo tooltipInlineSuggestionInfo = new InlineSuggestionInfo( mergedSpec, suggestionSource, /* autofillHints */ null, TYPE_SUGGESTION, - /* pinned */ false, /* tooltip */ null); + /* pinned */ false, /* tooltip */ null); return new InlineSuggestion(tooltipInlineSuggestionInfo, tooltipContentProvider); } 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/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/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/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/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/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/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 7b18fb6a7c35..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; @@ -322,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; @@ -408,44 +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<>(); - - final DisplayManager.DisplayListener mDisplayListener = new DisplayManager.DisplayListener() { - @Override - public void onDisplayAdded(int displayId) { - - } - - @Override - public void onDisplayRemoved(int displayId) { - synchronized (mLoadedPointerIconsByDisplayAndType) { - mLoadedPointerIconsByDisplayAndType.remove(displayId); - mDisplayContexts.remove(displayId); - } - } - - @Override - public void onDisplayChanged(int displayId) { - synchronized (mLoadedPointerIconsByDisplayAndType) { - // The display density could have changed, so force all cached pointer icons to be - // reloaded for the display. - var iconsByType = mLoadedPointerIconsByDisplayAndType.get(displayId); - if (iconsByType == null) { - return; - } - iconsByType.clear(); - mDisplayContexts.remove(displayId); - } - mNative.reloadPointerIcons(); - } - }; - /** Point of injection for test dependencies. */ @VisibleForTesting static class Injector { @@ -504,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); @@ -613,14 +578,11 @@ public class InputManagerService extends IInputManager.Stub mWiredAccessoryCallbacks.systemReady(); } - Objects.requireNonNull( - mContext.getSystemService(DisplayManager.class)).registerDisplayListener( - mDisplayListener, mHandler); - mKeyboardLayoutManager.systemRunning(); mBatteryController.systemRunning(); mKeyboardBacklightController.systemRunning(); mKeyRemapper.systemRunning(); + mPointerIconCache.systemRunning(); } private void reloadDeviceAliases() { @@ -2374,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(); } @@ -2769,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. @@ -2796,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, @@ -3628,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/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..3f9e989a5bba 100644 --- a/services/core/java/com/android/server/pm/LauncherAppsService.java +++ b/services/core/java/com/android/server/pm/LauncherAppsService.java @@ -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..2b20bfd7a7c2 100644 --- a/services/core/java/com/android/server/pm/PackageArchiver.java +++ b/services/core/java/com/android/server/pm/PackageArchiver.java @@ -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/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 bf06c2aba405..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; } - return new WakeLockStats(uidWakeLockStats); + // 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.WakeLockData( + timer.getCountLocked(STATS_SINCE_CHARGED), + totalTimeLockHeldMs, + timer.isRunningLocked() ? timer.getCurrentDurationMsLocked(realtimeMs) : 0); } @Override @@ -1817,9 +1861,8 @@ public class BatteryStatsImpl extends BatteryStats { if (historyDirectory == null) { mCheckinFile = null; mStatsFile = null; - mHistory = new BatteryStatsHistory(mConstants.MAX_HISTORY_FILES, - mConstants.MAX_HISTORY_BUFFER, mStepDetailsCalculator, mClock, mMonotonicClock, - traceDelegate, eventLogger); + mHistory = new BatteryStatsHistory(mConstants.MAX_HISTORY_BUFFER, + mStepDetailsCalculator, mClock, mMonotonicClock, traceDelegate, eventLogger); } else { mCheckinFile = new AtomicFile(new File(historyDirectory, "batterystats-checkin.bin")); mStatsFile = new AtomicFile(new File(historyDirectory, "batterystats.bin")); @@ -10962,8 +11005,8 @@ public class BatteryStatsImpl extends BatteryStats { mStatsFile = null; mCheckinFile = null; mDailyFile = null; - mHistory = new BatteryStatsHistory(mConstants.MAX_HISTORY_FILES, - mConstants.MAX_HISTORY_BUFFER, mStepDetailsCalculator, mClock, mMonotonicClock); + mHistory = new BatteryStatsHistory(mConstants.MAX_HISTORY_BUFFER, + mStepDetailsCalculator, mClock, mMonotonicClock); } else { mStatsFile = new AtomicFile(new File(systemDir, "batterystats.bin")); mCheckinFile = new AtomicFile(new File(systemDir, "batterystats-checkin.bin")); 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/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/webkit/SystemImpl.java b/services/core/java/com/android/server/webkit/SystemImpl.java index 3b2e69a97889..c6e8eb8d3743 100644 --- a/services/core/java/com/android/server/webkit/SystemImpl.java +++ b/services/core/java/com/android/server/webkit/SystemImpl.java @@ -23,6 +23,7 @@ import android.app.AppGlobals; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; +import android.content.pm.PackageInstaller; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.UserInfo; @@ -225,6 +226,21 @@ public class SystemImpl implements SystemInterface { } @Override + public void installExistingPackageForAllUsers(Context context, String packageName) { + UserManager userManager = context.getSystemService(UserManager.class); + for (UserInfo userInfo : userManager.getUsers()) { + installPackageForUser(packageName, userInfo.id); + } + } + + private void installPackageForUser(String packageName, int userId) { + final Context context = AppGlobals.getInitialApplication(); + final Context contextAsUser = context.createContextAsUser(UserHandle.of(userId), 0); + final PackageInstaller installer = contextAsUser.getPackageManager().getPackageInstaller(); + installer.installExistingPackage(packageName, PackageManager.INSTALL_REASON_UNKNOWN, null); + } + + @Override public boolean systemIsDebuggable() { return Build.IS_DEBUGGABLE; } diff --git a/services/core/java/com/android/server/webkit/SystemInterface.java b/services/core/java/com/android/server/webkit/SystemInterface.java index 5ed2cfe4252d..ad32f623c80d 100644 --- a/services/core/java/com/android/server/webkit/SystemInterface.java +++ b/services/core/java/com/android/server/webkit/SystemInterface.java @@ -43,6 +43,7 @@ public interface SystemInterface { public void killPackageDependents(String packageName); public void enablePackageForAllUsers(Context context, String packageName, boolean enable); + public void installExistingPackageForAllUsers(Context context, String packageName); public boolean systemIsDebuggable(); public PackageInfo getPackageInfoForProvider(WebViewProviderInfo configInfo) diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl2.java b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl2.java index 27c80c43cd94..596de686089e 100644 --- a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl2.java +++ b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl2.java @@ -211,14 +211,16 @@ class WebViewUpdateServiceImpl2 implements WebViewUpdateServiceInterface { } if (repairNeeded) { - // We didn't find a valid WebView implementation. Try explicitly re-enabling the - // default package for all users in case it was disabled, even if we already did the - // one-time migration before. If this actually changes the state, we will see the - // PackageManager broadcast shortly and try again. + // We didn't find a valid WebView implementation. Try explicitly re-installing and + // re-enabling the default package for all users in case it was disabled, even if we + // already did the one-time migration before. If this actually changes the state, we + // will see the PackageManager broadcast shortly and try again. Slog.w( TAG, - "No provider available for all users, trying to enable " + "No provider available for all users, trying to install and enable " + mDefaultProvider.packageName); + mSystemInterface.installExistingPackageForAllUsers( + mContext, mDefaultProvider.packageName); mSystemInterface.enablePackageForAllUsers( mContext, mDefaultProvider.packageName, true); } 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/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/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/DevicePolicyCacheImpl.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java index e7855bc85061..c4e2dc802104 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java @@ -15,6 +15,10 @@ */ package com.android.server.devicepolicy; +import static android.app.admin.DevicePolicyManager.CONTENT_PROTECTION_DISABLED; +import static android.app.admin.DevicePolicyManager.ContentProtectionPolicy; + +import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.admin.DevicePolicyCache; import android.app.admin.DevicePolicyManager; @@ -70,10 +74,14 @@ public class DevicePolicyCacheImpl extends DevicePolicyCache { /** Maps to {@code ActiveAdmin.mAdminCanGrantSensorsPermissions}. */ private final AtomicBoolean mCanGrantSensorsPermissions = new AtomicBoolean(false); + @GuardedBy("mLock") + private final SparseIntArray mContentProtectionPolicy = new SparseIntArray(); + public void onUserRemoved(int userHandle) { synchronized (mLock) { mPasswordQuality.delete(userHandle); mPermissionPolicy.delete(userHandle); + mContentProtectionPolicy.delete(userHandle); } } @@ -143,6 +151,24 @@ public class DevicePolicyCacheImpl extends DevicePolicyCache { } @Override + public @ContentProtectionPolicy int getContentProtectionPolicy(@UserIdInt int userId) { + synchronized (mLock) { + return mContentProtectionPolicy.get(userId, CONTENT_PROTECTION_DISABLED); + } + } + + /** Update the content protection policy for the given user. */ + public void setContentProtectionPolicy(@UserIdInt int userId, @Nullable Integer value) { + synchronized (mLock) { + if (value == null) { + mContentProtectionPolicy.delete(userId); + } else { + mContentProtectionPolicy.put(userId, value); + } + } + } + + @Override public boolean canAdminGrantSensorsPermissions() { return mCanGrantSensorsPermissions.get(); } @@ -178,6 +204,7 @@ public class DevicePolicyCacheImpl extends DevicePolicyCache { pw.println("Screen capture disallowed users: " + mScreenCaptureDisallowedUsers); pw.println("Password quality: " + mPasswordQuality); pw.println("Permission policy: " + mPermissionPolicy); + pw.println("Content protection policy: " + mContentProtectionPolicy); pw.println("Admin can grant sensors permission: " + mCanGrantSensorsPermissions.get()); pw.print("Shortcuts overrides: "); pw.println(mLauncherShortcutOverrides); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 9c48f2991267..0f97f4a7cdc0 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -3633,6 +3633,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { userId == UserHandle.USER_SYSTEM ? UserHandle.USER_ALL : userId); updatePermissionPolicyCache(userId); updateAdminCanGrantSensorsPermissionCache(userId); + updateContentProtectionPolicyCache(userId); final List<PreferentialNetworkServiceConfig> preferentialNetworkServiceConfigs; synchronized (getLockObject()) { @@ -23534,6 +23535,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } + private void updateContentProtectionPolicyCache(@UserIdInt int userId) { + mPolicyCache.setContentProtectionPolicy( + userId, + mDevicePolicyEngine.getResolvedPolicy(PolicyDefinition.CONTENT_PROTECTION, userId)); + } + @Override public ManagedSubscriptionsPolicy getManagedSubscriptionsPolicy() { synchronized (getLockObject()) { 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/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java index 1247f900260a..71facab99fce 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java @@ -359,7 +359,7 @@ final class PolicyDefinition<V> { new NoArgsPolicyKey(DevicePolicyIdentifiers.CONTENT_PROTECTION_POLICY), new MostRecent<>(), POLICY_FLAG_LOCAL_ONLY_POLICY, - (Integer value, Context context, Integer userId, PolicyKey policyKey) -> true, + PolicyEnforcerCallbacks::setContentProtectionPolicy, new IntegerPolicySerializer()); private static final Map<String, PolicyDefinition<?>> POLICY_DEFINITIONS = new HashMap<>(); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java index 54242ab279b0..c108deaf33bc 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java @@ -18,6 +18,7 @@ package com.android.server.devicepolicy; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.UserIdInt; import android.app.AppGlobals; import android.app.admin.DevicePolicyCache; import android.app.admin.DevicePolicyManager; @@ -282,6 +283,21 @@ final class PolicyEnforcerCallbacks { return true; } + static boolean setContentProtectionPolicy( + @Nullable Integer value, + @NonNull Context context, + @UserIdInt Integer userId, + @NonNull PolicyKey policyKey) { + Binder.withCleanCallingIdentity( + () -> { + DevicePolicyCache cache = DevicePolicyCache.getInstance(); + if (cache instanceof DevicePolicyCacheImpl cacheImpl) { + cacheImpl.setContentProtectionPolicy(userId, value); + } + }); + return true; + } + private static void updateScreenCaptureDisabled() { BackgroundThread.getHandler().post(() -> { try { 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/RefreshRateSettingsUtilsTest.java b/services/tests/displayservicetests/src/com/android/server/display/RefreshRateSettingsUtilsTest.java index a8af98f7a332..8a6c2440a232 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/RefreshRateSettingsUtilsTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/RefreshRateSettingsUtilsTest.java @@ -16,6 +16,8 @@ package com.android.server.display; +import static android.hardware.display.DisplayManager.DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED; + import static com.android.internal.display.RefreshRateSettingsUtils.DEFAULT_REFRESH_RATE; import static org.junit.Assert.assertEquals; @@ -50,6 +52,8 @@ public class RefreshRateSettingsUtilsTest { private DisplayManager mDisplayManagerMock; @Mock private Display mDisplayMock; + @Mock + private Display mDisplayMock2; @Before public void setUp() { @@ -65,25 +69,54 @@ public class RefreshRateSettingsUtilsTest { new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600, /* refreshRate= */ 90) }; - when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(mDisplayMock); when(mDisplayMock.getSupportedModes()).thenReturn(modes); + + Display.Mode[] modes2 = new Display.Mode[]{ + new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600, + /* refreshRate= */ 70), + new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600, + /* refreshRate= */ 130), + new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600, + /* refreshRate= */ 80) + }; + when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY + 1)).thenReturn(mDisplayMock2); + when(mDisplayMock2.getSupportedModes()).thenReturn(modes2); + + when(mDisplayManagerMock.getDisplays(DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED)) + .thenReturn(new Display[]{ mDisplayMock, mDisplayMock2 }); } @Test public void testFindHighestRefreshRateForDefaultDisplay() { - when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(mDisplayMock); assertEquals(120, RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext), /* delta= */ 0); } @Test - public void testFindHighestRefreshRate_DisplayIsNull() { + public void testFindHighestRefreshRateForDefaultDisplay_DisplayIsNull() { when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(null); assertEquals(DEFAULT_REFRESH_RATE, RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext), /* delta= */ 0); } + + @Test + public void testFindHighestRefreshRateAmongAllDisplays() { + assertEquals(130, + RefreshRateSettingsUtils.findHighestRefreshRateAmongAllDisplays(mContext), + /* delta= */ 0); + } + + @Test + public void testFindHighestRefreshRateAmongAllDisplays_NoDisplays() { + when(mDisplayManagerMock.getDisplays(DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED)) + .thenReturn(new Display[0]); + assertEquals(DEFAULT_REFRESH_RATE, + RefreshRateSettingsUtils.findHighestRefreshRateAmongAllDisplays(mContext), + /* delta= */ 0); + + } } 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/media/mediarouterservicetest/src/com/android/server/media/AudioManagerRouteControllerTest.java b/services/tests/media/mediarouterservicetest/src/com/android/server/media/AudioManagerRouteControllerTest.java index 8f5d1253406e..a918be2292af 100644 --- a/services/tests/media/mediarouterservicetest/src/com/android/server/media/AudioManagerRouteControllerTest.java +++ b/services/tests/media/mediarouterservicetest/src/com/android/server/media/AudioManagerRouteControllerTest.java @@ -16,6 +16,8 @@ package com.android.server.media; +import static android.Manifest.permission.MODIFY_AUDIO_ROUTING; + import static com.android.server.media.AudioRoutingUtils.ATTRIBUTES_MEDIA; import static com.android.server.media.AudioRoutingUtils.getMediaAudioProductStrategy; @@ -31,6 +33,7 @@ import static org.mockito.Mockito.when; import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.Instrumentation; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothManager; import android.content.Context; @@ -48,6 +51,7 @@ import android.os.UserHandle; import androidx.test.platform.app.InstrumentationRegistry; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -85,6 +89,7 @@ public class AudioManagerRouteControllerTest { /* name= */ null, /* address= */ null); + private Instrumentation mInstrumentation; private AudioDeviceInfo mSelectedAudioDeviceInfo; private Set<AudioDeviceInfo> mAvailableAudioDeviceInfos; @Mock private AudioManager mMockAudioManager; @@ -96,10 +101,11 @@ public class AudioManagerRouteControllerTest { @Before public void setUp() { MockitoAnnotations.initMocks(this); - + mInstrumentation = InstrumentationRegistry.getInstrumentation(); + mInstrumentation.getUiAutomation().adoptShellPermissionIdentity(MODIFY_AUDIO_ROUTING); Resources mockResources = Mockito.mock(Resources.class); when(mockResources.getText(anyInt())).thenReturn(FAKE_ROUTE_NAME); - Context realContext = InstrumentationRegistry.getInstrumentation().getContext(); + Context realContext = mInstrumentation.getContext(); Context mockContext = Mockito.mock(Context.class); when(mockContext.getResources()).thenReturn(mockResources); // The bluetooth stack needs the application info, but we cannot use a spy because the @@ -135,6 +141,11 @@ public class AudioManagerRouteControllerTest { clearInvocations(mOnDeviceRouteChangedListener); } + @After + public void tearDown() { + mInstrumentation.getUiAutomation().dropShellPermissionIdentity(); + } + @Test public void getSelectedRoute_afterDevicesConnect_returnsRightSelectedRoute() { assertThat(mControllerUnderTest.getSelectedRoute().getType()) 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/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java index ae6984ef0a8d..374426ad67a1 100644 --- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java +++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java @@ -55,7 +55,6 @@ import org.junit.runner.RunWith; import java.io.File; import java.io.IOException; -import java.nio.file.Files; import java.util.List; @SmallTest @@ -70,11 +69,10 @@ public class BatteryUsageStatsProviderTest { private static final long MINUTE_IN_MS = 60 * 1000; private static final double PRECISION = 0.00001; - private File mHistoryDir; - @Rule(order = 1) public final BatteryUsageStatsRule mStatsRule = - new BatteryUsageStatsRule(12345, mHistoryDir) + new BatteryUsageStatsRule(12345) + .createTempDirectory() .setAveragePower(PowerProfile.POWER_FLASHLIGHT, 360.0) .setAveragePower(PowerProfile.POWER_AUDIO, 720.0); @@ -83,9 +81,6 @@ public class BatteryUsageStatsProviderTest { @Before public void setup() throws IOException { - mHistoryDir = Files.createTempDirectory("BatteryUsageStatsProviderTest").toFile(); - clearDirectory(mHistoryDir); - if (RavenwoodRule.isUnderRavenwood()) { mContext = mock(Context.class); SensorManager sensorManager = mock(SensorManager.class); @@ -95,17 +90,6 @@ public class BatteryUsageStatsProviderTest { } } - private void clearDirectory(File dir) { - if (dir.exists()) { - for (File child : dir.listFiles()) { - if (child.isDirectory()) { - clearDirectory(child); - } - child.delete(); - } - } - } - @Test public void test_getBatteryUsageStats() { BatteryStatsImpl batteryStats = prepareBatteryStats(); @@ -423,7 +407,7 @@ public class BatteryUsageStatsProviderTest { } PowerStatsStore powerStatsStore = new PowerStatsStore( - new File(mHistoryDir, "powerstatsstore"), + new File(mStatsRule.getHistoryDir(), "powerstatsstore"), mStatsRule.getHandler(), null); powerStatsStore.reset(); diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java index 7e8fa55020ab..296ad0e939de 100644 --- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java +++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java @@ -35,7 +35,6 @@ import android.os.Handler; import android.os.HandlerThread; import android.os.UidBatteryConsumer; import android.os.UserBatteryConsumer; -import android.platform.test.ravenwood.RavenwoodRule; import android.util.SparseArray; import androidx.test.InstrumentationRegistry; @@ -50,6 +49,8 @@ import org.junit.runners.model.Statement; import org.mockito.stubbing.Answer; import java.io.File; +import java.io.IOException; +import java.nio.file.Files; import java.util.Arrays; @SuppressWarnings("SynchronizeOnNonFinalField") @@ -62,7 +63,9 @@ public class BatteryUsageStatsRule implements TestRule { private final PowerProfile mPowerProfile; private final MockClock mMockClock = new MockClock(); - private final File mHistoryDir; + private String mTestName; + private boolean mCreateTempDirectory; + private File mHistoryDir; private MockBatteryStatsImpl mBatteryStats; private Handler mHandler; @@ -80,32 +83,30 @@ public class BatteryUsageStatsRule implements TestRule { private Throwable mThrowable; public BatteryUsageStatsRule() { - this(0, null); + this(0); } public BatteryUsageStatsRule(long currentTime) { - this(currentTime, null); - } - - public BatteryUsageStatsRule(long currentTime, File historyDir) { mHandler = mock(Handler.class); mPowerProfile = spy(new PowerProfile()); mMockClock.currentTime = currentTime; - mHistoryDir = historyDir; - - if (!RavenwoodRule.isUnderRavenwood()) { - lateInitBatteryStats(); - } - mCpusByPolicy.put(0, new int[]{0, 1, 2, 3}); mCpusByPolicy.put(4, new int[]{4, 5, 6, 7}); mFreqsByPolicy.put(0, new int[]{300000, 1000000, 2000000}); mFreqsByPolicy.put(4, new int[]{300000, 1000000, 2500000, 3000000}); } - private void lateInitBatteryStats() { + private void initBatteryStats() { if (mBatteryStats != null) return; + if (mCreateTempDirectory) { + try { + mHistoryDir = Files.createTempDirectory(mTestName).toFile(); + } catch (IOException e) { + throw new RuntimeException(e); + } + clearDirectory(); + } mBatteryStats = new MockBatteryStatsImpl(mMockClock, mHistoryDir, mHandler); mBatteryStats.setPowerProfile(mPowerProfile); mBatteryStats.setCpuScalingPolicies(new CpuScalingPolicies(mCpusByPolicy, mFreqsByPolicy)); @@ -138,6 +139,15 @@ public class BatteryUsageStatsRule implements TestRule { return mHandler; } + public File getHistoryDir() { + return mHistoryDir; + } + + public BatteryUsageStatsRule createTempDirectory() { + mCreateTempDirectory = true; + return this; + } + public BatteryUsageStatsRule setTestPowerProfile(@XmlRes int xmlId) { mPowerProfile.forceInitForTesting(InstrumentationRegistry.getContext(), xmlId); return this; @@ -269,6 +279,7 @@ public class BatteryUsageStatsRule implements TestRule { @Override public Statement apply(Statement base, Description description) { + mTestName = description.getClassName() + "#" + description.getMethodName(); return new Statement() { @Override public void evaluate() throws Throwable { @@ -280,7 +291,7 @@ public class BatteryUsageStatsRule implements TestRule { } private void before() { - lateInitBatteryStats(); + initBatteryStats(); HandlerThread bgThread = new HandlerThread("bg thread"); bgThread.setUncaughtExceptionHandler((thread, throwable)-> { mThrowable = throwable; @@ -324,6 +335,9 @@ public class BatteryUsageStatsRule implements TestRule { } public MockBatteryStatsImpl getBatteryStats() { + if (mBatteryStats == null) { + initBatteryStats(); + } return mBatteryStats; } @@ -397,4 +411,19 @@ public class BatteryUsageStatsRule implements TestRule { } return null; } + + public void clearDirectory() { + clearDirectory(mHistoryDir); + } + + private void clearDirectory(File dir) { + if (dir.exists()) { + for (File child : dir.listFiles()) { + if (child.isDirectory()) { + clearDirectory(child); + } + child.delete(); + } + } + } } diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsAggregatorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsAggregatorTest.java index af5b462e017d..2ea86a4527eb 100644 --- a/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsAggregatorTest.java +++ b/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsAggregatorTest.java @@ -58,7 +58,7 @@ public class PowerStatsAggregatorTest { @Before public void setup() throws ParseException { - mHistory = new BatteryStatsHistory(32, 1024, + mHistory = new BatteryStatsHistory(1024, mock(BatteryStatsHistory.HistoryStepDetailsCalculator.class), mClock, mMonotonicClock, mock(BatteryStatsHistory.TraceDelegate.class), null); 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/webkit/TestSystemImpl.java b/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java index 65662d6b30b8..2039f93b9c40 100644 --- a/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java +++ b/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java @@ -83,6 +83,13 @@ public class TestSystemImpl implements SystemInterface { } } + @Override + public void installExistingPackageForAllUsers(Context context, String packageName) { + for (int userId : mUsers) { + installPackageForUser(packageName, userId); + } + } + private void enablePackageForUser(String packageName, boolean enable, int userId) { Map<Integer, PackageInfo> userPackages = mPackages.get(packageName); if (userPackages == null) { @@ -93,6 +100,17 @@ public class TestSystemImpl implements SystemInterface { setPackageInfoForUser(userId, packageInfo); } + private void installPackageForUser(String packageName, int userId) { + Map<Integer, PackageInfo> userPackages = mPackages.get(packageName); + if (userPackages == null) { + return; + } + PackageInfo packageInfo = userPackages.get(userId); + packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_INSTALLED; + packageInfo.applicationInfo.privateFlags &= (~ApplicationInfo.PRIVATE_FLAG_HIDDEN); + setPackageInfoForUser(userId, packageInfo); + } + @Override public boolean systemIsDebuggable() { return mIsDebuggable; } diff --git a/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java b/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java index 5a06327fdde3..53c172a191b6 100644 --- a/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java @@ -1549,6 +1549,31 @@ public class WebViewUpdateServiceTest { Matchers.anyObject(), Mockito.eq(testPackage), Mockito.eq(true)); } + @Test + @RequiresFlagsEnabled("android.webkit.update_service_v2") + public void testDefaultWebViewPackageInstalling() { + String testPackage = "testDefault"; + WebViewProviderInfo[] packages = + new WebViewProviderInfo[] { + new WebViewProviderInfo( + testPackage, + "", + true /* default available */, + false /* fallback */, + null) + }; + setupWithPackages(packages); + mTestSystemImpl.setPackageInfo( + createPackageInfo( + testPackage, true /* enabled */, true /* valid */, false /* installed */)); + + // Check that the boot time logic tries to install the default package. + runWebViewBootPreparationOnMainSync(); + Mockito.verify(mTestSystemImpl) + .installExistingPackageForAllUsers( + Matchers.anyObject(), Mockito.eq(testPackage)); + } + private void testDefaultPackageChosen(PackageInfo packageInfo) { WebViewProviderInfo[] packages = new WebViewProviderInfo[] { 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/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() } } |