diff options
460 files changed, 6986 insertions, 3397 deletions
diff --git a/cmds/uiautomator/cmds/uiautomator/src/com/android/commands/uiautomator/DumpCommand.java b/cmds/uiautomator/cmds/uiautomator/src/com/android/commands/uiautomator/DumpCommand.java index 3b14be7327f7..24727c5f2448 100644 --- a/cmds/uiautomator/cmds/uiautomator/src/com/android/commands/uiautomator/DumpCommand.java +++ b/cmds/uiautomator/cmds/uiautomator/src/com/android/commands/uiautomator/DumpCommand.java @@ -107,7 +107,7 @@ public class DumpCommand extends Command { DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY); int rotation = display.getRotation(); Point size = new Point(); - display.getSize(size); + display.getRealSize(size); AccessibilityNodeInfoDumper.dumpWindowToFile(info, dumpFile, rotation, size.x, size.y); } diff --git a/cmds/uiautomator/library/core-src/com/android/uiautomator/core/AccessibilityNodeInfoDumper.java b/cmds/uiautomator/library/core-src/com/android/uiautomator/core/AccessibilityNodeInfoDumper.java index ab198b319e27..488292d68620 100644 --- a/cmds/uiautomator/library/core-src/com/android/uiautomator/core/AccessibilityNodeInfoDumper.java +++ b/cmds/uiautomator/library/core-src/com/android/uiautomator/core/AccessibilityNodeInfoDumper.java @@ -139,7 +139,7 @@ public class AccessibilityNodeInfoDumper { serializer.attribute("", "id", Integer.toString(displayId)); int rotation = display.getRotation(); Point size = new Point(); - display.getSize(size); + display.getRealSize(size); for (int i = 0, n = windows.size(); i < n; ++i) { dumpWindowRec(windows.get(i), serializer, i, size.x, size.y, rotation); } diff --git a/cmds/uiautomator/library/core-src/com/android/uiautomator/core/UiDevice.java b/cmds/uiautomator/library/core-src/com/android/uiautomator/core/UiDevice.java index 6fd2bf250e2c..1bcd343e5668 100644 --- a/cmds/uiautomator/library/core-src/com/android/uiautomator/core/UiDevice.java +++ b/cmds/uiautomator/library/core-src/com/android/uiautomator/core/UiDevice.java @@ -767,7 +767,7 @@ public class UiDevice { if(root != null) { Display display = getAutomatorBridge().getDefaultDisplay(); Point size = new Point(); - display.getSize(size); + display.getRealSize(size); AccessibilityNodeInfoDumper.dumpWindowToFile(root, new File(new File(Environment.getDataDirectory(), "local/tmp"), fileName), display.getRotation(), size.x, size.y); diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 449729e18376..48df9e66be70 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -3933,6 +3933,9 @@ public class ActivityManager { * processes to reclaim memory; the system will take care of restarting * these processes in the future as needed. * + * <p class="note">Third party applications can only use this API to kill their own processes. + * </p> + * * @param packageName The name of the package whose processes are to * be killed. */ diff --git a/core/java/android/content/AttributionSource.java b/core/java/android/content/AttributionSource.java index 3f2fa2188d24..16b18c85e790 100644 --- a/core/java/android/content/AttributionSource.java +++ b/core/java/android/content/AttributionSource.java @@ -31,6 +31,7 @@ import android.os.Parcelable; import android.os.Process; import android.permission.PermissionManager; import android.util.ArraySet; +import android.util.Log; import com.android.internal.annotations.Immutable; @@ -87,6 +88,8 @@ import java.util.Set; */ @Immutable public final class AttributionSource implements Parcelable { + private static final String TAG = "AttributionSource"; + private static final String DESCRIPTOR = "android.content.AttributionSource"; private static final Binder sDefaultToken = new Binder(DESCRIPTOR); @@ -154,9 +157,20 @@ public final class AttributionSource implements Parcelable { AttributionSource(@NonNull Parcel in) { this(AttributionSourceState.CREATOR.createFromParcel(in)); - // Since we just unpacked this object as part of it transiting a Binder - // call, this is the perfect time to enforce that its UID and PID can be trusted - enforceCallingUidAndPid(); + if (!Binder.isDirectlyHandlingTransaction()) { + Log.e(TAG, "Unable to verify calling UID #" + mAttributionSourceState.uid + " PID #" + + mAttributionSourceState.pid + " when not handling Binder transaction; " + + "clearing."); + mAttributionSourceState.pid = -1; + mAttributionSourceState.uid = -1; + mAttributionSourceState.packageName = null; + mAttributionSourceState.attributionTag = null; + mAttributionSourceState.next = null; + } else { + // Since we just unpacked this object as part of it transiting a Binder + // call, this is the perfect time to enforce that its UID and PID can be trusted + enforceCallingUidAndPid(); + } } /** @hide */ diff --git a/core/java/android/service/quicksettings/TileService.java b/core/java/android/service/quicksettings/TileService.java index 506b3b81eb9a..81c5796374af 100644 --- a/core/java/android/service/quicksettings/TileService.java +++ b/core/java/android/service/quicksettings/TileService.java @@ -506,7 +506,7 @@ public class TileService extends Service { * the calling package or if the calling user cannot act on behalf of the user from the * {@code context}.</li> * <li> {@link IllegalArgumentException} if the user of the {@code context} is not the - * current user.</li> + * current user. Only thrown for apps targeting {@link Build.VERSION_CODES#TIRAMISU}</li> * </ul> */ public static final void requestListeningState(Context context, ComponentName component) { diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java index d53ad17f07ef..e27af17ebc3d 100644 --- a/core/java/android/service/wallpaper/WallpaperService.java +++ b/core/java/android/service/wallpaper/WallpaperService.java @@ -61,7 +61,6 @@ import android.hardware.display.DisplayManager.DisplayListener; import android.os.Build; import android.os.Bundle; import android.os.Handler; -import android.os.HandlerThread; import android.os.IBinder; import android.os.Looper; import android.os.Message; @@ -181,9 +180,6 @@ public abstract class WallpaperService extends Service { private final ArrayList<Engine> mActiveEngines = new ArrayList<Engine>(); - private Handler mBackgroundHandler; - private HandlerThread mBackgroundThread; - static final class WallpaperCommand { String action; int x; @@ -202,6 +198,14 @@ public abstract class WallpaperService extends Service { */ public class Engine { IWallpaperEngineWrapper mIWallpaperEngine; + final ArraySet<RectF> mLocalColorAreas = new ArraySet<>(4); + final ArraySet<RectF> mLocalColorsToAdd = new ArraySet<>(4); + + // 2D matrix [x][y] to represent a page of a portion of a window + EngineWindowPage[] mWindowPages = new EngineWindowPage[0]; + Bitmap mLastScreenshot; + int mLastWindowPage = -1; + private boolean mResetWindowPages; // Copies from mIWallpaperEngine. HandlerCaller mCaller; @@ -263,27 +267,11 @@ public abstract class WallpaperService extends Service { final Object mLock = new Object(); boolean mOffsetMessageEnqueued; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) float mPendingXOffset; float mPendingYOffset; float mPendingXOffsetStep; float mPendingYOffsetStep; - - /** - * local color extraction related fields - * to be used by the background thread only (except the atomic boolean) - */ - final ArraySet<RectF> mLocalColorAreas = new ArraySet<>(4); - final ArraySet<RectF> mLocalColorsToAdd = new ArraySet<>(4); - private long mLastProcessLocalColorsTimestamp; - private AtomicBoolean mProcessLocalColorsPending = new AtomicBoolean(false); - private int mPixelCopyCount = 0; - // 2D matrix [x][y] to represent a page of a portion of a window - EngineWindowPage[] mWindowPages = new EngineWindowPage[0]; - Bitmap mLastScreenshot; - private boolean mResetWindowPages; - boolean mPendingSync; MotionEvent mPendingMove; boolean mIsInAmbientMode; @@ -292,8 +280,12 @@ public abstract class WallpaperService extends Service { private long mLastColorInvalidation; private final Runnable mNotifyColorsChanged = this::notifyColorsChanged; + // used to throttle processLocalColors + private long mLastProcessLocalColorsTimestamp; + private AtomicBoolean mProcessLocalColorsPending = new AtomicBoolean(false); private final Supplier<Long> mClockFunction; private final Handler mHandler; + private Display mDisplay; private Context mDisplayContext; private int mDisplayState; @@ -833,7 +825,7 @@ public abstract class WallpaperService extends Service { + "was not established."); } mResetWindowPages = true; - processLocalColors(); + processLocalColors(mPendingXOffset, mPendingXOffsetStep); } catch (RemoteException e) { Log.w(TAG, "Can't notify system because wallpaper connection was lost.", e); } @@ -1372,7 +1364,7 @@ public abstract class WallpaperService extends Service { resetWindowPages(); mSession.finishDrawing(mWindow, null /* postDrawTransaction */, Integer.MAX_VALUE); - processLocalColors(); + processLocalColors(mPendingXOffset, mPendingXOffsetStep); } reposition(); reportEngineShown(shouldWaitForEngineShown()); @@ -1517,7 +1509,7 @@ public abstract class WallpaperService extends Service { if (!mDestroyed) { mVisible = visible; reportVisibility(); - if (mReportedVisible) processLocalColors(); + if (mReportedVisible) processLocalColors(mPendingXOffset, mPendingXOffsetStep); } else { AnimationHandler.requestAnimatorsEnabled(visible, this); } @@ -1601,41 +1593,31 @@ public abstract class WallpaperService extends Service { } // setup local color extraction data - processLocalColors(); + processLocalColors(xOffset, xOffsetStep); } /** * Thread-safe util to call {@link #processLocalColorsInternal} with a minimum interval of * {@link #PROCESS_LOCAL_COLORS_INTERVAL_MS} between two calls. */ - private void processLocalColors() { + private void processLocalColors(float xOffset, float xOffsetStep) { if (mProcessLocalColorsPending.compareAndSet(false, true)) { final long now = mClockFunction.get(); final long timeSinceLastColorProcess = now - mLastProcessLocalColorsTimestamp; final long timeToWait = Math.max(0, PROCESS_LOCAL_COLORS_INTERVAL_MS - timeSinceLastColorProcess); - mBackgroundHandler.postDelayed(() -> { + mHandler.postDelayed(() -> { mLastProcessLocalColorsTimestamp = now + timeToWait; mProcessLocalColorsPending.set(false); - processLocalColorsInternal(); + processLocalColorsInternal(xOffset, xOffsetStep); }, timeToWait); } } - private void processLocalColorsInternal() { + private void processLocalColorsInternal(float xOffset, float xOffsetStep) { // implemented by the wallpaper if (supportsLocalColorExtraction()) return; - assertBackgroundThread(); - float xOffset; - float xOffsetStep; - float wallpaperDimAmount; - synchronized (mLock) { - xOffset = mPendingXOffset; - xOffsetStep = mPendingXOffsetStep; - wallpaperDimAmount = mWallpaperDimAmount; - } - if (DEBUG) { Log.d(TAG, "processLocalColors " + xOffset + " of step " + xOffsetStep); @@ -1698,7 +1680,7 @@ public abstract class WallpaperService extends Service { xPage = mWindowPages.length - 1; } current = mWindowPages[xPage]; - updatePage(current, xPage, xPages, wallpaperDimAmount); + updatePage(current, xPage, xPages, finalXOffsetStep); Trace.endSection(); } @@ -1718,23 +1700,16 @@ public abstract class WallpaperService extends Service { } } - /** - * Must be called with the surface lock held. - * Must not be called if the surface is not valid. - * Will unlock the surface when done using it. - */ void updatePage(EngineWindowPage currentPage, int pageIndx, int numPages, - float wallpaperDimAmount) { - - assertBackgroundThread(); - + float xOffsetStep) { // in case the clock is zero, we start with negative time long current = SystemClock.elapsedRealtime() - DEFAULT_UPDATE_SCREENSHOT_DURATION; long lapsed = current - currentPage.getLastUpdateTime(); // Always update the page when the last update time is <= 0 // This is important especially when the device first boots - if (lapsed < DEFAULT_UPDATE_SCREENSHOT_DURATION) return; - + if (lapsed < DEFAULT_UPDATE_SCREENSHOT_DURATION) { + return; + } Surface surface = mSurfaceHolder.getSurface(); if (!surface.isValid()) return; boolean widthIsLarger = mSurfaceSize.x > mSurfaceSize.y; @@ -1750,42 +1725,33 @@ public abstract class WallpaperService extends Service { Bitmap screenShot = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); final Bitmap finalScreenShot = screenShot; - final String pixelCopySectionName = "WallpaperService#pixelCopy"; - final int pixelCopyCount = mPixelCopyCount++; - Trace.beginAsyncSection(pixelCopySectionName, pixelCopyCount); - try { - PixelCopy.request(surface, screenShot, (res) -> { - Trace.endAsyncSection(pixelCopySectionName, pixelCopyCount); - if (DEBUG) Log.d(TAG, "result of pixel copy is " + res); - if (res != PixelCopy.SUCCESS) { - Bitmap lastBitmap = currentPage.getBitmap(); - // assign the last bitmap taken for now - currentPage.setBitmap(mLastScreenshot); - Bitmap lastScreenshot = mLastScreenshot; - if (lastScreenshot != null && !lastScreenshot.isRecycled() - && !Objects.equals(lastBitmap, lastScreenshot)) { - updatePageColors(currentPage, pageIndx, numPages, wallpaperDimAmount); - } - } else { - mLastScreenshot = finalScreenShot; - // going to hold this lock for a while - currentPage.setBitmap(finalScreenShot); - currentPage.setLastUpdateTime(current); - updatePageColors(currentPage, pageIndx, numPages, wallpaperDimAmount); + Trace.beginSection("WallpaperService#pixelCopy"); + PixelCopy.request(surface, screenShot, (res) -> { + Trace.endSection(); + if (DEBUG) Log.d(TAG, "result of pixel copy is " + res); + if (res != PixelCopy.SUCCESS) { + Bitmap lastBitmap = currentPage.getBitmap(); + // assign the last bitmap taken for now + currentPage.setBitmap(mLastScreenshot); + Bitmap lastScreenshot = mLastScreenshot; + if (lastScreenshot != null && !lastScreenshot.isRecycled() + && !Objects.equals(lastBitmap, lastScreenshot)) { + updatePageColors(currentPage, pageIndx, numPages, xOffsetStep); } - }, mBackgroundHandler); - } catch (IllegalArgumentException e) { - // this can potentially happen if the surface is invalidated right between the - // surface.isValid() check and the PixelCopy operation. - // in this case, stop: we'll compute colors on the next processLocalColors call. - Log.i(TAG, "Cancelling processLocalColors: exception caught during PixelCopy"); - } + } else { + mLastScreenshot = finalScreenShot; + // going to hold this lock for a while + currentPage.setBitmap(finalScreenShot); + currentPage.setLastUpdateTime(current); + updatePageColors(currentPage, pageIndx, numPages, xOffsetStep); + } + }, mHandler); + } // locked by the passed page - private void updatePageColors( - EngineWindowPage page, int pageIndx, int numPages, float wallpaperDimAmount) { + private void updatePageColors(EngineWindowPage page, int pageIndx, int numPages, + float xOffsetStep) { if (page.getBitmap() == null) return; - assertBackgroundThread(); Trace.beginSection("WallpaperService#updatePageColors"); if (DEBUG) { Log.d(TAG, "updatePageColorsLocked for page " + pageIndx + " with areas " @@ -1807,7 +1773,7 @@ public abstract class WallpaperService extends Service { Log.e(TAG, "Error creating page local color bitmap", e); continue; } - WallpaperColors color = WallpaperColors.fromBitmap(target, wallpaperDimAmount); + WallpaperColors color = WallpaperColors.fromBitmap(target, mWallpaperDimAmount); target.recycle(); WallpaperColors currentColor = page.getColors(area); @@ -1824,26 +1790,17 @@ public abstract class WallpaperService extends Service { + " local color callback for area" + area + " for page " + pageIndx + " of " + numPages); } - mHandler.post(() -> { - try { - mConnection.onLocalWallpaperColorsChanged(area, color, - mDisplayContext.getDisplayId()); - } catch (RemoteException e) { - Log.e(TAG, "Error calling Connection.onLocalWallpaperColorsChanged", e); - } - }); + try { + mConnection.onLocalWallpaperColorsChanged(area, color, + mDisplayContext.getDisplayId()); + } catch (RemoteException e) { + Log.e(TAG, "Error calling Connection.onLocalWallpaperColorsChanged", e); + } } } Trace.endSection(); } - private void assertBackgroundThread() { - if (!mBackgroundHandler.getLooper().isCurrentThread()) { - throw new IllegalStateException( - "ProcessLocalColors should be called from the background thread"); - } - } - private RectF generateSubRect(RectF in, int pageInx, int numPages) { float minLeft = (float) (pageInx) / (float) (numPages); float maxRight = (float) (pageInx + 1) / (float) (numPages); @@ -1868,6 +1825,7 @@ public abstract class WallpaperService extends Service { if (supportsLocalColorExtraction()) return; if (!mResetWindowPages) return; mResetWindowPages = false; + mLastWindowPage = -1; for (int i = 0; i < mWindowPages.length; i++) { mWindowPages[i].setLastUpdateTime(0L); } @@ -1893,10 +1851,12 @@ public abstract class WallpaperService extends Service { if (DEBUG) { Log.d(TAG, "addLocalColorsAreas adding local color areas " + regions); } - mBackgroundHandler.post(() -> { + mHandler.post(() -> { mLocalColorsToAdd.addAll(regions); - processLocalColors(); + processLocalColors(mPendingXOffset, mPendingYOffset); }); + + } /** @@ -1906,7 +1866,7 @@ public abstract class WallpaperService extends Service { */ public void removeLocalColorsAreas(@NonNull List<RectF> regions) { if (supportsLocalColorExtraction()) return; - mBackgroundHandler.post(() -> { + mHandler.post(() -> { float step = mPendingXOffsetStep; mLocalColorsToAdd.removeAll(regions); mLocalColorAreas.removeAll(regions); @@ -2537,9 +2497,6 @@ public abstract class WallpaperService extends Service { @Override public void onCreate() { Trace.beginSection("WPMS.onCreate"); - mBackgroundThread = new HandlerThread("DefaultWallpaperLocalColorExtractor"); - mBackgroundThread.start(); - mBackgroundHandler = new Handler(mBackgroundThread.getLooper()); super.onCreate(); Trace.endSection(); } @@ -2552,7 +2509,6 @@ public abstract class WallpaperService extends Service { mActiveEngines.get(i).detach(); } mActiveEngines.clear(); - mBackgroundThread.quitSafely(); Trace.endSection(); } diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java index 02027e4a3969..293f9082670d 100644 --- a/core/java/android/view/Window.java +++ b/core/java/android/view/Window.java @@ -823,6 +823,11 @@ public abstract class Window { /** @hide */ public final void destroy() { mDestroyed = true; + onDestroy(); + } + + /** @hide */ + protected void onDestroy() { } /** @hide */ diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index 011232fe1915..cef5120bc0b7 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -21,6 +21,7 @@ import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CANT import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CANT_SHARE_WITH_PERSONAL; import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CANT_SHARE_WITH_WORK; import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CROSS_PROFILE_BLOCKED_TITLE; +import static android.content.ContentProvider.getUserIdFromUri; import static android.stats.devicepolicy.DevicePolicyEnums.RESOLVER_EMPTY_STATE_NO_SHARING_TO_PERSONAL; import static android.stats.devicepolicy.DevicePolicyEnums.RESOLVER_EMPTY_STATE_NO_SHARING_TO_WORK; @@ -161,6 +162,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; import java.util.function.Supplier; +import java.util.stream.Collectors; /** * The Chooser Activity handles intent resolution specifically for sharing intents - @@ -1424,7 +1426,11 @@ public class ChooserActivity extends ResolverActivity implements String action = targetIntent.getAction(); if (Intent.ACTION_SEND.equals(action)) { - Uri uri = targetIntent.getParcelableExtra(Intent.EXTRA_STREAM); + Uri uri = targetIntent.getParcelableExtra(Intent.EXTRA_STREAM, android.net.Uri.class); + if (!validForContentPreview(uri)) { + contentPreviewLayout.setVisibility(View.GONE); + return contentPreviewLayout; + } imagePreview.findViewById(R.id.content_preview_image_1_large) .setTransitionName(ChooserActivity.FIRST_IMAGE_PREVIEW_TRANSITION_NAME); mPreviewCoord.loadUriIntoView(R.id.content_preview_image_1_large, uri, 0); @@ -1434,7 +1440,7 @@ public class ChooserActivity extends ResolverActivity implements List<Uri> uris = targetIntent.getParcelableArrayListExtra(Intent.EXTRA_STREAM); List<Uri> imageUris = new ArrayList<>(); for (Uri uri : uris) { - if (isImageType(resolver.getType(uri))) { + if (validForContentPreview(uri) && isImageType(resolver.getType(uri))) { imageUris.add(uri); } } @@ -1544,9 +1550,16 @@ public class ChooserActivity extends ResolverActivity implements String action = targetIntent.getAction(); if (Intent.ACTION_SEND.equals(action)) { Uri uri = targetIntent.getParcelableExtra(Intent.EXTRA_STREAM); + if (!validForContentPreview(uri)) { + contentPreviewLayout.setVisibility(View.GONE); + return contentPreviewLayout; + } loadFileUriIntoView(uri, contentPreviewLayout); } else { List<Uri> uris = targetIntent.getParcelableArrayListExtra(Intent.EXTRA_STREAM); + uris = uris.stream() + .filter(ChooserActivity::validForContentPreview) + .collect(Collectors.toList()); int uriCount = uris.size(); if (uriCount == 0) { @@ -1605,6 +1618,24 @@ public class ChooserActivity extends ResolverActivity implements } } + /** + * Indicate if the incoming content URI should be allowed. + * + * @param uri the uri to test + * @return true if the URI is allowed for content preview + */ + private static boolean validForContentPreview(Uri uri) throws SecurityException { + if (uri == null) { + return false; + } + int userId = getUserIdFromUri(uri, UserHandle.USER_CURRENT); + if (userId != UserHandle.USER_CURRENT && userId != UserHandle.myUserId()) { + Log.e(TAG, "dropped invalid content URI belonging to user " + userId); + return false; + } + return true; + } + @VisibleForTesting protected boolean isImageType(String mimeType) { return mimeType != null && mimeType.startsWith("image/"); diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java index d8afe50d3af3..e7217def7689 100644 --- a/core/java/com/android/internal/jank/InteractionJankMonitor.java +++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java @@ -33,6 +33,7 @@ import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_IN import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_OPEN_ALL_APPS; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_QUICK_SWITCH; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_UNLOCK_ENTRANCE_ANIMATION; +import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_CLOCK_MOVE_ANIMATION; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_LAUNCH_CAMERA; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_OCCLUSION; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_PASSWORD_APPEAR; @@ -231,6 +232,7 @@ public class InteractionJankMonitor { public static final int CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS = 66; public static final int CUJ_LAUNCHER_CLOSE_ALL_APPS_SWIPE = 67; public static final int CUJ_LAUNCHER_CLOSE_ALL_APPS_TO_HOME = 68; + public static final int CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION = 70; private static final int NO_STATSD_LOGGING = -1; @@ -308,6 +310,8 @@ public class InteractionJankMonitor { UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_SWIPE_TO_RECENTS, UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_CLOSE_ALL_APPS_SWIPE, UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_CLOSE_ALL_APPS_TO_HOME, + NO_STATSD_LOGGING, + UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_CLOCK_MOVE_ANIMATION, }; private static volatile InteractionJankMonitor sInstance; @@ -396,7 +400,8 @@ public class InteractionJankMonitor { CUJ_RECENTS_SCROLLING, CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS, CUJ_LAUNCHER_CLOSE_ALL_APPS_SWIPE, - CUJ_LAUNCHER_CLOSE_ALL_APPS_TO_HOME + CUJ_LAUNCHER_CLOSE_ALL_APPS_TO_HOME, + CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION }) @Retention(RetentionPolicy.SOURCE) public @interface CujType { @@ -917,6 +922,8 @@ public class InteractionJankMonitor { return "LAUNCHER_CLOSE_ALL_APPS_SWIPE"; case CUJ_LAUNCHER_CLOSE_ALL_APPS_TO_HOME: return "LAUNCHER_CLOSE_ALL_APPS_TO_HOME"; + case CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION: + return "LOCKSCREEN_CLOCK_MOVE_ANIMATION"; } return "UNKNOWN"; } diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 3a0e09d1fc77..6fed26c4a81d 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -81,7 +81,6 @@ import android.telephony.ServiceState.RegState; import android.telephony.SignalStrength; import android.telephony.TelephonyManager; import android.text.TextUtils; -import android.text.format.DateUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.AtomicFile; @@ -202,7 +201,6 @@ public class BatteryStatsImpl extends BatteryStats { public static final int RESET_REASON_ADB_COMMAND = 2; public static final int RESET_REASON_FULL_CHARGE = 3; public static final int RESET_REASON_MEASURED_ENERGY_BUCKETS_CHANGE = 4; - public static final int RESET_REASON_PLUGGED_IN_FOR_LONG_DURATION = 5; protected Clock mClock; @@ -389,89 +387,6 @@ public class BatteryStatsImpl extends BatteryStats { } } - /** Provide BatteryStatsImpl configuration choices */ - public static class BatteryStatsConfig { - static final int RESET_ON_UNPLUG_HIGH_BATTERY_LEVEL_FLAG = 1 << 0; - static final int RESET_ON_UNPLUG_AFTER_SIGNIFICANT_CHARGE_FLAG = 1 << 1; - - private final int mFlags; - - private BatteryStatsConfig(Builder builder) { - int flags = 0; - if (builder.mResetOnUnplugHighBatteryLevel) { - flags |= RESET_ON_UNPLUG_HIGH_BATTERY_LEVEL_FLAG; - } - if (builder.mResetOnUnplugAfterSignificantCharge) { - flags |= RESET_ON_UNPLUG_AFTER_SIGNIFICANT_CHARGE_FLAG; - } - mFlags = flags; - } - - /** - * Returns whether a BatteryStats reset should occur on unplug when the battery level is - * high. - */ - boolean shouldResetOnUnplugHighBatteryLevel() { - return (mFlags & RESET_ON_UNPLUG_HIGH_BATTERY_LEVEL_FLAG) - == RESET_ON_UNPLUG_HIGH_BATTERY_LEVEL_FLAG; - } - - /** - * Returns whether a BatteryStats reset should occur on unplug if the battery charge a - * significant amount since it has been plugged in. - */ - boolean shouldResetOnUnplugAfterSignificantCharge() { - return (mFlags & RESET_ON_UNPLUG_AFTER_SIGNIFICANT_CHARGE_FLAG) - == RESET_ON_UNPLUG_AFTER_SIGNIFICANT_CHARGE_FLAG; - } - - /** - * Builder for BatteryStatsConfig - */ - public static class Builder { - private boolean mResetOnUnplugHighBatteryLevel; - private boolean mResetOnUnplugAfterSignificantCharge; - public Builder() { - mResetOnUnplugHighBatteryLevel = true; - mResetOnUnplugAfterSignificantCharge = true; - } - - /** - * Build the BatteryStatsConfig. - */ - public BatteryStatsConfig build() { - return new BatteryStatsConfig(this); - } - - /** - * Set whether a BatteryStats reset should occur on unplug when the battery level is - * high. - */ - public Builder setResetOnUnplugHighBatteryLevel(boolean reset) { - mResetOnUnplugHighBatteryLevel = reset; - return this; - } - - /** - * Set whether a BatteryStats reset should occur on unplug if the battery charge a - * significant amount since it has been plugged in. - */ - public Builder setResetOnUnplugAfterSignificantCharge(boolean reset) { - mResetOnUnplugAfterSignificantCharge = reset; - return this; - } - } - - } - - /** Handles calls to AlarmManager */ - public interface AlarmInterface { - /** Schedule an RTC alarm */ - void schedule(long rtcTimeMs, long windowLengthMs); - /** Cancel the previously scheduled alarm */ - void cancel(); - } - private final PlatformIdleStateCallback mPlatformIdleStateCallback; private final Runnable mDeferSetCharging = new Runnable() { @@ -802,7 +717,6 @@ public class BatteryStatsImpl extends BatteryStats { protected boolean mHaveBatteryLevel = false; protected boolean mRecordingHistory = false; int mNumHistoryItems; - private long mBatteryPluggedInRealTimeMs = 0; private static final int HISTORY_TAG_INDEX_LIMIT = 0x7ffe; private static final int MAX_HISTORY_TAG_STRING_LENGTH = 1024; @@ -1545,13 +1459,6 @@ public class BatteryStatsImpl extends BatteryStats { @GuardedBy("this") protected final Constants mConstants; - @VisibleForTesting - @GuardedBy("this") - protected BatteryStatsConfig mBatteryStatsConfig = new BatteryStatsConfig.Builder().build(); - - @VisibleForTesting - protected AlarmInterface mLongPlugInAlarmInterface = null; - /* * Holds a SamplingTimer associated with each Resource Power Manager state and voter, * recording their times when on-battery (regardless of screen state). @@ -1718,13 +1625,12 @@ public class BatteryStatsImpl extends BatteryStats { public BatteryStatsImpl(Clock clock, File historyDirectory) { init(clock); mStartClockTimeMs = clock.currentTimeMillis(); + mCheckinFile = null; mDailyFile = null; if (historyDirectory == null) { - mCheckinFile = null; mStatsFile = null; mBatteryStatsHistory = new BatteryStatsHistory(mHistoryBuffer); } else { - mCheckinFile = new AtomicFile(new File(historyDirectory, "batterystats-checkin.bin")); mStatsFile = new AtomicFile(new File(historyDirectory, "batterystats.bin")); mBatteryStatsHistory = new BatteryStatsHistory(this, historyDirectory, mHistoryBuffer); } @@ -12642,27 +12548,6 @@ public class BatteryStatsImpl extends BatteryStats { } /** - * Injects BatteryStatsConfig - */ - public void setBatteryStatsConfig(BatteryStatsConfig config) { - synchronized (this) { - mBatteryStatsConfig = config; - } - } - - /** - * Injects a LongPlugInAlarmHandler - */ - public void setLongPlugInAlarmInterface(AlarmInterface longPlugInAlarmInterface) { - synchronized (this) { - mLongPlugInAlarmInterface = longPlugInAlarmInterface; - if (!mOnBattery) { - scheduleNextResetWhilePluggedInCheck(); - } - } - } - - /** * Starts tracking CPU time-in-state for threads of the system server process, * keeping a separate account of threads receiving incoming binder calls. */ @@ -13134,12 +13019,12 @@ public class BatteryStatsImpl extends BatteryStats { } @GuardedBy("this") - public void resetAllStatsAndHistoryLocked(int reason) { + public void resetAllStatsCmdLocked() { final long mSecUptime = mClock.uptimeMillis(); long uptimeUs = mSecUptime * 1000; long mSecRealtime = mClock.elapsedRealtime(); long realtimeUs = mSecRealtime * 1000; - resetAllStatsLocked(mSecUptime, mSecRealtime, reason); + resetAllStatsLocked(mSecUptime, mSecRealtime, RESET_REASON_ADB_COMMAND); mDischargeStartLevel = mHistoryCur.batteryLevel; pullPendingStateUpdatesLocked(); addHistoryRecordLocked(mSecRealtime, mSecUptime); @@ -15613,73 +15498,6 @@ public class BatteryStatsImpl extends BatteryStats { } /** - * Might reset battery stats if conditions are met. Assumed the device is currently plugged in. - */ - @GuardedBy("this") - public void maybeResetWhilePluggedInLocked() { - final long elapsedRealtimeMs = mClock.elapsedRealtime(); - if (shouldResetWhilePluggedInLocked(elapsedRealtimeMs)) { - Slog.i(TAG, - "Resetting due to long plug in duration. elapsed time = " + elapsedRealtimeMs - + " ms, last plug in time = " + mBatteryPluggedInRealTimeMs - + " ms, last reset time = " + mRealtimeStartUs / 1000); - resetAllStatsAndHistoryLocked(RESET_REASON_PLUGGED_IN_FOR_LONG_DURATION); - } - - scheduleNextResetWhilePluggedInCheck(); - } - - @GuardedBy("this") - private void scheduleNextResetWhilePluggedInCheck() { - if (mLongPlugInAlarmInterface != null) { - final long timeoutMs = mClock.currentTimeMillis() - + mConstants.RESET_WHILE_PLUGGED_IN_MINIMUM_DURATION_HOURS - * DateUtils.HOUR_IN_MILLIS; - Calendar nextAlarm = Calendar.getInstance(); - nextAlarm.setTimeInMillis(timeoutMs); - - // Find the 2 AM the same day as the end of the minimum duration. - // This logic does not handle a Daylight Savings transition, or a timezone change - // while the alarm has been set. The need to reset after a long period while plugged - // in is not strict enough to warrant a well architected out solution. - nextAlarm.set(Calendar.MILLISECOND, 0); - nextAlarm.set(Calendar.SECOND, 0); - nextAlarm.set(Calendar.MINUTE, 0); - nextAlarm.set(Calendar.HOUR_OF_DAY, 2); - long nextTimeMs = nextAlarm.getTimeInMillis(); - if (nextTimeMs < timeoutMs) { - // The 2AM on the day of the timeout, move on the next day. - nextTimeMs += DateUtils.DAY_IN_MILLIS; - } - mLongPlugInAlarmInterface.schedule(nextTimeMs, DateUtils.HOUR_IN_MILLIS); - } - } - - - @GuardedBy("this") - private boolean shouldResetWhilePluggedInLocked(long elapsedRealtimeMs) { - if (mNoAutoReset) return false; - if (!mSystemReady) return false; - - final long pluggedInThresholdMs = mBatteryPluggedInRealTimeMs - + mConstants.RESET_WHILE_PLUGGED_IN_MINIMUM_DURATION_HOURS - * DateUtils.HOUR_IN_MILLIS; - if (elapsedRealtimeMs >= pluggedInThresholdMs) { - // The device has been plugged in for a long time. - final long resetThresholdMs = mRealtimeStartUs / 1000 - + mConstants.RESET_WHILE_PLUGGED_IN_MINIMUM_DURATION_HOURS - * DateUtils.HOUR_IN_MILLIS; - if (elapsedRealtimeMs >= resetThresholdMs) { - // And it has been a long time since the last reset. - return true; - } - } - - return false; - } - - - /** * Notifies BatteryStatsImpl that the system server is ready. */ public void onSystemReady() { @@ -15687,32 +15505,6 @@ public class BatteryStatsImpl extends BatteryStats { } @GuardedBy("this") - private boolean shouldResetOnUnplugLocked(int batteryStatus, int batteryLevel) { - if (mNoAutoReset) return false; - if (!mSystemReady) return false; - if (mBatteryStatsConfig.shouldResetOnUnplugHighBatteryLevel()) { - // Allow resetting due to currently being at high battery level - if (batteryStatus == BatteryManager.BATTERY_STATUS_FULL) return true; - if (batteryLevel >= 90) return true; - } - if (mBatteryStatsConfig.shouldResetOnUnplugAfterSignificantCharge()) { - // Allow resetting after a significant charge (from a very low level to a now very - // high level). - if (mDischargePlugLevel < 20 && batteryLevel >= 80) return true; - } - if (getHighDischargeAmountSinceCharge() >= 200) { - // Reset the stats if battery got partially charged and discharged repeatedly without - // ever reaching the full charge. - // This reset is done in order to prevent stats sessions from going on forever. - // Exceedingly long battery sessions would lead to an overflow of - // data structures such as mWakeupReasonStats. - return true; - } - - return false; - } - - @GuardedBy("this") protected void setOnBatteryLocked(final long mSecRealtime, final long mSecUptime, final boolean onBattery, final int oldStatus, final int level, final int chargeUah) { boolean doWrite = false; @@ -15724,10 +15516,23 @@ public class BatteryStatsImpl extends BatteryStats { final long realtimeUs = mSecRealtime * 1000; final int screenState = mScreenState; if (onBattery) { + // We will reset our status if we are unplugging after the + // battery was last full, or the level is at 100, or + // we have gone through a significant charge (from a very low + // level to a now very high level). + // Also, we will reset the stats if battery got partially charged + // and discharged repeatedly without ever reaching the full charge. + // This reset is done in order to prevent stats sessions from going on forever. + // Exceedingly long battery sessions would lead to an overflow of + // data structures such as mWakeupReasonStats. boolean reset = false; - if (shouldResetOnUnplugLocked(oldStatus, level)) { + if (!mNoAutoReset && mSystemReady + && (oldStatus == BatteryManager.BATTERY_STATUS_FULL + || level >= 90 + || (mDischargeCurrentLevel < 20 && level >= 80) + || getHighDischargeAmountSinceCharge() >= 200)) { Slog.i(TAG, "Resetting battery stats: level=" + level + " status=" + oldStatus - + " dischargeLevel=" + mDischargePlugLevel + + " dischargeLevel=" + mDischargeCurrentLevel + " lowAmount=" + getLowDischargeAmountSinceCharge() + " highAmount=" + getHighDischargeAmountSinceCharge()); // Before we write, collect a snapshot of the final aggregated @@ -15784,9 +15589,6 @@ public class BatteryStatsImpl extends BatteryStats { mInitStepMode = mCurStepMode; mModStepMode = 0; pullPendingStateUpdatesLocked(); - if (mLongPlugInAlarmInterface != null) { - mLongPlugInAlarmInterface.cancel(); - } mHistoryCur.batteryLevel = (byte)level; mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG; if (DEBUG_HISTORY) Slog.v(TAG, "Battery unplugged to: " @@ -15818,7 +15620,6 @@ public class BatteryStatsImpl extends BatteryStats { mLastChargingStateLevel = level; mOnBattery = mOnBatteryInternal = false; pullPendingStateUpdatesLocked(); - mBatteryPluggedInRealTimeMs = mSecRealtime; mHistoryCur.batteryLevel = (byte)level; mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG; if (DEBUG_HISTORY) Slog.v(TAG, "Battery plugged to: " @@ -15836,7 +15637,6 @@ public class BatteryStatsImpl extends BatteryStats { mMaxChargeStepLevel = level; mInitStepMode = mCurStepMode; mModStepMode = 0; - scheduleNextResetWhilePluggedInCheck(); } if (doWrite || (mLastWriteTimeMs + (60 * 1000)) < mSecRealtime) { if (mStatsFile != null && mBatteryStatsHistory.getActiveFile() != null) { @@ -16851,8 +16651,6 @@ public class BatteryStatsImpl extends BatteryStats { public static final String KEY_MAX_HISTORY_BUFFER_KB = "max_history_buffer_kb"; public static final String KEY_BATTERY_CHARGED_DELAY_MS = "battery_charged_delay_ms"; - public static final String KEY_RESET_WHILE_PLUGGED_IN_MINIMUM_DURATION_HOURS = - "reset_while_plugged_in_minimum_duration_hours"; private static final boolean DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME = true; private static final long DEFAULT_KERNEL_UID_READERS_THROTTLE_TIME = 1_000; @@ -16865,8 +16663,6 @@ public class BatteryStatsImpl extends BatteryStats { private static final int DEFAULT_MAX_HISTORY_FILES_LOW_RAM_DEVICE = 64; private static final int DEFAULT_MAX_HISTORY_BUFFER_LOW_RAM_DEVICE_KB = 64; /*Kilo Bytes*/ private static final int DEFAULT_BATTERY_CHARGED_DELAY_MS = 900000; /* 15 min */ - // Little less than 2 days - private static final int DEFAULT_RESET_WHILE_PLUGGED_IN_MINIMUM_DURATION_HOURS = 47; public boolean TRACK_CPU_ACTIVE_CLUSTER_TIME = DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME; /* Do not set default value for KERNEL_UID_READERS_THROTTLE_TIME. Need to trigger an @@ -16882,8 +16678,6 @@ public class BatteryStatsImpl extends BatteryStats { public int MAX_HISTORY_FILES; public int MAX_HISTORY_BUFFER; /*Bytes*/ public int BATTERY_CHARGED_DELAY_MS = DEFAULT_BATTERY_CHARGED_DELAY_MS; - public int RESET_WHILE_PLUGGED_IN_MINIMUM_DURATION_HOURS = - DEFAULT_RESET_WHILE_PLUGGED_IN_MINIMUM_DURATION_HOURS; private ContentResolver mResolver; private final KeyValueListParser mParser = new KeyValueListParser(','); @@ -16960,11 +16754,6 @@ public class BatteryStatsImpl extends BatteryStats { DEFAULT_MAX_HISTORY_BUFFER_LOW_RAM_DEVICE_KB : DEFAULT_MAX_HISTORY_BUFFER_KB) * 1024; - - RESET_WHILE_PLUGGED_IN_MINIMUM_DURATION_HOURS = mParser.getInt( - KEY_RESET_WHILE_PLUGGED_IN_MINIMUM_DURATION_HOURS, - DEFAULT_RESET_WHILE_PLUGGED_IN_MINIMUM_DURATION_HOURS); - updateBatteryChargedDelayMsLocked(); } } @@ -17019,8 +16808,6 @@ public class BatteryStatsImpl extends BatteryStats { pw.println(MAX_HISTORY_BUFFER/1024); pw.print(KEY_BATTERY_CHARGED_DELAY_MS); pw.print("="); pw.println(BATTERY_CHARGED_DELAY_MS); - pw.print(KEY_RESET_WHILE_PLUGGED_IN_MINIMUM_DURATION_HOURS); pw.print("="); - pw.println(RESET_WHILE_PLUGGED_IN_MINIMUM_DURATION_HOURS); } } diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java index bb69192f187f..e603e2ed57f1 100644 --- a/core/java/com/android/internal/policy/PhoneWindow.java +++ b/core/java/com/android/internal/policy/PhoneWindow.java @@ -295,6 +295,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { private boolean mClosingActionMenu; private int mVolumeControlStreamType = AudioManager.USE_DEFAULT_STREAM_TYPE; + private int mAudioMode = AudioManager.MODE_NORMAL; private MediaController mMediaController; private AudioManager mAudioManager; @@ -317,6 +318,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } }; + private AudioManager.OnModeChangedListener mOnModeChangedListener; + private Transition mEnterTransition = null; private Transition mReturnTransition = USE_DEFAULT_TRANSITION; private Transition mExitTransition = null; @@ -1950,9 +1953,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { case KeyEvent.KEYCODE_VOLUME_UP: case KeyEvent.KEYCODE_VOLUME_DOWN: case KeyEvent.KEYCODE_VOLUME_MUTE: { - // If we have a session send it the volume command, otherwise - // use the suggested stream. - if (mMediaController != null) { + // If we have a session and no active phone call send it the volume command, + // otherwise use the suggested stream. + if (mMediaController != null && !isActivePhoneCallOngoing()) { getMediaSessionManager().dispatchVolumeKeyEventToSessionAsSystemService(event, mMediaController.getSessionToken()); } else { @@ -2003,6 +2006,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { return false; } + private boolean isActivePhoneCallOngoing() { + return mAudioMode == AudioManager.MODE_IN_CALL + || mAudioMode == AudioManager.MODE_IN_COMMUNICATION; + } + private KeyguardManager getKeyguardManager() { if (mKeyguardManager == null) { mKeyguardManager = (KeyguardManager) getContext().getSystemService( @@ -2326,6 +2334,14 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } } + @Override + protected void onDestroy() { + if (mOnModeChangedListener != null) { + getAudioManager().removeOnModeChangedListener(mOnModeChangedListener); + mOnModeChangedListener = null; + } + } + private class PanelMenuPresenterCallback implements MenuPresenter.Callback { @Override public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) { @@ -3208,6 +3224,15 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { @Override public void setMediaController(MediaController controller) { mMediaController = controller; + if (controller != null && mOnModeChangedListener == null) { + mAudioMode = getAudioManager().getMode(); + mOnModeChangedListener = mode -> mAudioMode = mode; + getAudioManager().addOnModeChangedListener(getContext().getMainExecutor(), + mOnModeChangedListener); + } else if (mOnModeChangedListener != null) { + getAudioManager().removeOnModeChangedListener(mOnModeChangedListener); + mOnModeChangedListener = null; + } } @Override diff --git a/core/java/com/android/internal/protolog/BaseProtoLogImpl.java b/core/java/com/android/internal/protolog/BaseProtoLogImpl.java index 83309fc61009..ac9188a0debc 100644 --- a/core/java/com/android/internal/protolog/BaseProtoLogImpl.java +++ b/core/java/com/android/internal/protolog/BaseProtoLogImpl.java @@ -72,11 +72,13 @@ public class BaseProtoLogImpl { 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 TraceBuffer mBuffer; protected final ProtoLogViewerConfigReader mViewerConfig; + private final int mPerChunkSize; private boolean mProtoLogEnabled; private boolean mProtoLogEnabledLockFree; @@ -156,7 +158,7 @@ public class BaseProtoLogImpl { return; } try { - ProtoOutputStream os = new ProtoOutputStream(); + ProtoOutputStream os = new ProtoOutputStream(mPerChunkSize); long token = os.start(LOG); os.write(MESSAGE_HASH, messageHash); os.write(ELAPSED_REALTIME_NANOS, SystemClock.elapsedRealtimeNanos()); @@ -215,10 +217,16 @@ 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; } /** @@ -255,6 +263,7 @@ public class BaseProtoLogImpl { if (writeToFile) { writeProtoLogToFileLocked(); logAndPrintln(pw, "Log written to " + mLogFile + "."); + mBuffer.resetBuffer(); } if (mProtoLogEnabled) { logAndPrintln(pw, "ERROR: logging was re-enabled while waiting for flush."); @@ -363,7 +372,7 @@ public class BaseProtoLogImpl { try { long offset = (System.currentTimeMillis() - (SystemClock.elapsedRealtimeNanos() / 1000000)); - ProtoOutputStream proto = new ProtoOutputStream(); + ProtoOutputStream proto = new ProtoOutputStream(mPerChunkSize); proto.write(MAGIC_NUMBER, MAGIC_NUMBER_VALUE); proto.write(VERSION, PROTOLOG_VERSION); proto.write(REAL_TIME_TO_ELAPSED_TIME_OFFSET_MILLIS, offset); diff --git a/core/java/com/android/internal/protolog/ProtoLogImpl.java b/core/java/com/android/internal/protolog/ProtoLogImpl.java index 353c6c083d9d..527cfddf6d8e 100644 --- a/core/java/com/android/internal/protolog/ProtoLogImpl.java +++ b/core/java/com/android/internal/protolog/ProtoLogImpl.java @@ -30,6 +30,7 @@ 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; private static ProtoLogImpl sServiceInstance = null; @@ -94,7 +95,10 @@ public class ProtoLogImpl extends BaseProtoLogImpl { public static synchronized ProtoLogImpl getSingleInstance() { if (sServiceInstance == null) { sServiceInstance = new ProtoLogImpl( - new File(LOG_FILENAME), BUFFER_CAPACITY, new ProtoLogViewerConfigReader()); + new File(LOG_FILENAME) + , BUFFER_CAPACITY + , new ProtoLogViewerConfigReader() + , PER_CHUNK_SIZE); } return sServiceInstance; } @@ -105,8 +109,8 @@ public class ProtoLogImpl extends BaseProtoLogImpl { } public ProtoLogImpl(File logFile, int bufferCapacity, - ProtoLogViewerConfigReader viewConfigReader) { - super(logFile, VIEWER_CONFIG_FILENAME, bufferCapacity, viewConfigReader); - } + ProtoLogViewerConfigReader viewConfigReader, int perChunkSize) { + super(logFile, VIEWER_CONFIG_FILENAME, bufferCapacity, viewConfigReader, perChunkSize); + } } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 31903e25f8fd..0e95e30a99b8 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -3154,7 +3154,11 @@ android:protectionLevel="normal" /> <!-- Allows an application to call - {@link android.app.ActivityManager#killBackgroundProcesses}. + {@link android.app.ActivityManager#killBackgroundProcesses}. + + <p class="note">Third party applications can only use this API to kill their own + processes.</p> + <p>Protection level: normal --> <permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index 9491f22e5953..627911b07cb5 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -297,7 +297,7 @@ <string name="safeMode" msgid="8974401416068943888">"حالت ایمن"</string> <string name="android_system_label" msgid="5974767339591067210">"سیستم Android"</string> <string name="user_owner_label" msgid="8628726904184471211">"جابهجا شدن به نمایه شخصی"</string> - <string name="managed_profile_label" msgid="7316778766973512382">"جابهجا شدن به نمایه کاری"</string> + <string name="managed_profile_label" msgid="7316778766973512382">"رفتن به نمایه کاری"</string> <string name="permgrouplab_contacts" msgid="4254143639307316920">"مخاطبین"</string> <string name="permgroupdesc_contacts" msgid="9163927941244182567">"دسترسی به مخاطبین شما"</string> <string name="permgrouplab_location" msgid="1858277002233964394">"مکان"</string> diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml index 1226661b1896..8392df33c19f 100644 --- a/core/res/res/values-hy/strings.xml +++ b/core/res/res/values-hy/strings.xml @@ -1947,7 +1947,7 @@ <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g>՝ անհասանելի է"</string> <string name="app_streaming_blocked_title_for_permission_dialog" msgid="4483161748582966785">"Անհրաժեշտ է թույլտվություն"</string> <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Տեսախցիկն անհասանելի է"</string> - <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Շարունակեք հեռախոսով"</string> + <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Շարունակեք հեռախոսով"</string> <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Խոսափողն անհասանելի է"</string> <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"Play Խանութը հասանելի չէ"</string> <string name="app_streaming_blocked_title_for_settings_dialog" product="tv" msgid="196994247017450357">"Android TV-ի կարգավորումներն անհասանելի են"</string> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index 7060eeff4671..403afade6f59 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -1972,7 +1972,7 @@ <string name="profile_encrypted_message" msgid="1128512616293157802">"Tocca per sbloc. prof. di lav."</string> <string name="usb_mtp_launch_notification_title" msgid="774319638256707227">"Connesso a <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string> <string name="usb_mtp_launch_notification_description" msgid="6942535713629852684">"Tocca per visualizzare i file"</string> - <string name="pin_target" msgid="8036028973110156895">"Blocca"</string> + <string name="pin_target" msgid="8036028973110156895">"Fissa"</string> <string name="pin_specific_target" msgid="7824671240625957415">"Blocca <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="unpin_target" msgid="3963318576590204447">"Sgancia"</string> <string name="unpin_specific_target" msgid="3859828252160908146">"Sblocca <xliff:g id="LABEL">%1$s</xliff:g>"</string> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index b3bfebbb59c2..a2df4637fd22 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -1169,8 +1169,8 @@ <string name="no" msgid="5122037903299899715">"Отмена"</string> <string name="dialog_alert_title" msgid="651856561974090712">"Внимание!"</string> <string name="loading" msgid="3138021523725055037">"Загрузка…"</string> - <string name="capital_on" msgid="2770685323900821829">"I"</string> - <string name="capital_off" msgid="7443704171014626777">"O"</string> + <string name="capital_on" msgid="2770685323900821829">"Включено"</string> + <string name="capital_off" msgid="7443704171014626777">"Выключено"</string> <string name="checked" msgid="9179896827054513119">"отмечено"</string> <string name="not_checked" msgid="7972320087569023342">"не отмечено"</string> <string name="selected" msgid="6614607926197755875">"выбрано"</string> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 58c8b29dfad6..dafa0ad7989f 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -6092,9 +6092,4 @@ <!-- Whether to show weather on the lock screen by default. --> <bool name="config_lockscreenWeatherEnabledByDefault">false</bool> - - <!-- Whether to reset Battery Stats on unplug when the battery level is high. --> - <bool name="config_batteryStatsResetOnUnplugHighBatteryLevel">true</bool> - <!-- Whether to reset Battery Stats on unplug if the battery was significantly charged --> - <bool name="config_batteryStatsResetOnUnplugAfterSignificantCharge">true</bool> </resources> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 8addca27a7bb..591ba5feeee9 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -4903,7 +4903,4 @@ <!-- Whether to show weather on the lockscreen by default. --> <java-symbol type="bool" name="config_lockscreenWeatherEnabledByDefault" /> - - <java-symbol type="bool" name="config_batteryStatsResetOnUnplugHighBatteryLevel" /> - <java-symbol type="bool" name="config_batteryStatsResetOnUnplugAfterSignificantCharge" /> </resources> diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsResetTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsResetTest.java deleted file mode 100644 index 9c2d332a7c70..000000000000 --- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsResetTest.java +++ /dev/null @@ -1,362 +0,0 @@ -/* - * 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.os; - - -import static com.google.common.truth.Truth.assertThat; - -import android.content.Context; -import android.os.BatteryManager; - -import androidx.test.InstrumentationRegistry; -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -@SmallTest -@RunWith(AndroidJUnit4.class) -public class BatteryStatsResetTest { - - private static final int BATTERY_NOMINAL_VOLTAGE_MV = 3700; - private static final int BATTERY_CAPACITY_UAH = 4_000_000; - private static final int BATTERY_CHARGE_RATE_SECONDS_PER_LEVEL = 100; - - private MockClock mMockClock; - private MockBatteryStatsImpl mBatteryStatsImpl; - - - /** - * Battery status. Must be one of the following: - * {@link BatteryManager#BATTERY_STATUS_UNKNOWN} - * {@link BatteryManager#BATTERY_STATUS_CHARGING} - * {@link BatteryManager#BATTERY_STATUS_DISCHARGING} - * {@link BatteryManager#BATTERY_STATUS_NOT_CHARGING} - * {@link BatteryManager#BATTERY_STATUS_FULL} - */ - private int mBatteryStatus; - /** - * Battery health. Must be one of the following: - * {@link BatteryManager#BATTERY_HEALTH_UNKNOWN} - * {@link BatteryManager#BATTERY_HEALTH_GOOD} - * {@link BatteryManager#BATTERY_HEALTH_OVERHEAT} - * {@link BatteryManager#BATTERY_HEALTH_DEAD} - * {@link BatteryManager#BATTERY_HEALTH_OVER_VOLTAGE} - * {@link BatteryManager#BATTERY_HEALTH_UNSPECIFIED_FAILURE} - * {@link BatteryManager#BATTERY_HEALTH_COLD} - */ - private int mBatteryHealth; - /** - * Battery plug type. Can be the union of any number of the following flags: - * {@link BatteryManager#BATTERY_PLUGGED_AC} - * {@link BatteryManager#BATTERY_PLUGGED_USB} - * {@link BatteryManager#BATTERY_PLUGGED_WIRELESS} - * {@link BatteryManager#BATTERY_PLUGGED_DOCK} - * - * Zero means the device is unplugged. - */ - private int mBatteryPlugType; - private int mBatteryLevel; - private int mBatteryTemp; - private int mBatteryVoltageMv; - private int mBatteryChargeUah; - private int mBatteryChargeFullUah; - private long mBatteryChargeTimeToFullSeconds; - - @Before - public void setUp() { - final Context context = InstrumentationRegistry.getContext(); - - mMockClock = new MockClock(); - mBatteryStatsImpl = new MockBatteryStatsImpl(mMockClock, context.getFilesDir()); - mBatteryStatsImpl.onSystemReady(); - - - // Set up the battery state. Start off with a fully charged plugged in battery. - mBatteryStatus = BatteryManager.BATTERY_STATUS_FULL; - mBatteryHealth = BatteryManager.BATTERY_HEALTH_GOOD; - mBatteryPlugType = BatteryManager.BATTERY_PLUGGED_USB; - mBatteryLevel = 100; - mBatteryTemp = 70; // Arbitrary reasonable temperature. - mBatteryVoltageMv = BATTERY_NOMINAL_VOLTAGE_MV; - mBatteryChargeUah = BATTERY_CAPACITY_UAH; - mBatteryChargeFullUah = BATTERY_CAPACITY_UAH; - mBatteryChargeTimeToFullSeconds = 0; - } - - @Test - public void testResetOnUnplug_highBatteryLevel() { - mBatteryStatsImpl.setBatteryStatsConfig( - new BatteryStatsImpl.BatteryStatsConfig.Builder() - .setResetOnUnplugHighBatteryLevel(true) - .build()); - - long expectedResetTimeUs = 0; - - unplugBattery(); - dischargeToLevel(60); - - plugBattery(BatteryManager.BATTERY_PLUGGED_USB); - chargeToLevel(80); - unplugBattery(); - // Reset should not occur until battery level above 90. - assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs); - - plugBattery(BatteryManager.BATTERY_PLUGGED_USB); - chargeToLevel(95); - // Reset should not occur until unplug. - assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs); - - unplugBattery(); - // Reset should occur on unplug now that battery level is high (>=90) - expectedResetTimeUs = mMockClock.elapsedRealtime() * 1000; - assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs); - - // disable high battery level reset on unplug. - mBatteryStatsImpl.setBatteryStatsConfig( - new BatteryStatsImpl.BatteryStatsConfig.Builder() - .setResetOnUnplugHighBatteryLevel(false) - .build()); - - dischargeToLevel(60); - - plugBattery(BatteryManager.BATTERY_PLUGGED_USB); - chargeToLevel(95); - unplugBattery(); - // Reset should not occur since the high battery level logic has been disabled. - assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs); - } - - @Test - public void testResetOnUnplug_significantCharge() { - mBatteryStatsImpl.setBatteryStatsConfig( - new BatteryStatsImpl.BatteryStatsConfig.Builder() - .setResetOnUnplugAfterSignificantCharge(true) - .build()); - long expectedResetTimeUs = 0; - - unplugBattery(); - // Battery level dropped below 20%. - dischargeToLevel(15); - - plugBattery(BatteryManager.BATTERY_PLUGGED_USB); - chargeToLevel(50); - unplugBattery(); - // Reset should not occur until battery level above 80 - assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs); - - plugBattery(BatteryManager.BATTERY_PLUGGED_USB); - chargeToLevel(85); - unplugBattery(); - // Reset should not occur because the charge session did not go from 20% to 80% - assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs); - - // Battery level dropped below 20%. - dischargeToLevel(15); - - plugBattery(BatteryManager.BATTERY_PLUGGED_USB); - chargeToLevel(85); - unplugBattery(); - // Reset should occur after significant charge amount. - expectedResetTimeUs = mMockClock.elapsedRealtime() * 1000; - assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs); - - // disable reset on unplug after significant charge. - mBatteryStatsImpl.setBatteryStatsConfig( - new BatteryStatsImpl.BatteryStatsConfig.Builder() - .setResetOnUnplugAfterSignificantCharge(false) - .build()); - - // Battery level dropped below 20%. - dischargeToLevel(15); - - plugBattery(BatteryManager.BATTERY_PLUGGED_USB); - chargeToLevel(85); - unplugBattery(); - // Reset should not occur after significant charge amount. - assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs); - } - - @Test - public void testResetOnUnplug_manyPartialCharges() { - long expectedResetTimeUs = 0; - - unplugBattery(); - // Cumulative battery discharged: 60%. - dischargeToLevel(40); - - plugBattery(BatteryManager.BATTERY_PLUGGED_USB); - chargeToLevel(80); - unplugBattery(); - // Reset should not occur - assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs); - - // Cumulative battery discharged: 100%. - dischargeToLevel(40); - - plugBattery(BatteryManager.BATTERY_PLUGGED_USB); - chargeToLevel(80); - unplugBattery(); - // Reset should not occur - assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs); - - // Cumulative battery discharged: 140%. - dischargeToLevel(40); - - plugBattery(BatteryManager.BATTERY_PLUGGED_USB); - chargeToLevel(80); - unplugBattery(); - // Reset should not occur - assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs); - - // Cumulative battery discharged: 180%. - dischargeToLevel(40); - - plugBattery(BatteryManager.BATTERY_PLUGGED_USB); - chargeToLevel(80); - unplugBattery(); - // Reset should not occur - assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs); - - // Cumulative battery discharged: 220%. - dischargeToLevel(40); - - plugBattery(BatteryManager.BATTERY_PLUGGED_USB); - chargeToLevel(80); - unplugBattery(); - // Should reset after >200% of cumulative battery discharge - expectedResetTimeUs = mMockClock.elapsedRealtime() * 1000; - assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs); - } - - @Test - public void testResetWhilePluggedIn_longPlugIn() { - // disable high battery level reset on unplug. - mBatteryStatsImpl.setBatteryStatsConfig( - new BatteryStatsImpl.BatteryStatsConfig.Builder() - .setResetOnUnplugHighBatteryLevel(false) - .setResetOnUnplugAfterSignificantCharge(false) - .build()); - long expectedResetTimeUs = 0; - - plugBattery(BatteryManager.BATTERY_PLUGGED_USB); - mBatteryStatsImpl.maybeResetWhilePluggedInLocked(); - // Reset should not occur - assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs); - - // Increment time a day - incTimeMs(24L * 60L * 60L * 1000L); - mBatteryStatsImpl.maybeResetWhilePluggedInLocked(); - // Reset should still not occur - assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs); - - // Increment time a day - incTimeMs(24L * 60L * 60L * 1000L); - mBatteryStatsImpl.maybeResetWhilePluggedInLocked(); - // Reset 47 hour threshold crossed, reset should occur. - expectedResetTimeUs = mMockClock.elapsedRealtime() * 1000; - assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs); - - // Increment time a day - incTimeMs(24L * 60L * 60L * 1000L); - mBatteryStatsImpl.maybeResetWhilePluggedInLocked(); - // Reset should not occur - assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs); - - // Increment time a day - incTimeMs(24L * 60L * 60L * 1000L); - mBatteryStatsImpl.maybeResetWhilePluggedInLocked(); - // Reset another 47 hour threshold crossed, reset should occur. - expectedResetTimeUs = mMockClock.elapsedRealtime() * 1000; - assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs); - - // Increment time a day - incTimeMs(24L * 60L * 60L * 1000L); - mBatteryStatsImpl.maybeResetWhilePluggedInLocked(); - // Reset should not occur - assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs); - - unplugBattery(); - plugBattery(BatteryManager.BATTERY_PLUGGED_USB); - - // Increment time a day - incTimeMs(24L * 60L * 60L * 1000L); - mBatteryStatsImpl.maybeResetWhilePluggedInLocked(); - // Reset should not occur, since unplug occurred recently. - assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs); - - // Increment time a day - incTimeMs(24L * 60L * 60L * 1000L); - mBatteryStatsImpl.maybeResetWhilePluggedInLocked(); - // Reset another 47 hour threshold crossed, reset should occur. - expectedResetTimeUs = mMockClock.elapsedRealtime() * 1000; - assertThat(mBatteryStatsImpl.getStatsStartRealtime()).isEqualTo(expectedResetTimeUs); - } - - private void dischargeToLevel(int targetLevel) { - mBatteryStatus = BatteryManager.BATTERY_STATUS_DISCHARGING; - for (int level = mBatteryLevel - 1; level >= targetLevel; level--) { - prepareBatteryLevel(level); - incTimeMs(5000); // Arbitrary discharge rate. - updateBatteryState(); - } - } - - private void chargeToLevel(int targetLevel) { - mBatteryStatus = BatteryManager.BATTERY_STATUS_CHARGING; - for (int level = mBatteryLevel + 1; level <= targetLevel; level++) { - if (level >= 100) mBatteryStatus = BatteryManager.BATTERY_STATUS_FULL; - prepareBatteryLevel(level); - incTimeMs(BATTERY_CHARGE_RATE_SECONDS_PER_LEVEL * 1000); - updateBatteryState(); - } - } - - private void unplugBattery() { - mBatteryPlugType = 0; - updateBatteryState(); - } - - private void plugBattery(int type) { - mBatteryPlugType |= type; - updateBatteryState(); - } - - private void prepareBatteryLevel(int level) { - mBatteryLevel = level; - mBatteryChargeUah = mBatteryLevel * mBatteryChargeFullUah / 100; - mBatteryChargeTimeToFullSeconds = - (100 - mBatteryLevel) * BATTERY_CHARGE_RATE_SECONDS_PER_LEVEL; - } - - private void incTimeMs(long milliseconds) { - mMockClock.realtime += milliseconds; - mMockClock.uptime += milliseconds / 2; // Arbitrary slower uptime accumulation - mMockClock.currentTime += milliseconds; - } - - private void updateBatteryState() { - mBatteryStatsImpl.setBatteryStateLocked(mBatteryStatus, mBatteryHealth, mBatteryPlugType, - mBatteryLevel, mBatteryTemp, mBatteryVoltageMv, mBatteryChargeUah, - mBatteryChargeFullUah, mBatteryChargeTimeToFullSeconds, - mMockClock.elapsedRealtime(), mMockClock.uptimeMillis(), - mMockClock.currentTimeMillis()); - } -} - diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java index ae2d1afe0320..274286135174 100644 --- a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java +++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java @@ -342,7 +342,7 @@ public class BatteryUsageStatsProviderTest { Context context = InstrumentationRegistry.getContext(); BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats(); mStatsRule.setCurrentTime(5 * MINUTE_IN_MS); - batteryStats.resetAllStatsAndHistoryLocked(BatteryStatsImpl.RESET_REASON_ADB_COMMAND); + batteryStats.resetAllStatsCmdLocked(); BatteryUsageStatsStore batteryUsageStatsStore = new BatteryUsageStatsStore(context, batteryStats, new File(context.getCacheDir(), "BatteryUsageStatsProviderTest"), @@ -357,14 +357,14 @@ public class BatteryUsageStatsProviderTest { batteryStats.noteFlashlightOffLocked(APP_UID, 20 * MINUTE_IN_MS, 20 * MINUTE_IN_MS); mStatsRule.setCurrentTime(25 * MINUTE_IN_MS); - batteryStats.resetAllStatsAndHistoryLocked(BatteryStatsImpl.RESET_REASON_ADB_COMMAND); + batteryStats.resetAllStatsCmdLocked(); batteryStats.noteFlashlightOnLocked(APP_UID, 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS); batteryStats.noteFlashlightOffLocked(APP_UID, 50 * MINUTE_IN_MS, 50 * MINUTE_IN_MS); mStatsRule.setCurrentTime(55 * MINUTE_IN_MS); - batteryStats.resetAllStatsAndHistoryLocked(BatteryStatsImpl.RESET_REASON_ADB_COMMAND); + batteryStats.resetAllStatsCmdLocked(); // This section should be ignored because the timestamp is out or range batteryStats.noteFlashlightOnLocked(APP_UID, @@ -372,7 +372,7 @@ public class BatteryUsageStatsProviderTest { batteryStats.noteFlashlightOffLocked(APP_UID, 70 * MINUTE_IN_MS, 70 * MINUTE_IN_MS); mStatsRule.setCurrentTime(75 * MINUTE_IN_MS); - batteryStats.resetAllStatsAndHistoryLocked(BatteryStatsImpl.RESET_REASON_ADB_COMMAND); + batteryStats.resetAllStatsCmdLocked(); // This section should be ignored because it represents the current stats session batteryStats.noteFlashlightOnLocked(APP_UID, diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsStoreTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsStoreTest.java index 11b9047fab7f..c9729fab3b5e 100644 --- a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsStoreTest.java +++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsStoreTest.java @@ -84,7 +84,7 @@ public class BatteryUsageStatsStoreTest { mMockClock.realtime = 1_000_000; mMockClock.uptime = 1_000_000; - mBatteryStats.resetAllStatsAndHistoryLocked(BatteryStatsImpl.RESET_REASON_ADB_COMMAND); + mBatteryStats.resetAllStatsCmdLocked(); final long[] timestamps = mBatteryUsageStatsStore.listBatteryUsageStatsTimestamps(); assertThat(timestamps).hasLength(1); @@ -114,7 +114,7 @@ public class BatteryUsageStatsStoreTest { final int numberOfSnapshots = (int) (MAX_BATTERY_STATS_SNAPSHOT_STORAGE_BYTES / snapshotFileSize); for (int i = 0; i < numberOfSnapshots + 2; i++) { - mBatteryStats.resetAllStatsAndHistoryLocked(BatteryStatsImpl.RESET_REASON_ADB_COMMAND); + mBatteryStats.resetAllStatsCmdLocked(); mMockClock.realtime += 10_000_000; mMockClock.uptime += 10_000_000; @@ -141,7 +141,7 @@ public class BatteryUsageStatsStoreTest { mMockClock.currentTime += 10_000_000; prepareBatteryStats(); - mBatteryStats.resetAllStatsAndHistoryLocked(BatteryStatsImpl.RESET_REASON_ADB_COMMAND); + mBatteryStats.resetAllStatsCmdLocked(); } assertThat(getDirectorySize(mStoreDirectory)).isNotEqualTo(0); diff --git a/libs/WindowManager/Shell/res/color/split_divider_background.xml b/libs/WindowManager/Shell/res/color-night/taskbar_background.xml index 049980803ee3..9473cdd607d6 100644 --- a/libs/WindowManager/Shell/res/color/split_divider_background.xml +++ b/libs/WindowManager/Shell/res/color-night/taskbar_background.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <!-- - ~ Copyright (C) 2021 The Android Open Source Project + ~ 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. @@ -14,6 +14,7 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License. --> +<!-- Should be the same as in packages/apps/Launcher3/res/color-night-v31/taskbar_background.xml --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:color="@android:color/system_neutral1_500" android:lStar="15" /> </selector>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/res/color/taskbar_background.xml b/libs/WindowManager/Shell/res/color/taskbar_background.xml index b3d260299106..0e165fca4fd3 100644 --- a/libs/WindowManager/Shell/res/color/taskbar_background.xml +++ b/libs/WindowManager/Shell/res/color/taskbar_background.xml @@ -16,5 +16,5 @@ --> <!-- Should be the same as in packages/apps/Launcher3/res/color-v31/taskbar_background.xml --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:color="@android:color/system_neutral1_500" android:lStar="15" /> + <item android:color="@android:color/system_neutral1_500" android:lStar="95" /> </selector>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/res/drawable/desktop_mode_decor_menu_background.xml b/libs/WindowManager/Shell/res/drawable/desktop_mode_decor_menu_background.xml index 9167382d0898..c6e634c6622c 100644 --- a/libs/WindowManager/Shell/res/drawable/desktop_mode_decor_menu_background.xml +++ b/libs/WindowManager/Shell/res/drawable/desktop_mode_decor_menu_background.xml @@ -17,6 +17,6 @@ <shape android:shape="rectangle" xmlns:android="http://schemas.android.com/apk/res/android"> <solid android:color="@android:color/white" /> - <corners android:radius="20dp" /> + <corners android:radius="@dimen/caption_menu_corner_radius" /> <stroke android:width="1dp" android:color="#b3b3b3"/> </shape> diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_decor_handle_menu.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_decor_handle_menu.xml index f6e3f2edfa14..f9aeb6a8448a 100644 --- a/libs/WindowManager/Shell/res/layout/desktop_mode_decor_handle_menu.xml +++ b/libs/WindowManager/Shell/res/layout/desktop_mode_decor_handle_menu.xml @@ -21,7 +21,6 @@ android:layout_height="match_parent" android:orientation="vertical" android:background="@drawable/desktop_mode_decor_menu_background" - android:elevation="@dimen/caption_menu_elevation" android:divider="?android:attr/dividerHorizontal" android:showDividers="middle" android:dividerPadding="18dip"> @@ -63,38 +62,46 @@ android:layout_width="0dp" android:layout_height="1dp" android:layout_weight="0.5" /> - <Button + <ImageButton style="@style/CaptionWindowingButtonStyle" android:id="@+id/fullscreen_button" android:contentDescription="@string/fullscreen_text" - android:background="@drawable/caption_fullscreen_button"/> + android:src="@drawable/caption_fullscreen_button" + android:scaleType="fitCenter" + android:background="?android:selectableItemBackgroundBorderless"/> <Space android:layout_width="0dp" android:layout_height="1dp" android:layout_weight="1" /> - <Button + <ImageButton style="@style/CaptionWindowingButtonStyle" android:id="@+id/split_screen_button" android:contentDescription="@string/split_screen_text" - android:background="@drawable/caption_split_screen_button"/> + android:src="@drawable/caption_split_screen_button" + android:scaleType="fitCenter" + android:background="?android:selectableItemBackgroundBorderless"/> <Space android:layout_width="0dp" android:layout_height="1dp" android:layout_weight="1" /> - <Button + <ImageButton style="@style/CaptionWindowingButtonStyle" android:id="@+id/floating_button" android:contentDescription="@string/float_button_text" - android:background="@drawable/caption_floating_button"/> + android:src="@drawable/caption_floating_button" + android:scaleType="fitCenter" + android:background="?android:selectableItemBackgroundBorderless"/> <Space android:layout_width="0dp" android:layout_height="1dp" android:layout_weight="1" /> - <Button + <ImageButton style="@style/CaptionWindowingButtonStyle" android:id="@+id/desktop_button" android:contentDescription="@string/desktop_text" - android:background="@drawable/caption_desktop_button"/> + android:src="@drawable/caption_desktop_button" + android:scaleType="fitCenter" + android:background="?android:selectableItemBackgroundBorderless"/> <Space android:layout_width="0dp" android:layout_height="1dp" diff --git a/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_layout.xml b/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_layout.xml index e8edad15dfc3..413cfd78fd91 100644 --- a/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_layout.xml +++ b/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_layout.xml @@ -16,9 +16,7 @@ <com.android.wm.shell.compatui.letterboxedu.LetterboxEduDialogLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:background="@android:color/system_neutral1_900"> + style="@style/LetterboxDialog"> <!-- The background of the top-level layout acts as the background dim. --> diff --git a/libs/WindowManager/Shell/res/layout/letterbox_restart_dialog_layout.xml b/libs/WindowManager/Shell/res/layout/letterbox_restart_dialog_layout.xml index ba9852c4dd6b..5aff4159e135 100644 --- a/libs/WindowManager/Shell/res/layout/letterbox_restart_dialog_layout.xml +++ b/libs/WindowManager/Shell/res/layout/letterbox_restart_dialog_layout.xml @@ -16,14 +16,10 @@ <com.android.wm.shell.compatui.RestartDialogLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:background="@android:color/system_neutral1_900"> + style="@style/LetterboxDialog"> <!-- The background of the top-level layout acts as the background dim. --> - <!--TODO (b/266288912): Resolve overdraw warning --> - <!-- Vertical margin will be set dynamically since it depends on task bounds. Setting the alpha of the dialog container to 0, since it shouldn't be visible until the enter animation starts. --> diff --git a/libs/WindowManager/Shell/res/values-night/colors.xml b/libs/WindowManager/Shell/res/values-night/colors.xml index 83c4d93982f4..5c6bb57a7f1c 100644 --- a/libs/WindowManager/Shell/res/values-night/colors.xml +++ b/libs/WindowManager/Shell/res/values-night/colors.xml @@ -15,6 +15,7 @@ --> <resources> + <color name="docked_divider_handle">#ffffff</color> <!-- Bubbles --> <color name="bubbles_icon_tint">@color/GM2_grey_200</color> <!-- Splash screen--> diff --git a/libs/WindowManager/Shell/res/values/colors.xml b/libs/WindowManager/Shell/res/values/colors.xml index 6e750a3d5e34..6fb70006e67f 100644 --- a/libs/WindowManager/Shell/res/values/colors.xml +++ b/libs/WindowManager/Shell/res/values/colors.xml @@ -17,7 +17,8 @@ */ --> <resources> - <color name="docked_divider_handle">#ffffff</color> + <color name="docked_divider_handle">#000000</color> + <color name="split_divider_background">@color/taskbar_background</color> <drawable name="forced_resizable_background">#59000000</drawable> <color name="minimize_dock_shadow_start">#60000000</color> <color name="minimize_dock_shadow_end">#00000000</color> @@ -41,6 +42,9 @@ <color name="letterbox_education_accent_primary">@android:color/system_accent1_100</color> <color name="letterbox_education_text_secondary">@android:color/system_neutral2_200</color> + <!-- Letterbox Dialog --> + <color name="letterbox_dialog_background">@android:color/system_neutral1_900</color> + <!-- GM2 colors --> <color name="GM2_grey_200">#E8EAED</color> <color name="GM2_grey_700">#5F6368</color> diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml index 336c156e831a..680ad5101366 100644 --- a/libs/WindowManager/Shell/res/values/dimen.xml +++ b/libs/WindowManager/Shell/res/values/dimen.xml @@ -370,6 +370,10 @@ <dimen name="freeform_resize_corner">44dp</dimen> - <dimen name="caption_menu_elevation">4dp</dimen> + <!-- The radius of the caption menu shadow. --> + <dimen name="caption_menu_shadow_radius">4dp</dimen> + + <!-- The radius of the caption menu corners. --> + <dimen name="caption_menu_corner_radius">20dp</dimen> </resources> diff --git a/libs/WindowManager/Shell/res/values/styles.xml b/libs/WindowManager/Shell/res/values/styles.xml index 0a0c49f2d93f..bc2e71d1c013 100644 --- a/libs/WindowManager/Shell/res/values/styles.xml +++ b/libs/WindowManager/Shell/res/values/styles.xml @@ -38,11 +38,9 @@ </style> <style name="CaptionWindowingButtonStyle"> - <item name="android:layout_width">32dp</item> - <item name="android:layout_height">32dp</item> + <item name="android:layout_width">40dp</item> + <item name="android:layout_height">40dp</item> <item name="android:padding">4dp</item> - <item name="android:layout_marginTop">5dp</item> - <item name="android:layout_marginBottom">5dp</item> </style> <style name="CaptionMenuButtonStyle" parent="@style/Widget.AppCompat.Button.Borderless"> @@ -80,6 +78,12 @@ <item name="android:textColor">@color/tv_pip_edu_text</item> </style> + <style name="LetterboxDialog" parent="@android:style/Theme.Holo"> + <item name="android:layout_width">wrap_content</item> + <item name="android:layout_height">wrap_content</item> + <item name="android:background">@color/letterbox_dialog_background</item> + </style> + <style name="RestartDialogTitleText"> <item name="android:textSize">24sp</item> <item name="android:textColor">?android:attr/textColorPrimary</item> 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 71e15c12b9c0..c08085ee8cd0 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 @@ -61,6 +61,7 @@ import android.os.Binder; import android.os.Handler; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; import android.service.notification.NotificationListenerService; @@ -125,6 +126,15 @@ public class BubbleController implements ConfigurationChangeListener { private static final String SYSTEM_DIALOG_REASON_KEY = "reason"; private static final String SYSTEM_DIALOG_REASON_GESTURE_NAV = "gestureNav"; + // TODO(b/256873975) Should use proper flag when available to shell/launcher + /** + * Whether bubbles are showing in the bubble bar from launcher. This is only available + * on large screens and {@link BubbleController#isShowingAsBubbleBar()} should be used + * to check all conditions that indicate if the bubble bar is in use. + */ + private static final boolean BUBBLE_BAR_ENABLED = + SystemProperties.getBoolean("persist.wm.debug.bubble_bar", false); + private final Context mContext; private final BubblesImpl mImpl = new BubblesImpl(); private Bubbles.BubbleExpandListener mExpandListener; @@ -150,9 +160,6 @@ public class BubbleController implements ConfigurationChangeListener { private final ShellExecutor mBackgroundExecutor; - // Whether or not we should show bubbles pinned at the bottom of the screen. - private boolean mIsBubbleBarEnabled; - private BubbleLogger mLogger; private BubbleData mBubbleData; @Nullable private BubbleStackView mStackView; @@ -533,10 +540,10 @@ public class BubbleController implements ConfigurationChangeListener { mDataRepository.removeBubblesForUser(removedUserId, parentUserId); } - // TODO(b/256873975): Should pass this into the constructor once flags are available to shell. - /** Sets whether the bubble bar is enabled (i.e. bubbles pinned to bottom on large screens). */ - public void setBubbleBarEnabled(boolean enabled) { - mIsBubbleBarEnabled = enabled; + /** Whether bubbles are showing in the bubble bar. */ + public boolean isShowingAsBubbleBar() { + // TODO(b/269670598): should also check that we're in gesture nav + return BUBBLE_BAR_ENABLED && mBubblePositioner.isLargeScreen(); } /** Whether this userId belongs to the current user. */ @@ -605,12 +612,6 @@ public class BubbleController implements ConfigurationChangeListener { mStackView.setUnbubbleConversationCallback(mSysuiProxy::onUnbubbleConversation); } - if (mIsBubbleBarEnabled && mBubblePositioner.isLargeScreen()) { - mBubblePositioner.setUsePinnedLocation(true); - } else { - mBubblePositioner.setUsePinnedLocation(false); - } - addToWindowManagerMaybe(); } @@ -1852,13 +1853,6 @@ public class BubbleController implements ConfigurationChangeListener { } @Override - public void setBubbleBarEnabled(boolean enabled) { - mMainExecutor.execute(() -> { - BubbleController.this.setBubbleBarEnabled(enabled); - }); - } - - @Override public void onNotificationPanelExpandedChanged(boolean expanded) { mMainExecutor.execute( () -> BubbleController.this.onNotificationPanelExpandedChanged(expanded)); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java index 6230d22ebe12..3fd09675a245 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java @@ -283,7 +283,7 @@ public class BubbleData { } boolean isShowingOverflow() { - return mShowingOverflow && (isExpanded() || mPositioner.showingInTaskbar()); + return mShowingOverflow && isExpanded(); } /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java index 07c58527a815..5ea2450114f0 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java @@ -18,9 +18,6 @@ package com.android.wm.shell.bubbles; import static android.view.View.LAYOUT_DIRECTION_RTL; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import android.annotation.IntDef; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; @@ -39,8 +36,6 @@ import androidx.annotation.VisibleForTesting; import com.android.launcher3.icons.IconNormalizer; import com.android.wm.shell.R; -import java.lang.annotation.Retention; - /** * Keeps track of display size, configuration, and specific bubble sizes. One place for all * placement and positioning calculations to refer to. @@ -50,15 +45,6 @@ public class BubblePositioner { ? "BubblePositioner" : BubbleDebugConfig.TAG_BUBBLES; - @Retention(SOURCE) - @IntDef({TASKBAR_POSITION_NONE, TASKBAR_POSITION_RIGHT, TASKBAR_POSITION_LEFT, - TASKBAR_POSITION_BOTTOM}) - @interface TaskbarPosition {} - public static final int TASKBAR_POSITION_NONE = -1; - public static final int TASKBAR_POSITION_RIGHT = 0; - public static final int TASKBAR_POSITION_LEFT = 1; - public static final int TASKBAR_POSITION_BOTTOM = 2; - /** When the bubbles are collapsed in a stack only some of them are shown, this is how many. **/ public static final int NUM_VISIBLE_WHEN_RESTING = 2; /** Indicates a bubble's height should be the maximum available space. **/ @@ -108,15 +94,9 @@ public class BubblePositioner { private int mOverflowHeight; private int mMinimumFlyoutWidthLargeScreen; - private PointF mPinLocation; private PointF mRestingStackPosition; private int[] mPaddings = new int[4]; - private boolean mShowingInTaskbar; - private @TaskbarPosition int mTaskbarPosition = TASKBAR_POSITION_NONE; - private int mTaskbarIconSize; - private int mTaskbarSize; - public BubblePositioner(Context context, WindowManager windowManager) { mContext = context; mWindowManager = windowManager; @@ -153,27 +133,11 @@ public class BubblePositioner { + " insets: " + insets + " isLargeScreen: " + mIsLargeScreen + " isSmallTablet: " + mIsSmallTablet - + " bounds: " + bounds - + " showingInTaskbar: " + mShowingInTaskbar); + + " bounds: " + bounds); } updateInternal(mRotation, insets, bounds); } - /** - * Updates position information to account for taskbar state. - * - * @param taskbarPosition which position the taskbar is displayed in. - * @param showingInTaskbar whether the taskbar is being shown. - */ - public void updateForTaskbar(int iconSize, - @TaskbarPosition int taskbarPosition, boolean showingInTaskbar, int taskbarSize) { - mShowingInTaskbar = showingInTaskbar; - mTaskbarIconSize = iconSize; - mTaskbarPosition = taskbarPosition; - mTaskbarSize = taskbarSize; - update(); - } - @VisibleForTesting public void updateInternal(int rotation, Insets insets, Rect bounds) { mRotation = rotation; @@ -232,10 +196,6 @@ public class BubblePositioner { R.dimen.bubbles_flyout_min_width_large_screen); mMaxBubbles = calculateMaxBubbles(); - - if (mShowingInTaskbar) { - adjustForTaskbar(); - } } /** @@ -260,30 +220,6 @@ public class BubblePositioner { return mDefaultMaxBubbles; } - /** - * Taskbar insets appear as navigationBar insets, however, unlike navigationBar this should - * not inset bubbles UI as bubbles floats above the taskbar. This adjust the available space - * and insets to account for the taskbar. - */ - // TODO(b/171559950): When the insets are reported correctly we can remove this logic - private void adjustForTaskbar() { - // When bar is showing on edges... subtract that inset because we appear on top - if (mShowingInTaskbar && mTaskbarPosition != TASKBAR_POSITION_BOTTOM) { - WindowInsets metricInsets = mWindowManager.getCurrentWindowMetrics().getWindowInsets(); - Insets navBarInsets = metricInsets.getInsetsIgnoringVisibility( - WindowInsets.Type.navigationBars()); - int newInsetLeft = mInsets.left; - int newInsetRight = mInsets.right; - if (mTaskbarPosition == TASKBAR_POSITION_LEFT) { - mPositionRect.left -= navBarInsets.left; - newInsetLeft -= navBarInsets.left; - } else if (mTaskbarPosition == TASKBAR_POSITION_RIGHT) { - mPositionRect.right += navBarInsets.right; - newInsetRight -= navBarInsets.right; - } - mInsets = Insets.of(newInsetLeft, mInsets.top, newInsetRight, mInsets.bottom); - } - } /** * @return a rect of available screen space accounting for orientation, system bars and cutouts. @@ -327,14 +263,12 @@ public class BubblePositioner { * to the left or right side. */ public boolean showBubblesVertically() { - return isLandscape() || mShowingInTaskbar || mIsLargeScreen; + return isLandscape() || mIsLargeScreen; } /** Size of the bubble. */ public int getBubbleSize() { - return (mShowingInTaskbar && mTaskbarIconSize > 0) - ? mTaskbarIconSize - : mBubbleSize; + return mBubbleSize; } /** The amount of padding at the top of the screen that the bubbles avoid when being placed. */ @@ -699,9 +633,6 @@ public class BubblePositioner { /** The position the bubble stack should rest at when collapsed. */ public PointF getRestingPosition() { - if (mPinLocation != null) { - return mPinLocation; - } if (mRestingStackPosition == null) { return getDefaultStartPosition(); } @@ -713,9 +644,6 @@ public class BubblePositioner { * is being shown. */ public PointF getDefaultStartPosition() { - if (mPinLocation != null) { - return mPinLocation; - } // Start on the left if we're in LTR, right otherwise. final boolean startOnLeft = mContext.getResources().getConfiguration().getLayoutDirection() @@ -730,7 +658,6 @@ public class BubblePositioner { 1 /* default starts with 1 bubble */)); } - /** * Returns the region that the stack position must stay within. This goes slightly off the left * and right sides of the screen, below the status bar/cutout and above the navigation bar. @@ -751,39 +678,6 @@ public class BubblePositioner { } /** - * @return whether the bubble stack is pinned to the taskbar. - */ - public boolean showingInTaskbar() { - return mShowingInTaskbar; - } - - /** - * @return the taskbar position if set. - */ - public int getTaskbarPosition() { - return mTaskbarPosition; - } - - public int getTaskbarSize() { - return mTaskbarSize; - } - - /** - * In some situations bubbles will be pinned to a specific onscreen location. This sets whether - * bubbles should be pinned or not. - */ - public void setUsePinnedLocation(boolean usePinnedLocation) { - if (usePinnedLocation) { - mShowingInTaskbar = true; - mPinLocation = new PointF(mPositionRect.right - mBubbleSize, - mPositionRect.bottom - mBubbleSize); - } else { - mPinLocation = null; - mShowingInTaskbar = false; - } - } - - /** * Navigation bar has an area where system gestures can be started from. * * @return {@link Rect} for system navigation bar gesture zone 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 f2afefe243bc..15f8eaca0833 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 @@ -680,8 +680,6 @@ public class BubbleStackView extends FrameLayout // Re-show the expanded view if we hid it. showExpandedViewIfNeeded(); - } else if (mPositioner.showingInTaskbar()) { - mStackAnimationController.snapStackBack(); } else { // Fling the stack to the edge, and save whether or not it's going to end up on // the left side of the screen. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java index df4325763a17..a5deac5a51da 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java @@ -257,11 +257,6 @@ public interface Bubbles { */ void onUserRemoved(int removedUserId); - /** - * Sets whether bubble bar should be enabled or not. - */ - void setBubbleBarEnabled(boolean enabled); - /** Listener to find out about stack expansion / collapse events. */ interface BubbleExpandListener { /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java index 0ee0ea60a1bc..5533842f2d89 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java @@ -417,23 +417,9 @@ public class StackAnimationController extends } /** - * Snaps the stack back to the previous resting position. - */ - public void snapStackBack() { - if (mLayout == null) { - return; - } - PointF p = getStackPositionAlongNearestHorizontalEdge(); - springStackAfterFling(p.x, p.y); - } - - /** * Where the stack would be if it were snapped to the nearest horizontal edge (left or right). */ public PointF getStackPositionAlongNearestHorizontalEdge() { - if (mPositioner.showingInTaskbar()) { - return mPositioner.getRestingPosition(); - } final PointF stackPos = getStackPosition(); final boolean onLeft = mLayout.isFirstChildXLeftOfCenter(stackPos.x); final RectF bounds = mPositioner.getAllowableStackPositionRegion(getBubbleCount()); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java index f616e6f64750..ffc56b6f6106 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java @@ -120,6 +120,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange private int mOrientation; private int mRotation; private int mDensity; + private int mUiMode; private final boolean mDimNonImeSide; private ValueAnimator mDividerFlingAnimator; @@ -295,10 +296,12 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange final Rect rootBounds = configuration.windowConfiguration.getBounds(); final int orientation = configuration.orientation; final int density = configuration.densityDpi; + final int uiMode = configuration.uiMode; if (mOrientation == orientation && mRotation == rotation && mDensity == density + && mUiMode == uiMode && mRootBounds.equals(rootBounds)) { return false; } @@ -310,6 +313,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange mRootBounds.set(rootBounds); mRotation = rotation; mDensity = density; + mUiMode = uiMode; mDividerSnapAlgorithm = getSnapAlgorithm(mContext, mRootBounds, null); updateDividerConfig(mContext); initDividerPosition(mTempRect); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipContentOverlay.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipContentOverlay.java index 480bf93b2ddb..53bf42a3c911 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipContentOverlay.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipContentOverlay.java @@ -39,6 +39,9 @@ import android.window.TaskSnapshot; * Represents the content overlay used during the entering PiP animation. */ public abstract class PipContentOverlay { + // Fixed string used in WMShellFlickerTests + protected static final String LAYER_NAME = "PipContentOverlay"; + protected SurfaceControl mLeash; /** Attaches the internal {@link #mLeash} to the given parent leash. */ @@ -86,7 +89,7 @@ public abstract class PipContentOverlay { mContext = context; mLeash = new SurfaceControl.Builder(new SurfaceSession()) .setCallsite(TAG) - .setName(TAG) + .setName(LAYER_NAME) .setColorLayer() .build(); } @@ -139,7 +142,7 @@ public abstract class PipContentOverlay { mSourceRectHint = new Rect(sourceRectHint); mLeash = new SurfaceControl.Builder(new SurfaceSession()) .setCallsite(TAG) - .setName(TAG) + .setName(LAYER_NAME) .build(); } @@ -194,7 +197,7 @@ public abstract class PipContentOverlay { prepareAppIconOverlay(activityInfo); mLeash = new SurfaceControl.Builder(new SurfaceSession()) .setCallsite(TAG) - .setName(TAG) + .setName(LAYER_NAME) .build(); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java index f11836ea5bee..e9d257139779 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java @@ -1594,7 +1594,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, // source rect hint to enter PiP use bounds animation. if (sourceHintRect == null) { if (SystemProperties.getBoolean( - "persist.wm.debug.enable_pip_app_icon_overlay", false)) { + "persist.wm.debug.enable_pip_app_icon_overlay", true)) { animator.setAppIconContentOverlay( mContext, currentBounds, mTaskInfo.topActivityInfo); } else { 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 e5c0570841f4..7234b15bf6d2 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 @@ -804,7 +804,7 @@ public class PipTransition extends PipTransitionController { // We use content overlay when there is no source rect hint to enter PiP use bounds // animation. if (SystemProperties.getBoolean( - "persist.wm.debug.enable_pip_app_icon_overlay", false)) { + "persist.wm.debug.enable_pip_app_icon_overlay", true)) { animator.setAppIconContentOverlay( mContext, currentBounds, taskInfo.topActivityInfo); } else { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java index a6733843d4c3..c0e48105ffbe 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 @@ -204,7 +204,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, // and exit, since exit itself can trigger a number of changes that update the stages. private boolean mShouldUpdateRecents; private boolean mExitSplitScreenOnHide; - private boolean mIsSplitEntering; + private boolean mIsDividerRemoteAnimating; private boolean mIsDropEntering; private boolean mIsExiting; @@ -764,17 +764,9 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, final WindowContainerTransaction wct = new WindowContainerTransaction(); if (options1 == null) options1 = new Bundle(); if (pendingIntent2 == null) { - // Launching a solo task. - ActivityOptions activityOptions = ActivityOptions.fromBundle(options1); - activityOptions.update(ActivityOptions.makeRemoteAnimation(adapter)); - options1 = activityOptions.toBundle(); - addActivityOptions(options1, null /* launchTarget */); - if (shortcutInfo1 != null) { - wct.startShortcut(mContext.getPackageName(), shortcutInfo1, options1); - } else { - wct.sendPendingIntent(pendingIntent1, fillInIntent1, options1); - } - mSyncQueue.queue(wct); + // Launching a solo intent or shortcut as fullscreen. + launchAsFullscreenWithRemoteAnimation(pendingIntent1, fillInIntent1, shortcutInfo1, + options1, adapter, wct); return; } @@ -797,13 +789,9 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, final WindowContainerTransaction wct = new WindowContainerTransaction(); if (options1 == null) options1 = new Bundle(); if (taskId == INVALID_TASK_ID) { - // Launching a solo task. - ActivityOptions activityOptions = ActivityOptions.fromBundle(options1); - activityOptions.update(ActivityOptions.makeRemoteAnimation(adapter)); - options1 = activityOptions.toBundle(); - addActivityOptions(options1, null /* launchTarget */); - wct.sendPendingIntent(pendingIntent, fillInIntent, options1); - mSyncQueue.queue(wct); + // Launching a solo intent as fullscreen. + launchAsFullscreenWithRemoteAnimation(pendingIntent, fillInIntent, null, options1, + adapter, wct); return; } @@ -822,13 +810,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, final WindowContainerTransaction wct = new WindowContainerTransaction(); if (options1 == null) options1 = new Bundle(); if (taskId == INVALID_TASK_ID) { - // Launching a solo task. - ActivityOptions activityOptions = ActivityOptions.fromBundle(options1); - activityOptions.update(ActivityOptions.makeRemoteAnimation(adapter)); - options1 = activityOptions.toBundle(); - addActivityOptions(options1, null /* launchTarget */); - wct.startShortcut(mContext.getPackageName(), shortcutInfo, options1); - mSyncQueue.queue(wct); + // Launching a solo shortcut as fullscreen. + launchAsFullscreenWithRemoteAnimation(null, null, shortcutInfo, options1, adapter, wct); return; } @@ -838,6 +821,49 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, instanceId); } + private void launchAsFullscreenWithRemoteAnimation(@Nullable PendingIntent pendingIntent, + @Nullable Intent fillInIntent, @Nullable ShortcutInfo shortcutInfo, + @Nullable Bundle options, RemoteAnimationAdapter adapter, + WindowContainerTransaction wct) { + LegacyTransitions.ILegacyTransition transition = + (transit, apps, wallpapers, nonApps, finishedCallback, t) -> { + if (apps == null || apps.length == 0) { + onRemoteAnimationFinished(apps); + t.apply(); + try { + adapter.getRunner().onAnimationCancelled(mKeyguardShowing); + } catch (RemoteException e) { + Slog.e(TAG, "Error starting remote animation", e); + } + return; + } + + for (int i = 0; i < apps.length; ++i) { + if (apps[i].mode == MODE_OPENING) { + t.show(apps[i].leash); + } + } + t.apply(); + + try { + adapter.getRunner().onAnimationStart( + transit, apps, wallpapers, nonApps, finishedCallback); + } catch (RemoteException e) { + Slog.e(TAG, "Error starting remote animation", e); + } + }; + + addActivityOptions(options, null /* launchTarget */); + if (shortcutInfo != null) { + wct.startShortcut(mContext.getPackageName(), shortcutInfo, options); + } else if (pendingIntent != null) { + wct.sendPendingIntent(pendingIntent, fillInIntent, options); + } else { + Slog.e(TAG, "Pending intent and shortcut are null is invalid case."); + } + mSyncQueue.queue(transition, WindowManager.TRANSIT_OPEN, wct); + } + private void startWithLegacyTransition(WindowContainerTransaction wct, @Nullable PendingIntent mainPendingIntent, @Nullable Intent mainFillInIntent, @Nullable ShortcutInfo mainShortcutInfo, @Nullable Bundle mainOptions, @@ -881,7 +907,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, // Set false to avoid record new bounds with old task still on top; mShouldUpdateRecents = false; - mIsSplitEntering = true; + mIsDividerRemoteAnimating = true; if (mSplitRequest == null) { mSplitRequest = new SplitRequest(mainTaskId, mainPendingIntent != null ? mainPendingIntent.getIntent() : null, @@ -894,23 +920,25 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, if (options == null) options = new Bundle(); addActivityOptions(options, mMainStage); - options = wrapAsSplitRemoteAnimation(adapter, options); updateWindowBounds(mSplitLayout, wct); + wct.reorder(mRootTaskInfo.token, true); + wct.setForceTranslucent(mRootTaskInfo.token, false); // TODO(b/268008375): Merge APIs to start a split pair into one. if (mainTaskId != INVALID_TASK_ID) { + options = wrapAsSplitRemoteAnimation(adapter, options); wct.startTask(mainTaskId, options); - } else if (mainShortcutInfo != null) { - wct.startShortcut(mContext.getPackageName(), mainShortcutInfo, options); + mSyncQueue.queue(wct); } else { - wct.sendPendingIntent(mainPendingIntent, mainFillInIntent, options); + if (mainShortcutInfo != null) { + wct.startShortcut(mContext.getPackageName(), mainShortcutInfo, options); + } else { + wct.sendPendingIntent(mainPendingIntent, mainFillInIntent, options); + } + mSyncQueue.queue(wrapAsSplitRemoteAnimation(adapter), WindowManager.TRANSIT_OPEN, wct); } - wct.reorder(mRootTaskInfo.token, true); - wct.setForceTranslucent(mRootTaskInfo.token, false); - - mSyncQueue.queue(wct); mSyncQueue.runInSync(t -> { setDividerVisibility(true, t); }); @@ -967,6 +995,54 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, return activityOptions.toBundle(); } + private LegacyTransitions.ILegacyTransition wrapAsSplitRemoteAnimation( + RemoteAnimationAdapter adapter) { + LegacyTransitions.ILegacyTransition transition = + (transit, apps, wallpapers, nonApps, finishedCallback, t) -> { + if (apps == null || apps.length == 0) { + onRemoteAnimationFinished(apps); + t.apply(); + try { + adapter.getRunner().onAnimationCancelled(mKeyguardShowing); + } catch (RemoteException e) { + Slog.e(TAG, "Error starting remote animation", e); + } + return; + } + + // Wrap the divider bar into non-apps target to animate together. + nonApps = ArrayUtils.appendElement(RemoteAnimationTarget.class, nonApps, + getDividerBarLegacyTarget()); + + for (int i = 0; i < apps.length; ++i) { + if (apps[i].mode == MODE_OPENING) { + t.show(apps[i].leash); + // Reset the surface position of the opening app to prevent offset. + t.setPosition(apps[i].leash, 0, 0); + } + } + t.apply(); + + IRemoteAnimationFinishedCallback wrapCallback = + new IRemoteAnimationFinishedCallback.Stub() { + @Override + public void onAnimationFinished() throws RemoteException { + onRemoteAnimationFinished(apps); + finishedCallback.onAnimationFinished(); + } + }; + Transitions.setRunningRemoteTransitionDelegate(adapter.getCallingApplication()); + try { + adapter.getRunner().onAnimationStart( + transit, apps, wallpapers, nonApps, wrapCallback); + } catch (RemoteException e) { + Slog.e(TAG, "Error starting remote animation", e); + } + }; + + return transition; + } + private void setEnterInstanceId(InstanceId instanceId) { if (instanceId != null) { mLogger.enterRequested(instanceId, ENTER_REASON_LAUNCHER); @@ -974,7 +1050,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, } private void onRemoteAnimationFinishedOrCancelled(WindowContainerTransaction evictWct) { - mIsSplitEntering = false; + mIsDividerRemoteAnimating = false; mShouldUpdateRecents = true; mSplitRequest = null; // If any stage has no child after animation finished, it means that split will display @@ -993,6 +1069,27 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, } } + private void onRemoteAnimationFinished(RemoteAnimationTarget[] apps) { + mIsDividerRemoteAnimating = false; + mShouldUpdateRecents = true; + mSplitRequest = null; + // If any stage has no child after finished animation, that side of the split will display + // nothing. This might happen if starting the same app on the both sides while not + // supporting multi-instance. Exit the split screen and expand that app to full screen. + if (mMainStage.getChildCount() == 0 || mSideStage.getChildCount() == 0) { + mMainExecutor.execute(() -> exitSplitScreen(mMainStage.getChildCount() == 0 + ? mSideStage : mMainStage, EXIT_REASON_UNKNOWN)); + mSplitUnsupportedToast.show(); + return; + } + + final WindowContainerTransaction evictWct = new WindowContainerTransaction(); + prepareEvictNonOpeningChildTasks(SPLIT_POSITION_TOP_OR_LEFT, apps, evictWct); + prepareEvictNonOpeningChildTasks(SPLIT_POSITION_BOTTOM_OR_RIGHT, apps, evictWct); + mSyncQueue.queue(evictWct); + } + + /** * Collects all the current child tasks of a specific split and prepares transaction to evict * them to display. @@ -1240,7 +1337,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, } }); mShouldUpdateRecents = false; - mIsSplitEntering = false; + mIsDividerRemoteAnimating = false; mSplitLayout.getInvisibleBounds(mTempRect1); if (childrenToTop == null || childrenToTop.getTopVisibleChildTaskId() == INVALID_TASK_ID) { @@ -1573,7 +1670,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, && !ENABLE_SHELL_TRANSITIONS) { // Clear the divider remote animating flag as the divider will be re-rendered to apply // the new rotation config. - mIsSplitEntering = false; + mIsDividerRemoteAnimating = false; mSplitLayout.update(null /* t */); onLayoutSizeChanged(mSplitLayout); } @@ -1623,9 +1720,9 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, } void onChildTaskAppeared(StageListenerImpl stageListener, int taskId) { + // Handle entering split screen while there is a split pair running in the background. if (stageListener == mSideStageListener && !isSplitScreenVisible() && isSplitActive() - && !mIsSplitEntering) { - // Handle entring split case here if split already running background. + && mSplitRequest == null) { if (mIsDropEntering) { mSplitLayout.resetDividerPosition(); } else { @@ -1717,7 +1814,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, mDividerVisible = visible; sendSplitVisibilityChanged(); - if (mIsSplitEntering) { + if (mIsDividerRemoteAnimating) { ProtoLog.d(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, " Skip animating divider bar due to it's remote animating."); return; @@ -1737,7 +1834,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, " Skip animating divider bar due to divider leash not ready."); return; } - if (mIsSplitEntering) { + if (mIsDividerRemoteAnimating) { ProtoLog.d(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, " Skip animating divider bar due to it's remote animating."); return; @@ -1805,7 +1902,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, mSplitLayout.flingDividerToDismiss( mSideStagePosition != SPLIT_POSITION_BOTTOM_OR_RIGHT, EXIT_REASON_APP_FINISHED); - } else if (!isSplitScreenVisible() && !mIsSplitEntering) { + } else if (!isSplitScreenVisible() && mSplitRequest == null) { + // Dismiss split screen in the background once any sides of the split become empty. exitSplitScreen(null /* childrenToTop */, EXIT_REASON_APP_FINISHED); } } else if (isSideStage && hasChildren && !mMainStage.isActive()) { 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 0779f1d72551..72da1089c91c 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 @@ -74,6 +74,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin private boolean mDesktopActive; private AdditionalWindow mHandleMenu; private final int mHandleMenuWidthId = R.dimen.freeform_decor_caption_menu_width; + private final int mHandleMenuShadowRadiusId = R.dimen.caption_menu_shadow_radius; + private final int mHandleMenuCornerRadiusId = R.dimen.caption_menu_corner_radius; private PointF mHandleMenuPosition = new PointF(); DesktopModeWindowDecoration( @@ -353,19 +355,16 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin .windowConfiguration.getBounds().width(); final int menuWidth = loadDimensionPixelSize(resources, mHandleMenuWidthId); final int menuHeight = loadDimensionPixelSize(resources, mCaptionMenuHeightId); - - // Elevation gives the appearance of a changed x/y coordinate; this is to fix that - int elevationOffset = 2 * loadDimensionPixelSize(resources, - R.dimen.caption_menu_elevation); + final int shadowRadius = loadDimensionPixelSize(resources, mHandleMenuShadowRadiusId); + final int cornerRadius = loadDimensionPixelSize(resources, mHandleMenuCornerRadiusId); final int x = mRelayoutParams.mCaptionX + (captionWidth / 2) - (menuWidth / 2) - - mResult.mDecorContainerOffsetX - elevationOffset; - final int y = - mRelayoutParams.mCaptionY - mResult.mDecorContainerOffsetY - elevationOffset; + - mResult.mDecorContainerOffsetX; + final int y = mRelayoutParams.mCaptionY - mResult.mDecorContainerOffsetY; mHandleMenuPosition.set(x, y); String namePrefix = "Caption Menu"; mHandleMenu = addWindow(R.layout.desktop_mode_decor_handle_menu, namePrefix, t, x, y, - menuWidth, menuHeight, 2 * elevationOffset); + menuWidth, menuHeight, shadowRadius, cornerRadius); mSyncQueue.runInSync(transaction -> { transaction.merge(t); t.close(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java index ae685ad4b8d9..133826f3e69b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java @@ -391,11 +391,12 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> * @param yPos y position of new window * @param width width of new window * @param height height of new window - * @param cropPadding padding to add to window crop to ensure shadows display properly - * @return + * @param shadowRadius radius of the shadow of the new window + * @param cornerRadius radius of the corners of the new window + * @return the {@link AdditionalWindow} that was added. */ AdditionalWindow addWindow(int layoutId, String namePrefix, SurfaceControl.Transaction t, - int xPos, int yPos, int width, int height, int cropPadding) { + int xPos, int yPos, int width, int height, int shadowRadius, int cornerRadius) { final SurfaceControl.Builder builder = mSurfaceControlBuilderSupplier.get(); SurfaceControl windowSurfaceControl = builder .setName(namePrefix + " of Task=" + mTaskInfo.taskId) @@ -404,9 +405,10 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> .build(); View v = LayoutInflater.from(mDecorWindowContext).inflate(layoutId, null); - t.setPosition( - windowSurfaceControl, xPos, yPos) - .setWindowCrop(windowSurfaceControl, width + cropPadding, height + cropPadding) + t.setPosition(windowSurfaceControl, xPos, yPos) + .setWindowCrop(windowSurfaceControl, width, height) + .setShadowRadius(windowSurfaceControl, shadowRadius) + .setCornerRadius(windowSurfaceControl, cornerRadius) .show(windowSurfaceControl); final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(width, height, diff --git a/libs/WindowManager/Shell/tests/unittest/AndroidManifest.xml b/libs/WindowManager/Shell/tests/unittest/AndroidManifest.xml index fac04614d945..47a116be1b66 100644 --- a/libs/WindowManager/Shell/tests/unittest/AndroidManifest.xml +++ b/libs/WindowManager/Shell/tests/unittest/AndroidManifest.xml @@ -20,6 +20,7 @@ package="com.android.wm.shell.tests"> <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" /> + <uses-permission android:name="android.permission.VIBRATE"/> <application android:debuggable="true" android:largeHeap="true"> <uses-library android:name="android.test.mock" /> diff --git a/libs/WindowManager/Shell/tests/unittest/res/values/dimen.xml b/libs/WindowManager/Shell/tests/unittest/res/values/dimen.xml index 27d40b2b25b2..aa1b24189274 100644 --- a/libs/WindowManager/Shell/tests/unittest/res/values/dimen.xml +++ b/libs/WindowManager/Shell/tests/unittest/res/values/dimen.xml @@ -24,4 +24,6 @@ <dimen name="test_window_decor_bottom_outset">40dp</dimen> <dimen name="test_window_decor_shadow_radius">5dp</dimen> <dimen name="test_window_decor_resize_handle">10dp</dimen> + <dimen name="test_caption_menu_shadow_radius">4dp</dimen> + <dimen name="test_caption_menu_corner_radius">20dp</dimen> </resources>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java index b80edcece512..7e39b5b8f2ce 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java @@ -108,6 +108,8 @@ public class WindowDecorationTests extends ShellTestCase { private SurfaceControl.Transaction mMockSurfaceControlAddWindowT; private WindowDecoration.RelayoutParams mRelayoutParams = new WindowDecoration.RelayoutParams(); private int mCaptionMenuWidthId; + private int mCaptionMenuShadowRadiusId; + private int mCaptionMenuCornerRadiusId; @Before public void setUp() { @@ -118,6 +120,8 @@ public class WindowDecorationTests extends ShellTestCase { mRelayoutParams.mLayoutResId = 0; mRelayoutParams.mCaptionHeightId = R.dimen.test_freeform_decor_caption_height; mCaptionMenuWidthId = R.dimen.test_freeform_decor_caption_menu_width; + mCaptionMenuShadowRadiusId = R.dimen.test_caption_menu_shadow_radius; + mCaptionMenuCornerRadiusId = R.dimen.test_caption_menu_corner_radius; mRelayoutParams.mShadowRadiusId = R.dimen.test_window_decor_shadow_radius; doReturn(mMockSurfaceControlViewHost).when(mMockSurfaceControlViewHostFactory) @@ -431,7 +435,19 @@ public class WindowDecorationTests extends ShellTestCase { verify(additionalWindowSurfaceBuilder).setParent(decorContainerSurface); verify(additionalWindowSurfaceBuilder).build(); verify(mMockSurfaceControlAddWindowT).setPosition(additionalWindowSurface, 20, 40); - verify(mMockSurfaceControlAddWindowT).setWindowCrop(additionalWindowSurface, 442, 74); + final int width = WindowDecoration.loadDimensionPixelSize( + mContext.getResources(), mCaptionMenuWidthId); + final int height = WindowDecoration.loadDimensionPixelSize( + mContext.getResources(), mRelayoutParams.mCaptionHeightId); + verify(mMockSurfaceControlAddWindowT).setWindowCrop(additionalWindowSurface, width, height); + final int shadowRadius = WindowDecoration.loadDimensionPixelSize(mContext.getResources(), + mCaptionMenuShadowRadiusId); + verify(mMockSurfaceControlAddWindowT) + .setShadowRadius(additionalWindowSurface, shadowRadius); + final int cornerRadius = WindowDecoration.loadDimensionPixelSize(mContext.getResources(), + mCaptionMenuCornerRadiusId); + verify(mMockSurfaceControlAddWindowT) + .setCornerRadius(additionalWindowSurface, cornerRadius); verify(mMockSurfaceControlAddWindowT).show(additionalWindowSurface); verify(mMockSurfaceControlViewHostFactory, Mockito.times(2)) .create(any(), eq(defaultDisplay), any()); @@ -559,13 +575,15 @@ public class WindowDecorationTests extends ShellTestCase { int y = mRelayoutParams.mCaptionY; int width = loadDimensionPixelSize(resources, mCaptionMenuWidthId); int height = loadDimensionPixelSize(resources, mRelayoutParams.mCaptionHeightId); + int shadowRadius = loadDimensionPixelSize(resources, mCaptionMenuShadowRadiusId); + int cornerRadius = loadDimensionPixelSize(resources, mCaptionMenuCornerRadiusId); String name = "Test Window"; WindowDecoration.AdditionalWindow additionalWindow = addWindow(R.layout.desktop_mode_decor_handle_menu, name, mMockSurfaceControlAddWindowT, x - mRelayoutResult.mDecorContainerOffsetX, y - mRelayoutResult.mDecorContainerOffsetY, - width, height, 10); + width, height, shadowRadius, cornerRadius); return additionalWindow; } } diff --git a/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightDreamManager.java b/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightDreamManager.java index 5ecec4ddd1ad..3125f088c72b 100644 --- a/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightDreamManager.java +++ b/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightDreamManager.java @@ -72,6 +72,7 @@ public final class LowLightDreamManager { public static final int AMBIENT_LIGHT_MODE_LOW_LIGHT = 2; private final DreamManager mDreamManager; + private final LowLightTransitionCoordinator mLowLightTransitionCoordinator; @Nullable private final ComponentName mLowLightDreamComponent; @@ -81,8 +82,10 @@ public final class LowLightDreamManager { @Inject public LowLightDreamManager( DreamManager dreamManager, + LowLightTransitionCoordinator lowLightTransitionCoordinator, @Named(LOW_LIGHT_DREAM_COMPONENT) @Nullable ComponentName lowLightDreamComponent) { mDreamManager = dreamManager; + mLowLightTransitionCoordinator = lowLightTransitionCoordinator; mLowLightDreamComponent = lowLightDreamComponent; } @@ -111,7 +114,9 @@ public final class LowLightDreamManager { mAmbientLightMode = ambientLightMode; - mDreamManager.setSystemDreamComponent(mAmbientLightMode == AMBIENT_LIGHT_MODE_LOW_LIGHT - ? mLowLightDreamComponent : null); + boolean shouldEnterLowLight = mAmbientLightMode == AMBIENT_LIGHT_MODE_LOW_LIGHT; + mLowLightTransitionCoordinator.notifyBeforeLowLightTransition(shouldEnterLowLight, + () -> mDreamManager.setSystemDreamComponent( + shouldEnterLowLight ? mLowLightDreamComponent : null)); } } diff --git a/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightTransitionCoordinator.java b/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightTransitionCoordinator.java new file mode 100644 index 000000000000..874a2d5af75e --- /dev/null +++ b/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightTransitionCoordinator.java @@ -0,0 +1,111 @@ +/* + * 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.dream.lowlight; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.annotation.Nullable; + +import javax.inject.Inject; +import javax.inject.Singleton; + +/** + * Helper class that allows listening and running animations before entering or exiting low light. + */ +@Singleton +public class LowLightTransitionCoordinator { + /** + * Listener that is notified before low light entry. + */ + public interface LowLightEnterListener { + /** + * Callback that is notified before the device enters low light. + * + * @return an optional animator that will be waited upon before entering low light. + */ + Animator onBeforeEnterLowLight(); + } + + /** + * Listener that is notified before low light exit. + */ + public interface LowLightExitListener { + /** + * Callback that is notified before the device exits low light. + * + * @return an optional animator that will be waited upon before exiting low light. + */ + Animator onBeforeExitLowLight(); + } + + private LowLightEnterListener mLowLightEnterListener; + private LowLightExitListener mLowLightExitListener; + + @Inject + public LowLightTransitionCoordinator() { + } + + /** + * Sets the listener for the low light enter event. + * + * Only one listener can be set at a time. This method will overwrite any previously set + * listener. Null can be used to unset the listener. + */ + public void setLowLightEnterListener(@Nullable LowLightEnterListener lowLightEnterListener) { + mLowLightEnterListener = lowLightEnterListener; + } + + /** + * Sets the listener for the low light exit event. + * + * Only one listener can be set at a time. This method will overwrite any previously set + * listener. Null can be used to unset the listener. + */ + public void setLowLightExitListener(@Nullable LowLightExitListener lowLightExitListener) { + mLowLightExitListener = lowLightExitListener; + } + + /** + * Notifies listeners that the device is about to enter or exit low light. + * + * @param entering true if listeners should be notified before entering low light, false if this + * is notifying before exiting. + * @param callback callback that will be run after listeners complete. + */ + void notifyBeforeLowLightTransition(boolean entering, Runnable callback) { + Animator animator = null; + + if (entering && mLowLightEnterListener != null) { + animator = mLowLightEnterListener.onBeforeEnterLowLight(); + } else if (!entering && mLowLightExitListener != null) { + animator = mLowLightExitListener.onBeforeExitLowLight(); + } + + // If the listener returned an animator to indicate it was running an animation, run the + // callback after the animation completes, otherwise call the callback directly. + if (animator != null) { + animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animator) { + callback.run(); + } + }); + } else { + callback.run(); + } + } +} diff --git a/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightDreamManagerTest.java b/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightDreamManagerTest.java index 91a170f7ae14..4b95d8c84bac 100644 --- a/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightDreamManagerTest.java +++ b/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightDreamManagerTest.java @@ -21,7 +21,10 @@ import static com.android.dream.lowlight.LowLightDreamManager.AMBIENT_LIGHT_MODE import static com.android.dream.lowlight.LowLightDreamManager.AMBIENT_LIGHT_MODE_UNKNOWN; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.clearInvocations; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; @@ -44,44 +47,52 @@ public class LowLightDreamManagerTest { private DreamManager mDreamManager; @Mock + private LowLightTransitionCoordinator mTransitionCoordinator; + + @Mock private ComponentName mDreamComponent; + LowLightDreamManager mLowLightDreamManager; + @Before public void setUp() { MockitoAnnotations.initMocks(this); + + // Automatically run any provided Runnable to mTransitionCoordinator to simplify testing. + doAnswer(invocation -> { + ((Runnable) invocation.getArgument(1)).run(); + return null; + }).when(mTransitionCoordinator).notifyBeforeLowLightTransition(anyBoolean(), + any(Runnable.class)); + + mLowLightDreamManager = new LowLightDreamManager(mDreamManager, mTransitionCoordinator, + mDreamComponent); } @Test public void setAmbientLightMode_lowLight_setSystemDream() { - final LowLightDreamManager lowLightDreamManager = new LowLightDreamManager(mDreamManager, - mDreamComponent); - - lowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_LOW_LIGHT); + mLowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_LOW_LIGHT); + verify(mTransitionCoordinator).notifyBeforeLowLightTransition(eq(true), any()); verify(mDreamManager).setSystemDreamComponent(mDreamComponent); } @Test public void setAmbientLightMode_regularLight_clearSystemDream() { - final LowLightDreamManager lowLightDreamManager = new LowLightDreamManager(mDreamManager, - mDreamComponent); - - lowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_REGULAR); + mLowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_REGULAR); + verify(mTransitionCoordinator).notifyBeforeLowLightTransition(eq(false), any()); verify(mDreamManager).setSystemDreamComponent(null); } @Test public void setAmbientLightMode_defaultUnknownMode_clearSystemDream() { - final LowLightDreamManager lowLightDreamManager = new LowLightDreamManager(mDreamManager, - mDreamComponent); - // Set to low light first. - lowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_LOW_LIGHT); + mLowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_LOW_LIGHT); clearInvocations(mDreamManager); // Return to default unknown mode. - lowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_UNKNOWN); + mLowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_UNKNOWN); verify(mDreamManager).setSystemDreamComponent(null); } @@ -89,7 +100,7 @@ public class LowLightDreamManagerTest { @Test public void setAmbientLightMode_dreamComponentNotSet_doNothing() { final LowLightDreamManager lowLightDreamManager = new LowLightDreamManager(mDreamManager, - null /*dream component*/); + mTransitionCoordinator, null /*dream component*/); lowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_LOW_LIGHT); diff --git a/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightTransitionCoordinatorTest.java b/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightTransitionCoordinatorTest.java new file mode 100644 index 000000000000..81e1e33d6220 --- /dev/null +++ b/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightTransitionCoordinatorTest.java @@ -0,0 +1,113 @@ +/* + * 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.dream.lowlight; + +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.when; + +import android.animation.Animator; +import android.testing.AndroidTestingRunner; + +import androidx.test.filters.SmallTest; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +public class LowLightTransitionCoordinatorTest { + @Mock + private LowLightTransitionCoordinator.LowLightEnterListener mEnterListener; + + @Mock + private LowLightTransitionCoordinator.LowLightExitListener mExitListener; + + @Mock + private Animator mAnimator; + + @Captor + private ArgumentCaptor<Animator.AnimatorListener> mAnimatorListenerCaptor; + + @Mock + private Runnable mRunnable; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + } + + @Test + public void onEnterCalledOnListeners() { + LowLightTransitionCoordinator coordinator = new LowLightTransitionCoordinator(); + + coordinator.setLowLightEnterListener(mEnterListener); + + coordinator.notifyBeforeLowLightTransition(true, mRunnable); + + verify(mEnterListener).onBeforeEnterLowLight(); + verify(mRunnable).run(); + } + + @Test + public void onExitCalledOnListeners() { + LowLightTransitionCoordinator coordinator = new LowLightTransitionCoordinator(); + + coordinator.setLowLightExitListener(mExitListener); + + coordinator.notifyBeforeLowLightTransition(false, mRunnable); + + verify(mExitListener).onBeforeExitLowLight(); + verify(mRunnable).run(); + } + + @Test + public void listenerNotCalledAfterRemoval() { + LowLightTransitionCoordinator coordinator = new LowLightTransitionCoordinator(); + + coordinator.setLowLightEnterListener(mEnterListener); + coordinator.setLowLightEnterListener(null); + + coordinator.notifyBeforeLowLightTransition(true, mRunnable); + + verifyZeroInteractions(mEnterListener); + verify(mRunnable).run(); + } + + @Test + public void runnableCalledAfterAnimationEnds() { + when(mEnterListener.onBeforeEnterLowLight()).thenReturn(mAnimator); + + LowLightTransitionCoordinator coordinator = new LowLightTransitionCoordinator(); + coordinator.setLowLightEnterListener(mEnterListener); + + coordinator.notifyBeforeLowLightTransition(true, mRunnable); + + // Animator listener is added and the runnable is not run yet. + verify(mAnimator).addListener(mAnimatorListenerCaptor.capture()); + verifyZeroInteractions(mRunnable); + + // Runnable is run once the animation ends. + mAnimatorListenerCaptor.getValue().onAnimationEnd(null); + verify(mRunnable).run(); + } +} diff --git a/media/java/android/media/projection/OWNERS b/media/java/android/media/projection/OWNERS index 9ca391013aa3..2273f816ac60 100644 --- a/media/java/android/media/projection/OWNERS +++ b/media/java/android/media/projection/OWNERS @@ -1,2 +1,4 @@ michaelwr@google.com santoscordon@google.com +chaviw@google.com +nmusgrave@google.com diff --git a/packages/SettingsLib/DeviceStateRotationLock/OWNERS b/packages/SettingsLib/DeviceStateRotationLock/OWNERS new file mode 100644 index 000000000000..091df2610866 --- /dev/null +++ b/packages/SettingsLib/DeviceStateRotationLock/OWNERS @@ -0,0 +1 @@ +include platform/frameworks/base:/packages/SettingsLib/src/com/android/settingslib/devicestate/OWNERS
\ No newline at end of file diff --git a/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/DeviceStateRotationLockSettingsManager.java b/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/DeviceStateRotationLockSettingsManager.java index 4ed7e19f341d..10b004e1b243 100644 --- a/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/DeviceStateRotationLockSettingsManager.java +++ b/packages/SettingsLib/DeviceStateRotationLock/src/com.android.settingslib.devicestate/DeviceStateRotationLockSettingsManager.java @@ -29,6 +29,7 @@ import android.os.Looper; import android.os.UserHandle; import android.provider.Settings; import android.text.TextUtils; +import android.util.IndentingPrintWriter; import android.util.Log; import android.util.SparseIntArray; @@ -36,6 +37,7 @@ import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Objects; @@ -57,6 +59,7 @@ public final class DeviceStateRotationLockSettingsManager { private final SecureSettings mSecureSettings; private String[] mDeviceStateRotationLockDefaults; private SparseIntArray mDeviceStateRotationLockSettings; + private SparseIntArray mDeviceStateDefaultRotationLockSettings; private SparseIntArray mDeviceStateRotationLockFallbackSettings; private String mLastSettingValue; private List<SettableDeviceState> mSettableDeviceStates; @@ -93,9 +96,7 @@ public final class DeviceStateRotationLockSettingsManager { /** Returns true if device-state based rotation lock settings are enabled. */ public static boolean isDeviceStateRotationLockEnabled(Context context) { return context.getResources() - .getStringArray(R.array.config_perDeviceStateRotationLockDefaults) - .length - > 0; + .getStringArray(R.array.config_perDeviceStateRotationLockDefaults).length > 0; } private void listenForSettingsChange() { @@ -228,6 +229,15 @@ public final class DeviceStateRotationLockSettingsManager { try { key = Integer.parseInt(values[i++]); value = Integer.parseInt(values[i++]); + boolean isPersistedValueIgnored = value == DEVICE_STATE_ROTATION_LOCK_IGNORED; + boolean isDefaultValueIgnored = mDeviceStateDefaultRotationLockSettings.get(key) + == DEVICE_STATE_ROTATION_LOCK_IGNORED; + if (isPersistedValueIgnored != isDefaultValueIgnored) { + Log.w(TAG, "Conflict for ignored device state " + key + + ". Falling back on defaults"); + fallbackOnDefaults(); + return; + } mDeviceStateRotationLockSettings.put(key, value); } catch (NumberFormatException e) { Log.wtf(TAG, "Error deserializing one of the saved settings", e); @@ -276,6 +286,9 @@ public final class DeviceStateRotationLockSettingsManager { } private void persistSettingIfChanged(String newSettingValue) { + Log.v(TAG, "persistSettingIfChanged: " + + "last=" + mLastSettingValue + ", " + + "new=" + newSettingValue); if (TextUtils.equals(mLastSettingValue, newSettingValue)) { return; } @@ -288,6 +301,8 @@ public final class DeviceStateRotationLockSettingsManager { private void loadDefaults() { mSettableDeviceStates = new ArrayList<>(mDeviceStateRotationLockDefaults.length); + mDeviceStateDefaultRotationLockSettings = new SparseIntArray( + mDeviceStateRotationLockDefaults.length); mDeviceStateRotationLockSettings = new SparseIntArray( mDeviceStateRotationLockDefaults.length); mDeviceStateRotationLockFallbackSettings = new SparseIntArray(1); @@ -311,6 +326,7 @@ public final class DeviceStateRotationLockSettingsManager { boolean isSettable = rotationLockSetting != DEVICE_STATE_ROTATION_LOCK_IGNORED; mSettableDeviceStates.add(new SettableDeviceState(deviceState, isSettable)); mDeviceStateRotationLockSettings.put(deviceState, rotationLockSetting); + mDeviceStateDefaultRotationLockSettings.put(deviceState, rotationLockSetting); } catch (NumberFormatException e) { Log.wtf(TAG, "Error parsing settings entry. Entry was: " + entry, e); return; @@ -318,6 +334,22 @@ public final class DeviceStateRotationLockSettingsManager { } } + /** Dumps internal state. */ + public void dump(IndentingPrintWriter pw) { + pw.println("DeviceStateRotationLockSettingsManager"); + pw.increaseIndent(); + pw.println("mDeviceStateRotationLockDefaults: " + Arrays.toString( + mDeviceStateRotationLockDefaults)); + pw.println("mDeviceStateDefaultRotationLockSettings: " + + mDeviceStateDefaultRotationLockSettings); + pw.println("mDeviceStateRotationLockSettings: " + mDeviceStateRotationLockSettings); + pw.println("mDeviceStateRotationLockFallbackSettings: " + + mDeviceStateRotationLockFallbackSettings); + pw.println("mSettableDeviceStates: " + mSettableDeviceStates); + pw.println("mLastSettingValue: " + mLastSettingValue); + pw.decreaseIndent(); + } + /** * Called when the persisted settings have changed, requiring a reinitialization of the * in-memory map. @@ -372,5 +404,13 @@ public final class DeviceStateRotationLockSettingsManager { public int hashCode() { return Objects.hash(mDeviceState, mIsSettable); } + + @Override + public String toString() { + return "SettableDeviceState{" + + "mDeviceState=" + mDeviceState + + ", mIsSettable=" + mIsSettable + + '}'; + } } } diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml index 6d8bf5fe9012..6aa00dfe507f 100644 --- a/packages/SettingsLib/res/values-af/strings.xml +++ b/packages/SettingsLib/res/values-af/strings.xml @@ -532,7 +532,7 @@ <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Wekkers en onthounotas"</string> <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Laat toe dat wekkers en onthounotas gestel word"</string> <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Wekkers en onthounotas"</string> - <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Laat hierdie program toe om wekkers te stel en tydsensitiewe handelinge te skeduleer. Dit laat die program op die agtergrond werk, wat meer batterykrag kan gebruik.\n\nAs hierdie toestemming af is, sal bestaande wekkers en tydgegronde geleenthede wat deur hierdie program geskeduleer is, nie werk nie."</string> + <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Laat hierdie app toe om wekkers te stel en tydsensitiewe handelinge te skeduleer. Dit laat die app op die agtergrond werk, wat meer batterykrag kan gebruik.\n\nAs hierdie toestemming af is, sal bestaande wekkers en tydgegronde geleenthede wat deur hierdie app geskeduleer is, nie werk nie."</string> <string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"skedule, wekker, onthounota, horlosie"</string> <string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Skakel aan"</string> <string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Skakel Moenie steur nie aan"</string> diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml index f39f7fc1779d..9ee3bcf75a3f 100644 --- a/packages/SettingsLib/res/values-bs/strings.xml +++ b/packages/SettingsLib/res/values-bs/strings.xml @@ -532,7 +532,7 @@ <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmi i podsjetnici"</string> <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Dozvoli postavljanje alarma i podsjetnika"</string> <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmi i podsjetnici"</string> - <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Dozvolite ovoj aplikaciji da postavlja alarme i zakazuje vremenski osjetljive radnje. Ovim će se omogućiti aplikaciji da radi u pozadini, čime se može povećati potrošnja baterije.\n\nAko je ovo odobrenje isključeno, postojeći alarmi i događaji zasnovani na vremenu koje je ova aplikacija zakazala neće funkcionirati."</string> + <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Dozvolite ovoj aplikaciji da postavlja alarme i zakazuje vremenski osjetljive radnje. Ovim će se omogućiti aplikaciji da radi u pozadini, čime se može povećati potrošnja baterije.\n\nAko je ovo odobrenje isključeno, postojeći alarmi i događaji zasnovani na vremenu, a koje je ova aplikacija zakazala, neće funkcionirati."</string> <string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"raspored, alarm, podsjetnik, sat"</string> <string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Uključi"</string> <string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Uključi način rada Ne ometaj"</string> diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml index 516a86457967..5caab29acce2 100644 --- a/packages/SettingsLib/res/values-ca/strings.xml +++ b/packages/SettingsLib/res/values-ca/strings.xml @@ -532,7 +532,7 @@ <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmes i recordatoris"</string> <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Permet la configuració d\'alarmes i recordatoris"</string> <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmes i recordatoris"</string> - <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Permet que aquesta aplicació configuri alarmes i programi accions. Això permet a l\'aplicació executar-se en segon pla i, per tant, és possible que consumeixi més bateria.\n\nSi aquest permís està desactivat, les alarmes i els esdeveniments que ja hagi programat l\'aplicació no funcionaran."</string> + <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Permet que aquesta aplicació configuri alarmes i programi accions a una hora determinada. Això permet a l\'aplicació executar-se en segon pla i, per tant, és possible que consumeixi més bateria.\n\nSi aquest permís està desactivat, les alarmes i els esdeveniments que ja hagi programat l\'aplicació no funcionaran."</string> <string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"programació, alarma, recordatori, rellotge"</string> <string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Activa"</string> <string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Activa el mode No molestis"</string> diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml index 34e59f31fb3f..a37b500ac5de 100644 --- a/packages/SettingsLib/res/values-eu/strings.xml +++ b/packages/SettingsLib/res/values-eu/strings.xml @@ -532,7 +532,7 @@ <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmak eta abisuak"</string> <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Eman alarmak eta abisuak ezartzeko baimena"</string> <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmak eta abisuak"</string> - <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Eman alarmak ezartzeko eta denbora-muga duten ekintzak programatzeko baimena aplikazioari. Hala, aplikazioak atzeko planoan funtzionatuko du, eta litekeena da bateria gehiago kontsumitzea.\n\nEz baduzu ematen baimen hori, ez dute funtzionatuko aplikazio honen bidez programatutako alarmek eta denbora-muga duten ekintzek."</string> + <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Eman alarmak ezartzeko eta denbora-muga duten ekintzak programatzeko baimena aplikazioari. Hala, aplikazioak atzeko planoan funtzionatuko du, eta litekeena da bateria gehiago kontsumitzea.\n\nBaimen hori ematen ez baduzu, ez dute funtzionatuko aplikazio honen bidez programatutako alarmek eta denbora-muga duten ekintzek."</string> <string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"programazioa, alarma, abisua, erlojua"</string> <string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Aktibatu"</string> <string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Aktibatu ez molestatzeko modua"</string> diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml index 779515894503..22b4fbf631da 100644 --- a/packages/SettingsLib/res/values-ne/strings.xml +++ b/packages/SettingsLib/res/values-ne/strings.xml @@ -530,7 +530,7 @@ <string name="okay" msgid="949938843324579502">"ठिक छ"</string> <string name="done" msgid="381184316122520313">"सम्पन्न भयो"</string> <string name="alarms_and_reminders_label" msgid="6918395649731424294">"अलार्म र रिमाइन्डरहरू"</string> - <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"अलार्म तथा रिमाइन्डर सेट गर्न दिइयोस्"</string> + <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"अलार्म तथा रिमाइन्डर सेट गर्ने अनुमति दिनुहोस्"</string> <string name="alarms_and_reminders_title" msgid="8819933264635406032">"अलार्म तथा रिमाइन्डर"</string> <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"यो एपलाई अलार्म सेट गर्ने र समयमै पूरा गर्नु पर्ने कारबाहीहरूको रुटिन बनाउने अनुमति दिनुहोस्। यो अनुमति दिइएको छ भने यो एप ब्याकग्राउन्डमा चल्छ र धेरै ब्याट्री खपत हुन्छ।\n\nयो अनुमति दिइएको छैन भने सेट गरिएका अलार्म बज्दैनन् र यो एपले तय गरेका गतिविधि चल्दैनन्।"</string> <string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"समयतालिका, अलार्म, रिमाइन्डर, घडी"</string> diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml index b18d81973536..96f845e58818 100644 --- a/packages/SettingsLib/res/values-pl/strings.xml +++ b/packages/SettingsLib/res/values-pl/strings.xml @@ -532,7 +532,7 @@ <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmy i przypomnienia"</string> <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Zezwalaj na ustawianie alarmów i przypomnień"</string> <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmy i przypomnienia"</string> - <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Zezwól na ustawianie alarmów i planowanie innych działań, w przypadku których czas jest istotny. Dzięki temu aplikacja będzie mogła działać w tle, co może zwiększyć wykorzystanie baterii.\n\nJeśli nie włączysz tych uprawnień, istniejące alarmy i zaplanowane wydarzenia z tej aplikacji nie będą działać."</string> + <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Zezwalaj tej aplikacji na ustawianie alarmów i planowanie działań, w przypadku których czas jest istotny. Aplikacja będzie mogła działać w tle, co może zwiększyć wykorzystanie baterii.\n\nJeśli nie włączysz tego uprawnienia, istniejące alarmy i zaplanowane wydarzenia z tej aplikacji nie będą działać."</string> <string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"harmonogram, alarm, przypomnienie, zegar"</string> <string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Włącz"</string> <string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Włącz tryb Nie przeszkadzać"</string> diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml index 816108e52bcf..da7dcc5fa268 100644 --- a/packages/SettingsLib/res/values-pt-rBR/strings.xml +++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml @@ -532,7 +532,7 @@ <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmes e lembretes"</string> <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Autorizar a definição de alarmes e lembretes"</string> <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmes e lembretes"</string> - <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Permitir que o app defina alarmes e programe ações mais imediatas. Essa opção autoriza o app a ser executado em segundo plano, o que pode consumir mais bateria.\n\nSe a permissão for desativada, os alarmes e eventos programados pelo app não funcionarão."</string> + <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Permitir que o app defina alarmes e programe ações com hora marcada. Essa opção autoriza o app a ser executado em segundo plano, o que pode consumir mais bateria.\n\nSe a permissão for desativada, os alarmes e eventos programados pelo app não funcionarão."</string> <string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"programar, alarme, lembrete, relógio"</string> <string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Ativar"</string> <string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Ativar o Não perturbe"</string> diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml index d9116fe49ada..f70fae0223f0 100644 --- a/packages/SettingsLib/res/values-pt-rPT/strings.xml +++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml @@ -530,7 +530,7 @@ <string name="okay" msgid="949938843324579502">"OK"</string> <string name="done" msgid="381184316122520313">"Concluir"</string> <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmes e lembretes"</string> - <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Permitir a definição de alarmes e lembretes"</string> + <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Permitir alarmes e lembretes"</string> <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmes e lembretes"</string> <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Permita que esta app defina alarmes e agende outras ações com base no tempo. Esta ação permite que a app seja executada em segundo plano, o que pode utilizar mais bateria.\n\nSe esta autorização estiver desativada, os alarmes existentes e os eventos com base no tempo agendados por esta app não funcionam."</string> <string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"agendar, alarme, lembrete, relógio"</string> diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml index 816108e52bcf..da7dcc5fa268 100644 --- a/packages/SettingsLib/res/values-pt/strings.xml +++ b/packages/SettingsLib/res/values-pt/strings.xml @@ -532,7 +532,7 @@ <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmes e lembretes"</string> <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Autorizar a definição de alarmes e lembretes"</string> <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmes e lembretes"</string> - <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Permitir que o app defina alarmes e programe ações mais imediatas. Essa opção autoriza o app a ser executado em segundo plano, o que pode consumir mais bateria.\n\nSe a permissão for desativada, os alarmes e eventos programados pelo app não funcionarão."</string> + <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Permitir que o app defina alarmes e programe ações com hora marcada. Essa opção autoriza o app a ser executado em segundo plano, o que pode consumir mais bateria.\n\nSe a permissão for desativada, os alarmes e eventos programados pelo app não funcionarão."</string> <string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"programar, alarme, lembrete, relógio"</string> <string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Ativar"</string> <string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Ativar o Não perturbe"</string> diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml index ea5faa8dee93..fabfcdec3ae9 100644 --- a/packages/SettingsLib/res/values-ro/strings.xml +++ b/packages/SettingsLib/res/values-ro/strings.xml @@ -532,7 +532,7 @@ <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarme și mementouri"</string> <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Permite setarea pentru alarme și mementouri"</string> <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarme și mementouri"</string> - <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Permite acestei aplicații să stabilească alarme și să planifice acțiuni dependente de timp. Astfel, aplicația poate să ruleze în fundal, fapt care ar putea consuma mai multă baterie.\n\nDacă permisiunea este dezactivată, alarmele și evenimentele dependente de timp planificate de aplicație nu vor funcționa."</string> + <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Permite acestei aplicații să seteze alarme și să planifice acțiuni care trebuie realizate în timp scurt. Astfel, aplicația poate să ruleze în fundal, ceea ce ar putea crește consumul de baterie.\n\nDacă permisiunea este dezactivată, alarmele și evenimentele dependente de timp planificate de aplicație nu vor funcționa."</string> <string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"programare, alarmă, memento, ceas"</string> <string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Activează"</string> <string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Activează Nu deranja"</string> diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml index 9e4f23cc5a56..fe49f87d1f15 100644 --- a/packages/SettingsLib/res/values-ru/strings.xml +++ b/packages/SettingsLib/res/values-ru/strings.xml @@ -532,7 +532,7 @@ <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Будильники и напоминания"</string> <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Разрешить установку будильников и напоминаний"</string> <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Будильники и напоминания"</string> - <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Если вы разрешите этому приложению устанавливать будильники и планировать на определенное время действия, оно будет работать в фоновом режиме. В таком случае заряд батареи может расходоваться быстрее.\n\nЕсли отключить эту настройку, текущие будильники и созданные приложением мероприятия перестанут запускаться."</string> + <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Вы можете разрешить этому приложению устанавливать будильники и планировать запуск действий в определенное время. В этом случае оно будет работать в фоновом режиме и быстрее расходовать заряд батареи.\n\nЕсли отключить это разрешение, текущие будильники и созданные приложением события перестанут запускаться."</string> <string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"установить, будильник, напоминание, часы"</string> <string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Включить"</string> <string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Включите режим \"Не беспокоить\""</string> diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml index 1d187039f369..3f6a44019b71 100644 --- a/packages/SettingsLib/res/values-sk/strings.xml +++ b/packages/SettingsLib/res/values-sk/strings.xml @@ -532,7 +532,7 @@ <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Budíky a pripomenutia"</string> <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Povoliť nastavovanie budíkov a pripomenutí"</string> <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Budíky a pripomenutia"</string> - <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Povoľte tejto aplikácii nastavovať budíky a plánovať akcie s časovým obmedzením. Aplikácii to umožní pracovať na pozadí, čo môže zvýšiť spotrebu batérie.\n\nAk je toto povolenie vypnuté, súčasné budíky a udalosti s časovým obmedzením naplánované touto aplikáciu nebudú fungovať."</string> + <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Povoľte tejto aplikácii nastavovať budíky a plánovať akcie s časovým obmedzením. Aplikácii to umožní pracovať na pozadí, čo môže zvýšiť spotrebu batérie.\n\nAk je toto povolenie vypnuté, existujúce budíky a udalosti s časovým obmedzením naplánované touto aplikáciu nebudú fungovať."</string> <string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"plán, budík, pripomenutie, hodiny"</string> <string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Zapnúť"</string> <string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Zapnite režim bez vyrušení"</string> diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml index 738e97e6d659..61229297036e 100644 --- a/packages/SettingsLib/res/values-tr/strings.xml +++ b/packages/SettingsLib/res/values-tr/strings.xml @@ -530,7 +530,7 @@ <string name="okay" msgid="949938843324579502">"Tamam"</string> <string name="done" msgid="381184316122520313">"Bitti"</string> <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmlar ve hatırlatıcılar"</string> - <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Alarm ve hatırlatıcı ayarlanmasına izin ver"</string> + <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Alarm ve hatırlatıcı ayarlamasına izin ver"</string> <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmlar ve hatırlatıcılar"</string> <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Bu uygulamanın alarm kurmasına ve zamana bağlı işlemler programlamasına izin verin. Bu izin, uygulamanın arka planda çalışmasına olanak sağlayarak daha fazla pil harcanmasına neden olabilir.\n\nBu izin verilmezse bu uygulama tarafından programlanmış mevcut alarmlar ve zamana bağlı etkinlikler çalışmaz."</string> <string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"program, alarm, hatırlatıcı, saat"</string> diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml index 50d292192727..4931c90915e4 100644 --- a/packages/SettingsLib/res/values-zh-rTW/strings.xml +++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml @@ -240,7 +240,7 @@ <string name="adb_wireless_error" msgid="721958772149779856">"錯誤"</string> <string name="adb_wireless_settings" msgid="2295017847215680229">"無線偵錯"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"如要查看並使用可用的裝置,請開啟無線偵錯功能"</string> - <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"使用 QR 圖碼配對裝置"</string> + <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"使用 QR code 配對裝置"</string> <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"使用 QR code 掃描器配對新裝置"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"使用配對碼配對裝置"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"使用六位數的配對碼配對新裝置"</string> diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManagerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManagerTest.java index 81006dd6b011..0fa15eb6bc0c 100644 --- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManagerTest.java +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManagerTest.java @@ -33,7 +33,10 @@ import androidx.test.runner.AndroidJUnit4; import com.android.internal.R; import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager.SettableDeviceState; +import com.google.common.truth.Expect; + import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -45,6 +48,8 @@ import java.util.List; @RunWith(AndroidJUnit4.class) public class DeviceStateRotationLockSettingsManagerTest { + @Rule public Expect mExpect = Expect.create(); + @Mock private Context mMockContext; @Mock private Resources mMockResources; @@ -117,4 +122,40 @@ public class DeviceStateRotationLockSettingsManagerTest { new SettableDeviceState(/* deviceState= */ 0, /* isSettable= */ false) ).inOrder(); } + + @Test + public void persistedInvalidIgnoredState_returnsDefaults() { + when(mMockResources.getStringArray( + R.array.config_perDeviceStateRotationLockDefaults)).thenReturn( + new String[]{"0:1", "1:0:2", "2:2"}); + // Here 2 has IGNORED, and in the defaults 1 has IGNORED. + persistSettings("0:2:2:0:1:2"); + DeviceStateRotationLockSettingsManager manager = + new DeviceStateRotationLockSettingsManager(mMockContext, mFakeSecureSettings); + + mExpect.that(manager.getRotationLockSetting(0)).isEqualTo(1); + mExpect.that(manager.getRotationLockSetting(1)).isEqualTo(2); + mExpect.that(manager.getRotationLockSetting(2)).isEqualTo(2); + } + + @Test + public void persistedValidValues_returnsPersistedValues() { + when(mMockResources.getStringArray( + R.array.config_perDeviceStateRotationLockDefaults)).thenReturn( + new String[]{"0:1", "1:0:2", "2:2"}); + persistSettings("0:2:1:0:2:1"); + DeviceStateRotationLockSettingsManager manager = + new DeviceStateRotationLockSettingsManager(mMockContext, mFakeSecureSettings); + + mExpect.that(manager.getRotationLockSetting(0)).isEqualTo(2); + mExpect.that(manager.getRotationLockSetting(1)).isEqualTo(1); + mExpect.that(manager.getRotationLockSetting(2)).isEqualTo(1); + } + + private void persistSettings(String value) { + mFakeSecureSettings.putStringForUser( + Settings.Secure.DEVICE_STATE_ROTATION_LOCK, + value, + UserHandle.USER_CURRENT); + } } diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt index 17a94b8639d0..296c2ae5cf99 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt @@ -419,7 +419,7 @@ class ActivityLaunchAnimator( internal val delegate: AnimationDelegate init { - delegate = AnimationDelegate(controller, callback, launchAnimator, listener) + delegate = AnimationDelegate(controller, callback, listener, launchAnimator) } @BinderThread @@ -446,10 +446,10 @@ class ActivityLaunchAnimator( constructor( private val controller: Controller, private val callback: Callback, - /** The animator to use to animate the window launch. */ - private val launchAnimator: LaunchAnimator = DEFAULT_LAUNCH_ANIMATOR, /** Listener for animation lifecycle events. */ - private val listener: Listener? = null + private val listener: Listener? = null, + /** The animator to use to animate the window launch. */ + private val launchAnimator: LaunchAnimator = DEFAULT_LAUNCH_ANIMATOR ) : RemoteAnimationDelegate<IRemoteAnimationFinishedCallback> { private val launchContainer = controller.launchContainer private val context = launchContainer.context diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/Expandable.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/Expandable.kt index 40a5e9794d37..c49a487c6766 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/Expandable.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/Expandable.kt @@ -26,7 +26,7 @@ interface Expandable { * currently not attached or visible). * * @param cujType the CUJ type from the [com.android.internal.jank.InteractionJankMonitor] - * associated to the launch that will use this controller. + * associated to the launch that will use this controller. */ fun activityLaunchController(cujType: Int? = null): ActivityLaunchAnimator.Controller? diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchAnimator.kt index 9668066be125..3417ffd6b83a 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchAnimator.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchAnimator.kt @@ -75,7 +75,7 @@ class LaunchAnimator(private val timings: Timings, private val interpolators: In * - Get the associated [Context]. * - Compute whether we are expanding fully above the launch container. * - Get to overlay to which we initially put the window background layer, until the opening - * window is made visible (see [openingWindowSyncView]). + * window is made visible (see [openingWindowSyncView]). * * This container can be changed to force this [Controller] to animate the expanding view * inside a different location, for instance to ensure correct layering during the diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchableView.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchableView.kt index b98b92219c33..ed8e70568b48 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchableView.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchableView.kt @@ -24,7 +24,7 @@ interface LaunchableView { * Set whether this view should block/postpone all calls to [View.setVisibility]. This ensures * that this view: * - remains invisible during the launch animation given that it is ghosted and already drawn - * somewhere else. + * somewhere else. * - remains invisible as long as a dialog expanded from it is shown. * - restores its expected visibility once the dialog expanded from it is dismissed. * diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteTransitionAdapter.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteTransitionAdapter.kt index 0e2d23b04a4f..6946e6bf88a8 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteTransitionAdapter.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteTransitionAdapter.kt @@ -182,9 +182,9 @@ class RemoteTransitionAdapter { * Represents a TransitionInfo object as an array of old-style targets * * @param wallpapers If true, this will return wallpaper targets; otherwise it returns - * non-wallpaper targets. + * non-wallpaper targets. * @param leashMap Temporary map of change leash -> launcher leash. Is an output, so should - * be populated by this function. If null, it is ignored. + * be populated by this function. If null, it is ignored. */ fun wrapTargets( info: TransitionInfo, diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ShadeInterpolation.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ShadeInterpolation.kt index a96f893a8db4..b89a8b0e0272 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/ShadeInterpolation.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ShadeInterpolation.kt @@ -6,6 +6,7 @@ object ShadeInterpolation { /** * Interpolate alpha for notification background scrim during shade expansion. + * * @param fraction Shade expansion fraction */ @JvmStatic @@ -16,6 +17,7 @@ object ShadeInterpolation { /** * Interpolate alpha for shade content during shade expansion. + * * @param fraction Shade expansion fraction */ @JvmStatic diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt index 341784e26257..468a8b10bc01 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt @@ -161,7 +161,6 @@ class TextInterpolator(layout: Layout) { * This API is useful to continue animation from the middle of the state. For example, if you * animate weight from 200 to 400, then if you want to move back to 200 at the half of the * animation, it will look like - * * <pre> <code> * ``` * val interp = TextInterpolator(layout) @@ -497,7 +496,9 @@ class TextInterpolator(layout: Layout) { count, layout.textDirectionHeuristic, paint - ) { _, _, glyphs, _ -> runs.add(glyphs) } + ) { _, _, glyphs, _ -> + runs.add(glyphs) + } out.add(runs) if (lineNo > 0) { diff --git a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleShader.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleShader.kt index 0b842ad5331c..5ed723bdd254 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleShader.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleShader.kt @@ -25,7 +25,6 @@ import com.android.systemui.surfaceeffects.shaderutil.ShaderUtilLibrary /** * Shader class that renders an expanding ripple effect. The ripple contains three elements: - * * 1. an expanding filled [RippleShape] that appears in the beginning and quickly fades away * 2. an expanding ring that appears throughout the effect * 3. an expanding ring-shaped area that reveals noise over #2. @@ -311,6 +310,7 @@ class RippleShader(rippleShape: RippleShape = RippleShape.CIRCLE) : * Parameters used for fade in and outs of the ripple. * * <p>Note that all the fade in/ outs are "linear" progression. + * * ``` * (opacity) * 1 @@ -325,6 +325,7 @@ class RippleShader(rippleShape: RippleShape = RippleShape.CIRCLE) : * fadeIn fadeOut * Start & End Start & End * ``` + * * <p>If no fade in/ out is needed, set [fadeInStart] and [fadeInEnd] to 0; [fadeOutStart] and * [fadeOutEnd] to 1. */ diff --git a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseAnimationConfig.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseAnimationConfig.kt index 79bc2f432ded..89871fa7d875 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseAnimationConfig.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseAnimationConfig.kt @@ -30,12 +30,14 @@ data class TurbulenceNoiseAnimationConfig( * Noise move speed variables. * * Its sign determines the direction; magnitude determines the speed. <ul> + * * ``` * <li> [noiseMoveSpeedX] positive: right to left; negative: left to right. * <li> [noiseMoveSpeedY] positive: bottom to top; negative: top to bottom. * <li> [noiseMoveSpeedZ] its sign doesn't matter much, as it moves in Z direction. Use it * to add turbulence in place. * ``` + * * </ul> */ val noiseMoveSpeedX: Float = 0f, diff --git a/packages/SystemUI/animation/src/com/android/systemui/util/AnimatorExtensions.kt b/packages/SystemUI/animation/src/com/android/systemui/util/AnimatorExtensions.kt new file mode 100644 index 000000000000..35dbb89ad801 --- /dev/null +++ b/packages/SystemUI/animation/src/com/android/systemui/util/AnimatorExtensions.kt @@ -0,0 +1,80 @@ +/* + * 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.systemui.util + +import androidx.core.animation.Animator + +/** + * Add an action which will be invoked when the animation has ended. + * + * @return the [Animator.AnimatorListener] added to the Animator + * @see Animator.end + */ +inline fun Animator.doOnEnd( + crossinline action: (animator: Animator) -> Unit +): Animator.AnimatorListener = addListener(onEnd = action) + +/** + * Add an action which will be invoked when the animation has started. + * + * @return the [Animator.AnimatorListener] added to the Animator + * @see Animator.start + */ +inline fun Animator.doOnStart( + crossinline action: (animator: Animator) -> Unit +): Animator.AnimatorListener = addListener(onStart = action) + +/** + * Add an action which will be invoked when the animation has been cancelled. + * + * @return the [Animator.AnimatorListener] added to the Animator + * @see Animator.cancel + */ +inline fun Animator.doOnCancel( + crossinline action: (animator: Animator) -> Unit +): Animator.AnimatorListener = addListener(onCancel = action) + +/** + * Add an action which will be invoked when the animation has repeated. + * + * @return the [Animator.AnimatorListener] added to the Animator + */ +inline fun Animator.doOnRepeat( + crossinline action: (animator: Animator) -> Unit +): Animator.AnimatorListener = addListener(onRepeat = action) + +/** + * Add a listener to this Animator using the provided actions. + * + * @return the [Animator.AnimatorListener] added to the Animator + */ +inline fun Animator.addListener( + crossinline onEnd: (animator: Animator) -> Unit = {}, + crossinline onStart: (animator: Animator) -> Unit = {}, + crossinline onCancel: (animator: Animator) -> Unit = {}, + crossinline onRepeat: (animator: Animator) -> Unit = {} +): Animator.AnimatorListener { + val listener = + object : Animator.AnimatorListener { + override fun onAnimationRepeat(animator: Animator) = onRepeat(animator) + override fun onAnimationEnd(animator: Animator) = onEnd(animator) + override fun onAnimationCancel(animator: Animator) = onCancel(animator) + override fun onAnimationStart(animator: Animator) = onStart(animator) + } + addListener(listener) + return listener +} diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/DemotingTestWithoutBugDetector.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/DemotingTestWithoutBugDetector.kt new file mode 100644 index 000000000000..f64ea4561906 --- /dev/null +++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/DemotingTestWithoutBugDetector.kt @@ -0,0 +1,77 @@ +/* + * 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.systemui.lint + +import com.android.tools.lint.client.api.UElementHandler +import com.android.tools.lint.detector.api.Category +import com.android.tools.lint.detector.api.Detector +import com.android.tools.lint.detector.api.Implementation +import com.android.tools.lint.detector.api.Issue +import com.android.tools.lint.detector.api.JavaContext +import com.android.tools.lint.detector.api.Scope +import com.android.tools.lint.detector.api.Severity +import com.android.tools.lint.detector.api.SourceCodeScanner +import org.jetbrains.uast.UAnnotation +import org.jetbrains.uast.UElement + +class DemotingTestWithoutBugDetector : Detector(), SourceCodeScanner { + override fun getApplicableUastTypes(): List<Class<out UElement>> { + return listOf(UAnnotation::class.java) + } + + override fun createUastHandler(context: JavaContext): UElementHandler { + return object : UElementHandler() { + override fun visitAnnotation(node: UAnnotation) { + if (node.qualifiedName !in DEMOTING_ANNOTATION) { + return + } + val bugId = node.findAttributeValue("bugId")!!.evaluate() as Int + if (bugId <= 0) { + val location = context.getLocation(node) + val message = "Please attach a bug id to track demoted test" + context.report(ISSUE, node, location, message) + } + } + } + } + + companion object { + val DEMOTING_ANNOTATION = + listOf("androidx.test.filters.FlakyTest", "android.platform.test.annotations.FlakyTest") + + @JvmField + val ISSUE: Issue = + Issue.create( + id = "DemotingTestWithoutBug", + briefDescription = "Demoting a test without attaching a bug.", + explanation = + """ + Annotations (`@FlakyTest`) demote tests to an unmonitored \ + test suite. Please set the `bugId` field in such annotations to track \ + the test status. + """, + category = Category.TESTING, + priority = 8, + severity = Severity.WARNING, + implementation = + Implementation( + DemotingTestWithoutBugDetector::class.java, + Scope.JAVA_FILE_SCOPE + ) + ) + } +} diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt index 84f70502fa45..387b67d231cd 100644 --- a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt +++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt @@ -39,7 +39,8 @@ class SystemUIIssueRegistry : IssueRegistry() { RegisterReceiverViaContextDetector.ISSUE, SoftwareBitmapDetector.ISSUE, NonInjectedServiceDetector.ISSUE, - StaticSettingsProviderDetector.ISSUE + StaticSettingsProviderDetector.ISSUE, + DemotingTestWithoutBugDetector.ISSUE ) override val api: Int diff --git a/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/CleanArchitectureDependencyViolationDetectorTest.kt b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/CleanArchitectureDependencyViolationDetectorTest.kt index a4b59fd8e086..a5f832a17de4 100644 --- a/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/CleanArchitectureDependencyViolationDetectorTest.kt +++ b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/CleanArchitectureDependencyViolationDetectorTest.kt @@ -64,7 +64,8 @@ class CleanArchitectureDependencyViolationDetectorTest : SystemUILintDetectorTes class BadClass( private val viewModel: ViewModel, ) - """.trimIndent() + """ + .trimIndent() ) ) .issues( @@ -98,7 +99,8 @@ class CleanArchitectureDependencyViolationDetectorTest : SystemUILintDetectorTes class BadClass( private val repository: Repository, ) - """.trimIndent() + """ + .trimIndent() ) ) .issues( @@ -136,7 +138,8 @@ class CleanArchitectureDependencyViolationDetectorTest : SystemUILintDetectorTes private val interactor: Interactor, private val viewmodel: ViewModel, ) - """.trimIndent() + """ + .trimIndent() ) ) .issues( @@ -176,7 +179,8 @@ class CleanArchitectureDependencyViolationDetectorTest : SystemUILintDetectorTes class BadClass( private val interactor: Interactor, ) - """.trimIndent() + """ + .trimIndent() ) ) .issues( @@ -207,7 +211,8 @@ class CleanArchitectureDependencyViolationDetectorTest : SystemUILintDetectorTes data class Model( private val name: String, ) - """.trimIndent() + """ + .trimIndent() ) private val REPOSITORY_FILE = TestFiles.kotlin( @@ -228,7 +233,8 @@ class CleanArchitectureDependencyViolationDetectorTest : SystemUILintDetectorTes return models } } - """.trimIndent() + """ + .trimIndent() ) private val INTERACTOR_FILE = TestFiles.kotlin( @@ -245,7 +251,8 @@ class CleanArchitectureDependencyViolationDetectorTest : SystemUILintDetectorTes return repository.getModels() } } - """.trimIndent() + """ + .trimIndent() ) private val VIEW_MODEL_FILE = TestFiles.kotlin( @@ -262,7 +269,8 @@ class CleanArchitectureDependencyViolationDetectorTest : SystemUILintDetectorTes return interactor.getModels().map { model -> model.name } } } - """.trimIndent() + """ + .trimIndent() ) private val NON_CLEAN_ARCHITECTURE_FILE = TestFiles.kotlin( @@ -282,7 +290,8 @@ class CleanArchitectureDependencyViolationDetectorTest : SystemUILintDetectorTes ) } } - """.trimIndent() + """ + .trimIndent() ) private val LEGITIMATE_FILES = arrayOf( diff --git a/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/DemotingTestWithoutBugDetectorTest.kt b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/DemotingTestWithoutBugDetectorTest.kt new file mode 100644 index 000000000000..557c300635eb --- /dev/null +++ b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/DemotingTestWithoutBugDetectorTest.kt @@ -0,0 +1,151 @@ +/* + * 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.systemui.lint + +import com.android.tools.lint.checks.infrastructure.TestFile +import com.android.tools.lint.checks.infrastructure.TestFiles +import com.android.tools.lint.detector.api.Detector +import com.android.tools.lint.detector.api.Issue +import org.junit.Test + +class DemotingTestWithoutBugDetectorTest : SystemUILintDetectorTest() { + + override fun getDetector(): Detector = DemotingTestWithoutBugDetector() + override fun getIssues(): List<Issue> = listOf(DemotingTestWithoutBugDetector.ISSUE) + + @Test + fun testMarkFlaky_withBugId() { + lint() + .files( + TestFiles.java( + """ + package test.pkg; + import androidx.test.filters.FlakyTest; + + @FlakyTest(bugId = 123) + public class TestClass { + public void testCase() {} + } + """ + ) + .indented(), + *stubs + ) + .issues(DemotingTestWithoutBugDetector.ISSUE) + .run() + .expectClean() + + lint() + .files( + TestFiles.java( + """ + package test.pkg; + import android.platform.test.annotations.FlakyTest; + + @FlakyTest(bugId = 123) + public class TestClass { + public void testCase() {} + } + """ + ) + .indented(), + *stubs + ) + .issues(DemotingTestWithoutBugDetector.ISSUE) + .run() + .expectClean() + } + + @Test + fun testMarkFlaky_withoutBugId() { + lint() + .files( + TestFiles.java( + """ + package test.pkg; + import androidx.test.filters.FlakyTest; + + @FlakyTest + public class TestClass { + public void testCase() {} + } + """ + ) + .indented(), + *stubs + ) + .issues(DemotingTestWithoutBugDetector.ISSUE) + .run() + .expect( + """ + src/test/pkg/TestClass.java:4: Warning: Please attach a bug id to track demoted test [DemotingTestWithoutBug] + @FlakyTest + ~~~~~~~~~~ + 0 errors, 1 warnings + """ + ) + + lint() + .files( + TestFiles.java( + """ + package test.pkg; + import android.platform.test.annotations.FlakyTest; + + @FlakyTest + public class TestClass { + public void testCase() {} + } + """ + ) + .indented(), + *stubs + ) + .issues(DemotingTestWithoutBugDetector.ISSUE) + .run() + .expect( + """ + src/test/pkg/TestClass.java:4: Warning: Please attach a bug id to track demoted test [DemotingTestWithoutBug] + @FlakyTest + ~~~~~~~~~~ + 0 errors, 1 warnings + """ + ) + } + + private val filtersFlakyTestStub: TestFile = + java( + """ + package androidx.test.filters; + + public @interface FlakyTest { + int bugId() default -1; + } + """ + ) + private val annotationsFlakyTestStub: TestFile = + java( + """ + package android.platform.test.annotations; + + public @interface FlakyTest { + int bugId() default -1; + } + """ + ) + private val stubs = arrayOf(filtersFlakyTestStub, annotationsFlakyTestStub) +} diff --git a/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/DumpableNotRegisteredDetectorTest.kt b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/DumpableNotRegisteredDetectorTest.kt index 3d6cbc749569..95b700543f1e 100644 --- a/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/DumpableNotRegisteredDetectorTest.kt +++ b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/DumpableNotRegisteredDetectorTest.kt @@ -37,7 +37,8 @@ class DumpableNotRegisteredDetectorTest : SystemUILintDetectorTest() { class SomeClass() { } - """.trimIndent() + """ + .trimIndent() ), *stubs, ) @@ -67,7 +68,8 @@ class DumpableNotRegisteredDetectorTest : SystemUILintDetectorTest() { pw.println("testDump"); } } - """.trimIndent() + """ + .trimIndent() ), *stubs, ) @@ -97,7 +99,8 @@ class DumpableNotRegisteredDetectorTest : SystemUILintDetectorTest() { pw.println("testDump"); } } - """.trimIndent() + """ + .trimIndent() ), *stubs, ) @@ -127,7 +130,8 @@ class DumpableNotRegisteredDetectorTest : SystemUILintDetectorTest() { pw.println("testDump"); } } - """.trimIndent() + """ + .trimIndent() ), *stubs, ) diff --git a/packages/SystemUI/compose/core/src/com/android/compose/SystemUiController.kt b/packages/SystemUI/compose/core/src/com/android/compose/SystemUiController.kt index a02954ab4800..08ab1462b161 100644 --- a/packages/SystemUI/compose/core/src/com/android/compose/SystemUiController.kt +++ b/packages/SystemUI/compose/core/src/com/android/compose/SystemUiController.kt @@ -78,11 +78,10 @@ interface SystemUiController { * Set the status bar color. * * @param color The **desired** [Color] to set. This may require modification if running on an - * API level that only supports white status bar icons. + * API level that only supports white status bar icons. * @param darkIcons Whether dark status bar icons would be preferable. * @param transformColorForLightContent A lambda which will be invoked to transform [color] if - * dark icons were requested but are not available. Defaults to applying a black scrim. - * + * dark icons were requested but are not available. Defaults to applying a black scrim. * @see statusBarDarkContentEnabled */ fun setStatusBarColor( @@ -95,16 +94,15 @@ interface SystemUiController { * Set the navigation bar color. * * @param color The **desired** [Color] to set. This may require modification if running on an - * API level that only supports white navigation bar icons. Additionally this will be ignored - * and [Color.Transparent] will be used on API 29+ where gesture navigation is preferred or the - * system UI automatically applies background protection in other navigation modes. + * API level that only supports white navigation bar icons. Additionally this will be ignored + * and [Color.Transparent] will be used on API 29+ where gesture navigation is preferred or + * the system UI automatically applies background protection in other navigation modes. * @param darkIcons Whether dark navigation bar icons would be preferable. * @param navigationBarContrastEnforced Whether the system should ensure that the navigation bar - * has enough contrast when a fully transparent background is requested. Only supported on API - * 29+. + * has enough contrast when a fully transparent background is requested. Only supported on API + * 29+. * @param transformColorForLightContent A lambda which will be invoked to transform [color] if - * dark icons were requested but are not available. Defaults to applying a black scrim. - * + * dark icons were requested but are not available. Defaults to applying a black scrim. * @see navigationBarDarkContentEnabled * @see navigationBarContrastEnforced */ diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/Expandable.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/Expandable.kt index cfc38df08b0a..d4a81f9c765d 100644 --- a/packages/SystemUI/compose/core/src/com/android/compose/animation/Expandable.kt +++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/Expandable.kt @@ -255,7 +255,9 @@ fun Expandable( .onGloballyPositioned { controller.boundsInComposeViewRoot.value = it.boundsInRoot() } - ) { wrappedContent(controller.expandable) } + ) { + wrappedContent(controller.expandable) + } } else -> { val clickModifier = diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/ExpandableController.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/ExpandableController.kt index edb10c7d392f..767756e17747 100644 --- a/packages/SystemUI/compose/core/src/com/android/compose/animation/ExpandableController.kt +++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/ExpandableController.kt @@ -156,9 +156,9 @@ internal class ExpandableControllerImpl( * Create a [LaunchAnimator.Controller] that is going to be used to drive an activity or dialog * animation. This controller will: * 1. Compute the start/end animation state using [boundsInComposeViewRoot] and the location of - * composeViewRoot on the screen. + * composeViewRoot on the screen. * 2. Update [animatorState] with the current animation state if we are animating, or null - * otherwise. + * otherwise. */ private fun launchController(): LaunchAnimator.Controller { return object : LaunchAnimator.Controller { diff --git a/packages/SystemUI/compose/core/src/com/android/compose/pager/Pager.kt b/packages/SystemUI/compose/core/src/com/android/compose/pager/Pager.kt index eb9d62506faa..a80a1f934dab 100644 --- a/packages/SystemUI/compose/core/src/com/android/compose/pager/Pager.kt +++ b/packages/SystemUI/compose/core/src/com/android/compose/pager/Pager.kt @@ -86,21 +86,20 @@ object PagerDefaults { /** * A horizontally scrolling layout that allows users to flip between items to the left and right. * - * @sample com.google.accompanist.sample.pager.HorizontalPagerSample - * * @param count the number of pages. * @param modifier the modifier to apply to this layout. * @param state the state object to be used to control or observe the pager's state. * @param reverseLayout reverse the direction of scrolling and layout, when `true` items will be - * composed from the end to the start and [PagerState.currentPage] == 0 will mean the first item is - * located at the end. + * composed from the end to the start and [PagerState.currentPage] == 0 will mean the first item + * is located at the end. * @param itemSpacing horizontal spacing to add between items. * @param flingBehavior logic describing fling behavior. * @param key the scroll position will be maintained based on the key, which means if you add/remove - * items before the current visible item the item with the given key will be kept as the first - * visible one. + * items before the current visible item the item with the given key will be kept as the first + * visible one. * @param content a block which describes the content. Inside this block you can reference - * [PagerScope.currentPage] and other properties in [PagerScope]. + * [PagerScope.currentPage] and other properties in [PagerScope]. + * @sample com.google.accompanist.sample.pager.HorizontalPagerSample */ @ExperimentalPagerApi @Composable @@ -134,21 +133,20 @@ fun HorizontalPager( /** * A vertically scrolling layout that allows users to flip between items to the top and bottom. * - * @sample com.google.accompanist.sample.pager.VerticalPagerSample - * * @param count the number of pages. * @param modifier the modifier to apply to this layout. * @param state the state object to be used to control or observe the pager's state. * @param reverseLayout reverse the direction of scrolling and layout, when `true` items will be - * composed from the bottom to the top and [PagerState.currentPage] == 0 will mean the first item is - * located at the bottom. + * composed from the bottom to the top and [PagerState.currentPage] == 0 will mean the first item + * is located at the bottom. * @param itemSpacing vertical spacing to add between items. * @param flingBehavior logic describing fling behavior. * @param key the scroll position will be maintained based on the key, which means if you add/remove - * items before the current visible item the item with the given key will be kept as the first - * visible one. + * items before the current visible item the item with the given key will be kept as the first + * visible one. * @param content a block which describes the content. Inside this block you can reference - * [PagerScope.currentPage] and other properties in [PagerScope]. + * [PagerScope.currentPage] and other properties in [PagerScope]. + * @sample com.google.accompanist.sample.pager.VerticalPagerSample */ @ExperimentalPagerApi @Composable @@ -246,7 +244,9 @@ internal fun Pager( // Constraint the content to be <= than the size of the pager. .fillParentMaxHeight() .wrapContentSize() - ) { pagerScope.content(page) } + ) { + pagerScope.content(page) + } } } } else { @@ -272,7 +272,9 @@ internal fun Pager( // Constraint the content to be <= than the size of the pager. .fillParentMaxWidth() .wrapContentSize() - ) { pagerScope.content(page) } + ) { + pagerScope.content(page) + } } } } diff --git a/packages/SystemUI/compose/core/src/com/android/compose/pager/PagerState.kt b/packages/SystemUI/compose/core/src/com/android/compose/pager/PagerState.kt index 2e6ae78b43c7..1822a68f1e77 100644 --- a/packages/SystemUI/compose/core/src/com/android/compose/pager/PagerState.kt +++ b/packages/SystemUI/compose/core/src/com/android/compose/pager/PagerState.kt @@ -198,7 +198,7 @@ class PagerState( * * @param page the page to animate to. Must be between 0 and [pageCount] (inclusive). * @param pageOffset the percentage of the page width to offset, from the start of [page]. Must - * be in the range 0f..1f. + * be in the range 0f..1f. */ suspend fun animateScrollToPage( @IntRange(from = 0) page: Int, diff --git a/packages/SystemUI/compose/core/src/com/android/compose/pager/SnappingFlingBehavior.kt b/packages/SystemUI/compose/core/src/com/android/compose/pager/SnappingFlingBehavior.kt index 23122de56758..98140295306a 100644 --- a/packages/SystemUI/compose/core/src/com/android/compose/pager/SnappingFlingBehavior.kt +++ b/packages/SystemUI/compose/core/src/com/android/compose/pager/SnappingFlingBehavior.kt @@ -44,11 +44,11 @@ internal object SnappingFlingBehaviorDefaults { /** * Create and remember a snapping [FlingBehavior] to be used with [LazyListState]. * - * TODO: move this to a new module and make it public - * * @param lazyListState The [LazyListState] to update. * @param decayAnimationSpec The decay animation spec to use for decayed flings. * @param snapAnimationSpec The animation spec to use when snapping. + * + * TODO: move this to a new module and make it public */ @Composable internal fun rememberSnappingFlingBehavior( diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt b/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt index 3eeadae5385f..a74e56b6e2f2 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt @@ -60,7 +60,7 @@ import com.android.systemui.people.ui.viewmodel.PeopleViewModel * * @param viewModel the [PeopleViewModel] that should be composed. * @param onResult the callback called with the result of this screen. Callers should usually finish - * the Activity/Fragment/View hosting this Composable once a result is available. + * the Activity/Fragment/View hosting this Composable once a result is available. */ @Composable fun PeopleScreen( diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreenEmpty.kt b/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreenEmpty.kt index 3f590df697cb..0484ff475cdf 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreenEmpty.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreenEmpty.kt @@ -79,7 +79,9 @@ internal fun PeopleScreenEmpty( containerColor = androidColors.colorAccentPrimary, contentColor = androidColors.textColorOnAccent, ) - ) { Text(stringResource(R.string.got_it)) } + ) { + Text(stringResource(R.string.got_it)) + } } } diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderContract.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderContract.kt index c120876a7a63..0d880759bd09 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderContract.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderContract.kt @@ -51,7 +51,7 @@ object CustomizationProviderContract { * * Supported operations: * - Query - to know which slots are available, query the [SlotTable.URI] [Uri]. The result - * set will contain rows with the [SlotTable.Columns] columns. + * set will contain rows with the [SlotTable.Columns] columns. */ object SlotTable { const val TABLE_NAME = "slots" @@ -74,8 +74,8 @@ object CustomizationProviderContract { * * Supported operations: * - Query - to know about all the affordances that are available on the device, regardless - * of which ones are currently selected, query the [AffordanceTable.URI] [Uri]. The result - * set will contain rows, each with the columns specified in [AffordanceTable.Columns]. + * of which ones are currently selected, query the [AffordanceTable.URI] [Uri]. The result + * set will contain rows, each with the columns specified in [AffordanceTable.Columns]. */ object AffordanceTable { const val TABLE_NAME = "affordances" @@ -128,14 +128,14 @@ object CustomizationProviderContract { * * Supported operations: * - Insert - to insert an affordance and place it in a slot, insert values for the columns - * into the [SelectionTable.URI] [Uri]. The maximum capacity rule is enforced by the system. - * Selecting a new affordance for a slot that is already full will automatically remove the - * oldest affordance from the slot. + * into the [SelectionTable.URI] [Uri]. The maximum capacity rule is enforced by the + * system. Selecting a new affordance for a slot that is already full will automatically + * remove the oldest affordance from the slot. * - Query - to know which affordances are set on which slots, query the - * [SelectionTable.URI] [Uri]. The result set will contain rows, each of which with the - * columns from [SelectionTable.Columns]. + * [SelectionTable.URI] [Uri]. The result set will contain rows, each of which with the + * columns from [SelectionTable.Columns]. * - Delete - to unselect an affordance, removing it from a slot, delete from the - * [SelectionTable.URI] [Uri], passing in values for each column. + * [SelectionTable.URI] [Uri], passing in values for each column. */ object SelectionTable { const val TABLE_NAME = "selections" @@ -160,7 +160,7 @@ object CustomizationProviderContract { * * Supported operations: * - Query - to know the values of flags, query the [FlagsTable.URI] [Uri]. The result set will - * contain rows, each of which with the columns from [FlagsTable.Columns]. + * contain rows, each of which with the columns from [FlagsTable.Columns]. */ object FlagsTable { const val TABLE_NAME = "flags" diff --git a/packages/SystemUI/ktfmt_includes.txt b/packages/SystemUI/ktfmt_includes.txt index 943d7996dd89..8a6fc5dc53f1 100644 --- a/packages/SystemUI/ktfmt_includes.txt +++ b/packages/SystemUI/ktfmt_includes.txt @@ -1,28 +1,20 @@ +packages/SystemUI -packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt -packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt --packages/SystemUI/checks/src/com/android/internal/systemui/lint/BindServiceViaContextDetector.kt -packages/SystemUI/checks/src/com/android/internal/systemui/lint/BroadcastSentViaContextDetector.kt --packages/SystemUI/checks/src/com/android/internal/systemui/lint/GetMainLooperViaContextDetector.kt -packages/SystemUI/checks/src/com/android/internal/systemui/lint/RegisterReceiverViaContextDetector.kt -packages/SystemUI/checks/src/com/android/internal/systemui/lint/SoftwareBitmapDetector.kt --packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt --packages/SystemUI/checks/tests/com/android/systemui/lint/BindServiceViaContextDetectorTest.kt --packages/SystemUI/checks/tests/com/android/systemui/lint/BroadcastSentViaContextDetectorTest.kt --packages/SystemUI/checks/tests/com/android/systemui/lint/GetMainLooperViaContextDetectorTest.kt --packages/SystemUI/checks/tests/com/android/systemui/lint/RegisterReceiverViaContextDetectorTest.kt --packages/SystemUI/checks/tests/com/android/systemui/lint/SoftwareBitmapDetectorTest.kt +-packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt +-packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt -packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt --packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSContainerController.kt +-packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/View.kt -packages/SystemUI/shared/src/com/android/systemui/flags/Flag.kt -packages/SystemUI/shared/src/com/android/systemui/flags/FlagListenable.kt -packages/SystemUI/shared/src/com/android/systemui/flags/FlagManager.kt -packages/SystemUI/shared/src/com/android/systemui/flags/FlagSerializer.kt -packages/SystemUI/shared/src/com/android/systemui/flags/FlagSettingsHelper.kt -packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimator.kt --packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt --packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt --packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt +-packages/SystemUI/shared/src/com/android/systemui/shared/regionsampling/RegionDarkness.kt -packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButtonPositionCalculator.kt -packages/SystemUI/shared/src/com/android/systemui/shared/system/UncaughtExceptionPreHandlerManager.kt -packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/SmartspaceState.kt @@ -35,8 +27,6 @@ -packages/SystemUI/src/com/android/keyguard/BouncerPanelExpansionCalculator.kt -packages/SystemUI/src/com/android/keyguard/ClockEventController.kt -packages/SystemUI/src/com/android/keyguard/KeyguardBiometricLockoutLogger.kt --packages/SystemUI/src/com/android/keyguard/KeyguardListenModel.kt --packages/SystemUI/src/com/android/keyguard/KeyguardListenQueue.kt -packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt -packages/SystemUI/src/com/android/keyguard/KeyguardUserSwitcherAnchor.kt -packages/SystemUI/src/com/android/keyguard/clock/ClockPalette.kt @@ -65,12 +55,10 @@ -packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceView.kt -packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt -packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.kt --packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricIconController.kt -packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt -packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt -packages/SystemUI/src/com/android/systemui/biometrics/BiometricDisplayListener.kt -packages/SystemUI/src/com/android/systemui/biometrics/DwellRippleShader.kt --packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.kt -packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt -packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpView.kt -packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.kt @@ -80,7 +68,6 @@ -packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherView.kt -packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherViewController.kt -packages/SystemUI/src/com/android/systemui/biometrics/UdfpsHapticsSimulator.kt --packages/SystemUI/src/com/android/systemui/biometrics/UdfpsOverlayParams.kt -packages/SystemUI/src/com/android/systemui/biometrics/UdfpsShell.kt -packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.kt -packages/SystemUI/src/com/android/systemui/biometrics/Utils.kt @@ -93,8 +80,6 @@ -packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt -packages/SystemUI/src/com/android/systemui/broadcast/logging/BroadcastDispatcherLogger.kt -packages/SystemUI/src/com/android/systemui/camera/CameraGestureHelper.kt --packages/SystemUI/src/com/android/systemui/camera/CameraIntents.kt --packages/SystemUI/src/com/android/systemui/camera/CameraIntentsWrapper.kt -packages/SystemUI/src/com/android/systemui/charging/WiredChargingRippleController.kt -packages/SystemUI/src/com/android/systemui/controls/ControlStatus.kt -packages/SystemUI/src/com/android/systemui/controls/ControlsMetricsLogger.kt @@ -102,7 +87,6 @@ -packages/SystemUI/src/com/android/systemui/controls/ControlsServiceInfo.kt -packages/SystemUI/src/com/android/systemui/controls/CustomIconCache.kt -packages/SystemUI/src/com/android/systemui/controls/TooltipManager.kt --packages/SystemUI/src/com/android/systemui/controls/controller/AuxiliaryPersistenceWrapper.kt -packages/SystemUI/src/com/android/systemui/controls/controller/ControlInfo.kt -packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingController.kt -packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt @@ -132,6 +116,7 @@ -packages/SystemUI/src/com/android/systemui/controls/management/FavoritesModel.kt -packages/SystemUI/src/com/android/systemui/controls/management/ManagementPageIndicator.kt -packages/SystemUI/src/com/android/systemui/controls/management/StructureAdapter.kt +-packages/SystemUI/src/com/android/systemui/controls/start/ControlsStartable.kt -packages/SystemUI/src/com/android/systemui/controls/ui/Behavior.kt -packages/SystemUI/src/com/android/systemui/controls/ui/ChallengeDialogs.kt -packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt @@ -162,7 +147,6 @@ -packages/SystemUI/src/com/android/systemui/decor/RoundedCornerDecorProviderImpl.kt -packages/SystemUI/src/com/android/systemui/decor/RoundedCornerResDelegate.kt -packages/SystemUI/src/com/android/systemui/demomode/DemoModeAvailabilityTracker.kt --packages/SystemUI/src/com/android/systemui/demomode/DemoModeController.kt -packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt -packages/SystemUI/src/com/android/systemui/doze/util/BurnInHelper.kt -packages/SystemUI/src/com/android/systemui/dreams/smartspace/DreamSmartspaceController.kt @@ -172,20 +156,16 @@ -packages/SystemUI/src/com/android/systemui/dump/LogBufferEulogizer.kt -packages/SystemUI/src/com/android/systemui/dump/LogBufferFreezer.kt -packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.kt +-packages/SystemUI/src/com/android/systemui/flags/Flags.kt -packages/SystemUI/src/com/android/systemui/flags/ServerFlagReader.kt -packages/SystemUI/src/com/android/systemui/flags/SystemPropertiesHelper.kt -packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt --packages/SystemUI/src/com/android/systemui/log/LogBuffer.kt +-packages/SystemUI/src/com/android/systemui/keyguard/LifecycleScreenStatusProvider.kt +-packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceConfig.kt +-packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceCoreStartable.kt +-packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt -packages/SystemUI/src/com/android/systemui/log/LogBufferFactory.kt --packages/SystemUI/src/com/android/systemui/log/LogLevel.kt --packages/SystemUI/src/com/android/systemui/log/LogMessage.kt --packages/SystemUI/src/com/android/systemui/log/LogMessageImpl.kt --packages/SystemUI/src/com/android/systemui/log/LogcatEchoTracker.kt --packages/SystemUI/src/com/android/systemui/log/LogcatEchoTrackerDebug.kt --packages/SystemUI/src/com/android/systemui/log/LogcatEchoTrackerProd.kt --packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt -packages/SystemUI/src/com/android/systemui/media/MediaProjectionCaptureTarget.kt --packages/SystemUI/src/com/android/systemui/media/dagger/MediaProjectionModule.kt -packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogFactory.kt -packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt -packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogReceiver.kt @@ -202,6 +182,11 @@ -packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ReceiverChipRippleView.kt -packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt -packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderUiEventLogger.kt +-packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorResultHandler.kt +-packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewController.kt +-packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionTaskView.kt +-packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/RecentTasksAdapter.kt +-packages/SystemUI/src/com/android/systemui/mediaprojection/devicepolicy/ScreenCaptureDevicePolicyResolver.kt -packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanel.kt -packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt -packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgePanelParams.kt @@ -220,8 +205,6 @@ -packages/SystemUI/src/com/android/systemui/privacy/logging/PrivacyLogger.kt -packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.kt -packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt --packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt --packages/SystemUI/src/com/android/systemui/qs/FooterActionsView.kt -packages/SystemUI/src/com/android/systemui/qs/HeaderPrivacyIconsController.kt -packages/SystemUI/src/com/android/systemui/qs/QSEvents.kt -packages/SystemUI/src/com/android/systemui/qs/QSExpansionPathInterpolator.kt @@ -237,7 +220,6 @@ -packages/SystemUI/src/com/android/systemui/qs/external/TileRequestDialog.kt -packages/SystemUI/src/com/android/systemui/qs/external/TileRequestDialogEventLogger.kt -packages/SystemUI/src/com/android/systemui/qs/external/TileServiceRequestController.kt --packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt -packages/SystemUI/src/com/android/systemui/qs/tileimpl/HeightOverrideable.kt -packages/SystemUI/src/com/android/systemui/qs/tileimpl/IgnorableChildLinearLayout.kt -packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt @@ -245,10 +227,6 @@ -packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt -packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt -packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt --packages/SystemUI/src/com/android/systemui/ripple/RippleShader.kt --packages/SystemUI/src/com/android/systemui/ripple/RippleShaderUtilLibrary.kt --packages/SystemUI/src/com/android/systemui/ripple/RippleView.kt --packages/SystemUI/src/com/android/systemui/ripple/SdfShaderLibrary.kt -packages/SystemUI/src/com/android/systemui/screenshot/ImageCaptureImpl.kt -packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt -packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotPolicy.kt @@ -259,23 +237,21 @@ -packages/SystemUI/src/com/android/systemui/settings/UserContentResolverProvider.kt -packages/SystemUI/src/com/android/systemui/settings/UserContextProvider.kt -packages/SystemUI/src/com/android/systemui/settings/UserFileManager.kt --packages/SystemUI/src/com/android/systemui/settings/UserFileManagerImpl.kt -packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt -packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt -packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessMirrorHandler.kt -packages/SystemUI/src/com/android/systemui/settings/brightness/MirroredBrightnessController.kt -packages/SystemUI/src/com/android/systemui/shade/CombinedShadeHeadersConstraintManager.kt -packages/SystemUI/src/com/android/systemui/shade/CombinedShadeHeadersConstraintManagerImpl.kt --packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt -packages/SystemUI/src/com/android/systemui/shade/NPVCDownEventState.kt --packages/SystemUI/src/com/android/systemui/shade/NotifPanelEvents.kt -packages/SystemUI/src/com/android/systemui/shade/NotificationPanelUnfoldAnimationController.kt -packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt -packages/SystemUI/src/com/android/systemui/shade/PulsingGestureListener.kt +-packages/SystemUI/src/com/android/systemui/shade/ShadeHeightLogger.kt -packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt +-packages/SystemUI/src/com/android/systemui/shade/ShadeWindowLogger.kt -packages/SystemUI/src/com/android/systemui/shade/transition/ScrimShadeTransitionController.kt -packages/SystemUI/src/com/android/systemui/shade/transition/ShadeTransitionController.kt --packages/SystemUI/src/com/android/systemui/shade/transition/SplitShadeOverScroller.kt -packages/SystemUI/src/com/android/systemui/smartspace/SmartspacePrecondition.kt -packages/SystemUI/src/com/android/systemui/smartspace/SmartspaceTargetFilter.kt -packages/SystemUI/src/com/android/systemui/smartspace/dagger/SmartspaceModule.kt @@ -284,10 +260,8 @@ -packages/SystemUI/src/com/android/systemui/smartspace/preconditions/LockscreenPrecondition.kt -packages/SystemUI/src/com/android/systemui/statusbar/AbstractLockscreenShadeTransitionController.kt -packages/SystemUI/src/com/android/systemui/statusbar/ActionClickLogger.kt --packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBarWifiView.kt -packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt -packages/SystemUI/src/com/android/systemui/statusbar/DisableFlagsLogger.kt --packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt -packages/SystemUI/src/com/android/systemui/statusbar/LockScreenShadeOverScroller.kt -packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeKeyguardTransitionController.kt -packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeScrimTransitionController.kt @@ -311,10 +285,12 @@ -packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializer.kt -packages/SystemUI/src/com/android/systemui/statusbar/dagger/StartCentralSurfacesModule.kt -packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt +-packages/SystemUI/src/com/android/systemui/statusbar/events/StatusBarEventsModule.kt -packages/SystemUI/src/com/android/systemui/statusbar/events/StatusEvent.kt -packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt -packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventCoordinator.kt -packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt +-packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImpl.kt -packages/SystemUI/src/com/android/systemui/statusbar/gesture/GenericGestureDetector.kt -packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeUpGestureHandler.kt -packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeUpGestureLogger.kt @@ -325,7 +301,6 @@ -packages/SystemUI/src/com/android/systemui/statusbar/notification/LaunchAnimationParameters.kt -packages/SystemUI/src/com/android/systemui/statusbar/notification/NotifPipelineFlags.kt -packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClickerLogger.kt --packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManagerLogger.kt -packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt -packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt -packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.kt @@ -396,6 +371,9 @@ -packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferLogger.kt -packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt -packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationSectionHeadersModule.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/fsi/FsiChromeViewBinder.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/fsi/FsiDebug.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/fsi/FsiTaskViewConfig.kt -packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconBuilder.kt -packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt -packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt @@ -403,6 +381,7 @@ -packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderLogger.kt -packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProvider.kt -packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryViewWalker.kt -packages/SystemUI/src/com/android/systemui/statusbar/notification/people/NotificationPersonExtractor.kt -packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt -packages/SystemUI/src/com/android/systemui/statusbar/notification/people/ViewPipeline.kt @@ -444,13 +423,10 @@ -packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt -packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallFlags.kt -packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallLogger.kt --packages/SystemUI/src/com/android/systemui/statusbar/phone/panelstate/PanelExpansionStateManager.kt --packages/SystemUI/src/com/android/systemui/statusbar/phone/panelstate/ShadeStateListener.kt --packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserInfoTracker.kt -packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherContainer.kt --packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherController.kt --packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherFeatureController.kt -packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt +-packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/model/ConnectivitySlots.kt +-packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiView.kt -packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryStateNotifier.kt -packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceControlsController.kt -packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceControlsControllerImpl.kt @@ -470,19 +446,17 @@ -packages/SystemUI/src/com/android/systemui/statusbar/tv/VpnStatusObserver.kt -packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowModule.kt -packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowStateController.kt --packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewInfo.kt -packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt +-packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewInfo.kt -packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarRootView.kt -packages/SystemUI/src/com/android/systemui/toast/ToastDefaultAnimation.kt -packages/SystemUI/src/com/android/systemui/toast/ToastLogger.kt -packages/SystemUI/src/com/android/systemui/tv/TVSystemUICoreStartableModule.kt +-packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt -packages/SystemUI/src/com/android/systemui/unfold/FoldStateLogger.kt -packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt --packages/SystemUI/src/com/android/systemui/unfold/UnfoldLatencyTracker.kt --packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt -packages/SystemUI/src/com/android/systemui/unfold/UnfoldProgressProvider.kt -packages/SystemUI/src/com/android/systemui/user/UserCreator.kt --packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt -packages/SystemUI/src/com/android/systemui/user/UserSwitcherPopupMenu.kt -packages/SystemUI/src/com/android/systemui/user/UserSwitcherRootView.kt -packages/SystemUI/src/com/android/systemui/util/AsyncActivityLauncher.kt @@ -509,7 +483,6 @@ -packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayout.kt -packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayoutController.kt -packages/SystemUI/src/com/android/systemui/util/animation/UniqueObjectHostView.kt --packages/SystemUI/src/com/android/systemui/util/collection/RingBuffer.kt -packages/SystemUI/src/com/android/systemui/util/concurrency/Execution.kt -packages/SystemUI/src/com/android/systemui/util/concurrency/PendingTasksContainer.kt -packages/SystemUI/src/com/android/systemui/util/drawable/DrawableSize.kt @@ -517,6 +490,7 @@ -packages/SystemUI/src/com/android/systemui/util/kotlin/Flow.kt -packages/SystemUI/src/com/android/systemui/util/kotlin/IpcSerializer.kt -packages/SystemUI/src/com/android/systemui/util/kotlin/nullability.kt +-packages/SystemUI/src/com/android/systemui/util/recycler/HorizontalSpacerItemDecoration.kt -packages/SystemUI/src/com/android/systemui/util/view/ViewUtil.kt -packages/SystemUI/src/com/android/systemui/util/wrapper/RotationPolicyWrapper.kt -packages/SystemUI/src/com/android/systemui/volume/VolumePanelDialogReceiver.kt @@ -525,7 +499,6 @@ -packages/SystemUI/tests/src/com/android/keyguard/BouncerPanelExpansionCalculatorTest.kt -packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt -packages/SystemUI/tests/src/com/android/keyguard/KeyguardBiometricLockoutLoggerTest.kt --packages/SystemUI/tests/src/com/android/keyguard/KeyguardListenQueueTest.kt -packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt -packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt -packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.kt @@ -550,7 +523,6 @@ -packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt -packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt -packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricTestExtensions.kt --packages/SystemUI/tests/src/com/android/systemui/biometrics/SidefpsControllerTest.kt -packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt -packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt -packages/SystemUI/tests/src/com/android/systemui/broadcast/ActionReceiverTest.kt @@ -569,7 +541,6 @@ -packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapperTest.kt -packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt -packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsTileResourceConfigurationImplTest.kt --packages/SystemUI/tests/src/com/android/systemui/controls/controller/DeletionJobServiceTest.kt -packages/SystemUI/tests/src/com/android/systemui/controls/controller/ServiceWrapperTest.kt -packages/SystemUI/tests/src/com/android/systemui/controls/controller/StatefulControlSubscriberTest.kt -packages/SystemUI/tests/src/com/android/systemui/controls/dagger/ControlsComponentTest.kt @@ -579,8 +550,8 @@ -packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsRequestDialogTest.kt -packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsRequestReceiverTest.kt -packages/SystemUI/tests/src/com/android/systemui/controls/management/FavoritesModelTest.kt --packages/SystemUI/tests/src/com/android/systemui/controls/management/TestControlsRequestDialog.kt -packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlViewHolderTest.kt +-packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt -packages/SystemUI/tests/src/com/android/systemui/controls/ui/DetailDialogTest.kt -packages/SystemUI/tests/src/com/android/systemui/decor/CutoutDecorProviderFactoryTest.kt -packages/SystemUI/tests/src/com/android/systemui/decor/OverlayWindowTest.kt @@ -596,13 +567,16 @@ -packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsReleaseTest.kt -packages/SystemUI/tests/src/com/android/systemui/flags/FlagManagerTest.kt -packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceConfigTest.kt +-packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceCoreStartableTest.kt +-packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt -packages/SystemUI/tests/src/com/android/systemui/lifecycle/InstantTaskExecutorRule.kt --packages/SystemUI/tests/src/com/android/systemui/log/LogBufferTest.kt -packages/SystemUI/tests/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManagerTest.kt -packages/SystemUI/tests/src/com/android/systemui/media/nearby/NearbyMediaDevicesManagerTest.kt -packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt -packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt -packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderUiEventLoggerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/navigationbar/TaskbarDelegateTest.kt -packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/FloatingRotationButtonPositionCalculatorTest.kt -packages/SystemUI/tests/src/com/android/systemui/privacy/AppOpsPrivacyItemMonitorTest.kt -packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyChipBuilderTest.kt @@ -610,7 +584,6 @@ -packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt -packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogTest.kt -packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt --packages/SystemUI/tests/src/com/android/systemui/qs/FooterActionsControllerTest.kt -packages/SystemUI/tests/src/com/android/systemui/qs/HeaderPrivacyIconsControllerTest.kt -packages/SystemUI/tests/src/com/android/systemui/qs/QSContainerImplTest.kt -packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentDisableFlagsLoggerTest.kt @@ -641,36 +614,29 @@ -packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DndTileTest.kt -packages/SystemUI/tests/src/com/android/systemui/qs/tiles/LocationTileTest.kt -packages/SystemUI/tests/src/com/android/systemui/qs/tiles/MicrophoneToggleTileTest.kt --packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt -packages/SystemUI/tests/src/com/android/systemui/qs/user/UserSwitchDialogControllerTest.kt --packages/SystemUI/tests/src/com/android/systemui/ripple/RippleViewTest.kt -packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordDialogTest.kt -packages/SystemUI/tests/src/com/android/systemui/screenshot/ImageCaptureImplTest.kt --packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt -packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotPolicyImplTest.kt --packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt --packages/SystemUI/tests/src/com/android/systemui/settings/UserFileManagerImplTest.kt -packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt -packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessSliderControllerTest.kt -packages/SystemUI/tests/src/com/android/systemui/shade/CombinedShadeHeaderConstraintsTest.kt --packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerCombinedTest.kt --packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerTest.kt -packages/SystemUI/tests/src/com/android/systemui/shade/NotificationQSContainerControllerTest.kt -packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt -packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt -packages/SystemUI/tests/src/com/android/systemui/shade/transition/ScrimShadeTransitionControllerTest.kt -packages/SystemUI/tests/src/com/android/systemui/shade/transition/ShadeTransitionControllerTest.kt --packages/SystemUI/tests/src/com/android/systemui/shade/transition/SplitShadeOverScrollerTest.kt -packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimatorTest.kt -packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimatorTest.kt -packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt +-packages/SystemUI/tests/src/com/android/systemui/shared/navigationbar/RegionSamplingHelperTest.kt -packages/SystemUI/tests/src/com/android/systemui/shared/rotation/RotationButtonControllerTest.kt --packages/SystemUI/tests/src/com/android/systemui/shared/system/UncaughtExceptionPreHandlerTest.kt -packages/SystemUI/tests/src/com/android/systemui/smartspace/DreamSmartspaceControllerTest.kt -packages/SystemUI/tests/src/com/android/systemui/smartspace/LockscreenAndDreamTargetFilterTest.kt -packages/SystemUI/tests/src/com/android/systemui/smartspace/LockscreenPreconditionTest.kt -packages/SystemUI/tests/src/com/android/systemui/statusbar/BlurUtilsTest.kt -packages/SystemUI/tests/src/com/android/systemui/statusbar/DisableFlagsLoggerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/DragDownHelperTest.kt -packages/SystemUI/tests/src/com/android/systemui/statusbar/LSShadeTransitionLoggerTest.kt -packages/SystemUI/tests/src/com/android/systemui/statusbar/LightRevealScrimTest.kt -packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt @@ -683,10 +649,12 @@ -packages/SystemUI/tests/src/com/android/systemui/statusbar/VibratorHelperTest.kt -packages/SystemUI/tests/src/com/android/systemui/statusbar/commandline/CommandRegistryTest.kt -packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImplTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/DisableStateTrackerTest.kt -packages/SystemUI/tests/src/com/android/systemui/statusbar/gesture/GenericGestureDetectorTest.kt -packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt -packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorControllerTest.kt -packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManagerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLoggerTest.kt -packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataImplTest.kt -packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataStoreImplTest.kt -packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifPipelineChoreographerTest.kt @@ -719,7 +687,6 @@ -packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt -packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ConfigurationControllerImplTest.kt -packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/FoldStateListenerTest.kt --packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaTest.kt -packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LetterboxAppearanceCalculatorTest.kt -packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LetterboxBackgroundProviderTest.kt -packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt @@ -733,8 +700,7 @@ -packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallChronometerTest.kt -packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt -packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallLoggerTest.kt --packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/panelstate/ShadeExpansionStateManagerTest.kt --packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherControllerOldImplTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt -packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryStateNotifierTest.kt -packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ClockTest.kt -packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceControlsControllerImplTest.kt @@ -744,7 +710,6 @@ -packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt -packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisablerTest.kt -packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SafetyControllerTest.kt --packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerOldImplTest.kt -packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/VariableDateViewControllerTest.kt -packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/WalletControllerImplTest.kt -packages/SystemUI/tests/src/com/android/systemui/statusbar/window/StatusBarWindowStateControllerTest.kt @@ -753,40 +718,36 @@ -packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldLatencyTrackerTest.kt -packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldTransitionWallpaperControllerTest.kt -packages/SystemUI/tests/src/com/android/systemui/unfold/config/ResourceUnfoldTransitionConfigTest.kt --packages/SystemUI/tests/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProviderTest.kt -packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt -packages/SystemUI/tests/src/com/android/systemui/unfold/util/FoldableTestUtils.kt --packages/SystemUI/tests/src/com/android/systemui/unfold/util/NaturalRotationUnfoldProgressProviderTest.kt -packages/SystemUI/tests/src/com/android/systemui/unfold/util/ScaleAwareUnfoldProgressProviderTest.kt -packages/SystemUI/tests/src/com/android/systemui/unfold/util/TestFoldStateProvider.kt -packages/SystemUI/tests/src/com/android/systemui/usb/UsbPermissionActivityTest.kt -packages/SystemUI/tests/src/com/android/systemui/user/UserCreatorTest.kt --packages/SystemUI/tests/src/com/android/systemui/user/UserSwitcherActivityTest.kt +-packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt -packages/SystemUI/tests/src/com/android/systemui/util/FakeSharedPreferencesTest.kt -packages/SystemUI/tests/src/com/android/systemui/util/FloatingContentCoordinatorTest.kt -packages/SystemUI/tests/src/com/android/systemui/util/ListenerSetTest.kt -packages/SystemUI/tests/src/com/android/systemui/util/RingerModeLiveDataTest.kt -packages/SystemUI/tests/src/com/android/systemui/util/WallpaperControllerTest.kt -packages/SystemUI/tests/src/com/android/systemui/util/animation/AnimationUtilTest.kt --packages/SystemUI/tests/src/com/android/systemui/util/collection/RingBufferTest.kt -packages/SystemUI/tests/src/com/android/systemui/util/drawable/DrawableSizeTest.kt -packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt -packages/SystemUI/tests/src/com/android/systemui/util/kotlin/IpcSerializerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/util/kotlin/SuspendUtilTests.kt -packages/SystemUI/tests/src/com/android/systemui/util/view/ViewUtilTest.kt --packages/SystemUI/tests/utils/src/com/android/systemui/broadcast/FakeBroadcastDispatcher.kt -packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt -packages/SystemUI/tests/utils/src/com/android/systemui/util/FakeSharedPreferences.kt -packages/SystemUI/tests/utils/src/com/android/systemui/util/mockito/KotlinMockitoHelpers.kt -packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedModule.kt -packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt +-packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionProgressProvider.kt -packages/SystemUI/unfold/src/com/android/systemui/unfold/compat/ScreenSizeFoldProvider.kt -packages/SystemUI/unfold/src/com/android/systemui/unfold/compat/SizeScreenStatusProvider.kt -packages/SystemUI/unfold/src/com/android/systemui/unfold/config/ResourceUnfoldTransitionConfig.kt --packages/SystemUI/unfold/src/com/android/systemui/unfold/dagger/UnfoldBackground.kt -packages/SystemUI/unfold/src/com/android/systemui/unfold/dagger/UnfoldMain.kt +-packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/FixedTimingTransitionProgressProvider.kt -packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt -packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt -packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/FoldStateProvider.kt --packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/hinge/HingeSensorAngleProvider.kt -packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/screen/ScreenStatusProvider.kt --packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScaleAwareTransitionProgressProvider.kt diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogBuffer.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogBuffer.kt index e99b2149bc1d..3e34885a6d9c 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogBuffer.kt +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogBuffer.kt @@ -35,7 +35,6 @@ import kotlin.math.max * as the result of taking a bug report). * * You can dump the entire buffer at any time by running: - * * ``` * $ adb shell dumpsys activity service com.android.systemui/.SystemUIService <bufferName> * ``` @@ -46,13 +45,11 @@ import kotlin.math.max * locally (usually for debugging purposes). * * To enable logcat echoing for an entire buffer: - * * ``` * $ adb shell settings put global systemui/buffer/<bufferName> <level> * ``` * * To enable logcat echoing for a specific tag: - * * ``` * $ adb shell settings put global systemui/tag/<tag> <level> * ``` @@ -64,10 +61,10 @@ import kotlin.math.max * LogBufferFactory. * * @param name The name of this buffer, printed when the buffer is dumped and in some other - * situations. + * situations. * @param maxSize The maximum number of messages to keep in memory at any one time. Buffers start - * out empty and grow up to [maxSize] as new messages are logged. Once the buffer's size reaches the - * maximum, it behaves like a ring buffer. + * out empty and grow up to [maxSize] as new messages are logged. Once the buffer's size reaches + * the maximum, it behaves like a ring buffer. */ class LogBuffer @JvmOverloads @@ -116,22 +113,22 @@ constructor( * initializer stored and converts it to a human-readable log message. * * @param tag A string of at most 23 characters, used for grouping logs into categories or - * subjects. If this message is echoed to logcat, this will be the tag that is used. + * subjects. If this message is echoed to logcat, this will be the tag that is used. * @param level Which level to log the message at, both to the buffer and to logcat if it's - * echoed. In general, a module should split most of its logs into either INFO or DEBUG level. - * INFO level should be reserved for information that other parts of the system might care - * about, leaving the specifics of code's day-to-day operations to DEBUG. + * echoed. In general, a module should split most of its logs into either INFO or DEBUG level. + * INFO level should be reserved for information that other parts of the system might care + * about, leaving the specifics of code's day-to-day operations to DEBUG. * @param messageInitializer A function that will be called immediately to store relevant data - * on the log message. The value of `this` will be the LogMessage to be initialized. + * on the log message. The value of `this` will be the LogMessage to be initialized. * @param messagePrinter A function that will be called if and when the message needs to be - * dumped to logcat or a bug report. It should read the data stored by the initializer and - * convert it to a human-readable string. The value of `this` will be the LogMessage to be - * printed. **IMPORTANT:** The printer should ONLY ever reference fields on the LogMessage and - * NEVER any variables in its enclosing scope. Otherwise, the runtime will need to allocate a - * new instance of the printer for each call, thwarting our attempts at avoiding any sort of - * allocation. + * dumped to logcat or a bug report. It should read the data stored by the initializer and + * convert it to a human-readable string. The value of `this` will be the LogMessage to be + * printed. **IMPORTANT:** The printer should ONLY ever reference fields on the LogMessage and + * NEVER any variables in its enclosing scope. Otherwise, the runtime will need to allocate a + * new instance of the printer for each call, thwarting our attempts at avoiding any sort of + * allocation. * @param exception Provide any exception that need to be logged. This is saved as - * [LogMessage.exception] + * [LogMessage.exception] */ @JvmOverloads inline fun log( diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogcatEchoTrackerDebug.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogcatEchoTrackerDebug.kt index faf1b78c598d..7a125ac14ea1 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogcatEchoTrackerDebug.kt +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/LogcatEchoTrackerDebug.kt @@ -28,7 +28,6 @@ import android.provider.Settings * Version of [LogcatEchoTracker] for debuggable builds * * The log level of individual buffers or tags can be controlled via global settings: - * * ``` * # Echo any message to <bufferName> of <level> or higher * $ adb shell settings put global systemui/buffer/<bufferName> <level> diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/util/RingBuffer.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/util/RingBuffer.kt index 68d78907f028..4773f54a079e 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/util/RingBuffer.kt +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/util/RingBuffer.kt @@ -30,7 +30,7 @@ import kotlin.math.max * * @param maxSize The maximum size the buffer can grow to before it begins functioning as a ring. * @param factory A function that creates a fresh instance of T. Used by the buffer while it's - * growing to [maxSize]. + * growing to [maxSize]. */ class RingBuffer<T>(private val maxSize: Int, private val factory: () -> T) : Iterable<T> { diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml index 6cc5b9d7b7e8..992d143ff66d 100644 --- a/packages/SystemUI/res-keyguard/values/dimens.xml +++ b/packages/SystemUI/res-keyguard/values/dimens.xml @@ -78,7 +78,7 @@ <!-- The vertical margin between the date and the owner info. --> <!-- The translation for disappearing security views after having solved them. --> - <dimen name="disappear_y_translation">-32dp</dimen> + <dimen name="disappear_y_translation">-50dp</dimen> <!-- Dimens for animation for the Bouncer PIN view --> <dimen name="pin_view_trans_y_entry">120dp</dimen> diff --git a/packages/SystemUI/res-product/values/strings.xml b/packages/SystemUI/res-product/values/strings.xml index b71caef3f593..87b206ce57ac 100644 --- a/packages/SystemUI/res-product/values/strings.xml +++ b/packages/SystemUI/res-product/values/strings.xml @@ -122,6 +122,12 @@ Try again in <xliff:g id="number">%3$d</xliff:g> seconds. </string> + <!-- Content description of the fingerprint icon when the system-provided fingerprint dialog is showing, to locate the sensor (tablet) for accessibility (not shown on the screen). [CHAR LIMIT=NONE]--> + <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet">The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the tablet.\n\nPressing the power button turns off the screen.</string> + <!-- Content description of the fingerprint icon when the system-provided fingerprint dialog is showing, to locate the sensor (device) for accessibility (not shown on the screen). [CHAR LIMIT=NONE]--> + <string name="security_settings_sfps_enroll_find_sensor_message" product="device">The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the device.\n\nPressing the power button turns off the screen.</string> + <!-- Content description of the fingerprint icon when the system-provided fingerprint dialog is showing, to locate the sensor (default) for accessibility (not shown on the screen). [CHAR LIMIT=NONE]--> + <string name="security_settings_sfps_enroll_find_sensor_message" product="default">The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the phone.\n\nPressing the power button turns off the screen.</string> <!-- Text shown when viewing global actions while phone is locked and additional controls are hidden [CHAR LIMIT=NONE] --> <string name="global_action_lock_message" product="default">Unlock your phone for more options</string> @@ -134,4 +140,7 @@ <string name="media_transfer_playing_this_device" product="default">Playing on this phone</string> <!-- Text informing the user that their media is now playing on this tablet device. [CHAR LIMIT=50] --> <string name="media_transfer_playing_this_device" product="tablet">Playing on this tablet</string> + + + </resources> diff --git a/packages/SystemUI/res/drawable/qs_media_rec_scrim.xml b/packages/SystemUI/res/drawable/qs_media_rec_scrim.xml new file mode 100644 index 000000000000..de0a6201cb09 --- /dev/null +++ b/packages/SystemUI/res/drawable/qs_media_rec_scrim.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2023 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License + --> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <!-- gradient from 25% in the center to 100% at edges --> + <gradient + android:type="radial" + android:gradientRadius="40%p" + android:startColor="#AE000000" + android:endColor="#00000000" /> +</shape>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/media_recommendation_view.xml b/packages/SystemUI/res/layout/media_recommendation_view.xml index c54c4e48d13d..a4aeba1dbcd6 100644 --- a/packages/SystemUI/res/layout/media_recommendation_view.xml +++ b/packages/SystemUI/res/layout/media_recommendation_view.xml @@ -22,9 +22,10 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:translationZ="0dp" - android:scaleType="centerCrop" + android:scaleType="matrix" android:adjustViewBounds="true" android:clipToOutline="true" + android:layerType="hardware" android:background="@drawable/bg_smartspace_media_item"/> <!-- App icon --> diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index 4a73390d17cc..c5d28eef688f 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Kennisgewingskerm."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Vinnige instellings."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Kitsinstellings en kennisgewingskerm."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Sluitskerm."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Werksluitskerm"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Maak toe"</string> diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index f629387f6971..135284120b03 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"مركز الإشعارات."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"الإعدادات السريعة."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"\"الإعدادات السريعة\" و\"مركز الإشعارات\""</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"شاشة القفل."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"شاشة قفل بيانات العمل"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"إغلاق"</string> @@ -655,7 +654,7 @@ <string name="right_keycode" msgid="2480715509844798438">"رمز مفتاح اليمين"</string> <string name="left_icon" msgid="5036278531966897006">"رمز اليسار"</string> <string name="right_icon" msgid="1103955040645237425">"رمز اليمين"</string> - <string name="drag_to_add_tiles" msgid="8933270127508303672">"اضغط باستمرار مع السحب لإضافة الميزات."</string> + <string name="drag_to_add_tiles" msgid="8933270127508303672">"اضغط باستمرار مع السحب لإضافة المربّعات"</string> <string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"اضغط باستمرار مع السحب لإعادة ترتيب الميزات."</string> <string name="drag_to_remove_tiles" msgid="4682194717573850385">"اسحب هنا للإزالة"</string> <string name="drag_to_remove_disabled" msgid="933046987838658850">"الحدّ الأدنى من عدد المربعات الذي تحتاج إليه هو <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g>"</string> @@ -1044,14 +1043,9 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"التبديل إلى الملف الشخصي للعمل"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"إغلاق"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"إعدادات شاشة القفل"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"لا يتوفّر اتصال Wi-Fi."</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"استخدام الكاميرا محظور."</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"استخدام الكاميرا والميكروفون محظور."</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"استخدام الميكروفون محظور."</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"وضع الأولوية مفعّل."</string> </resources> diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml index aa198424065d..13acbde945b9 100644 --- a/packages/SystemUI/res/values-as/strings.xml +++ b/packages/SystemUI/res/values-as/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"জাননী পেনেল।"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ক্ষিপ্ৰ ছেটিং।"</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"ক্ষিপ্ৰ ছেটিং জাননী পেনেল।"</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"বন্ধ স্ক্ৰীন।"</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"কৰ্মস্থানৰ প্ৰ\'ফাইলৰ লক স্ক্ৰীন"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"বন্ধ কৰক"</string> diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml index c3312412c978..6a8eb2cd1ff3 100644 --- a/packages/SystemUI/res/values-az/strings.xml +++ b/packages/SystemUI/res/values-az/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Bildiriş kölgəsi."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Tez ayarlar."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Sürətli ayarlar və Bildiriş göstərişi."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Kilid ekranı."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Ekran kilidi"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Qapadın"</string> diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml index d2279bed089c..f045b59130d9 100644 --- a/packages/SystemUI/res/values-be/strings.xml +++ b/packages/SystemUI/res/values-be/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Цень апавяшчэння.."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Хуткія налады."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Хуткія налады і шчыток апавяшчэнняў."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Экран блакіроўкі."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Экран блакіроўкі дзейнасці"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Закрыць"</string> @@ -1044,14 +1043,9 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Пераключыцца на працоўны профіль"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Закрыць"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"Налады экрана блакіроўкі"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Сетка Wi-Fi недаступная"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Камера заблакіравана"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Камера і мікрафон заблакіраваны"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Мікрафон заблакіраваны"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Прыярытэтны рэжым уключаны"</string> </resources> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index 36b3c8b8d44b..dfb0c5b37270 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Падащ панел с известия."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Бързи настройки."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Падащ панел с бързи настройки и известия."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Заключване на екрана."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Заключен екран на служебния профил"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Затваряне"</string> diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml index 0f3f00c465e3..42e8492da33f 100644 --- a/packages/SystemUI/res/values-bn/strings.xml +++ b/packages/SystemUI/res/values-bn/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"বিজ্ঞপ্তি শেড৷"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"দ্রুত সেটিংস৷"</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"দ্রুত সেটিংস এবং বিজ্ঞপ্তি শেড।"</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"লক স্ক্রিন।"</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"কর্মস্থলের স্ক্রিন লক"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"বন্ধ করুন"</string> @@ -1044,14 +1043,9 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"অফিস প্রোফাইলে পাল্টে নিন"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"বন্ধ করুন"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"লক স্ক্রিন সেটিংস"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"ওয়াই-ফাই উপলভ্য নয়"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"ক্যামেরার অ্যাক্সেস ব্লক করা আছে"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"ক্যামেরা এবং মাইক্রোফোনের অ্যাক্সেস ব্লক করা আছে"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"মাইক্রোফোনের অ্যাক্সেস ব্লক করা আছে"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"\'প্রায়োরিটি\' মোড চালু করা আছে"</string> </resources> diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml index 823b72367b95..6da19137ae70 100644 --- a/packages/SystemUI/res/values-bs/strings.xml +++ b/packages/SystemUI/res/values-bs/strings.xml @@ -197,7 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Obavještenja sa sjenčenjem."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Brze postavke."</string> - <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Brze postavke i zaslon obavijesti."</string> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Brze postavke i lokacija za obavještenja."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Zaključan ekran."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Zaključan ekran radnog profila"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Zatvori"</string> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index d60722fc1d11..81903a7c2134 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Àrea de notificacions"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Configuració ràpida"</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Configuració ràpida i àrea de notificacions."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Pantalla de bloqueig"</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Pantalla de bloqueig per a la feina"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Tanca"</string> @@ -1044,14 +1043,9 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Canvia al perfil de treball"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Tanca"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"Configuració pantalla de bloqueig"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"No hi ha cap Wi‑Fi disponible"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"La càmera està bloquejada"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"La càmera i el micròfon estan bloquejats"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"El micròfon està bloquejat"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"El mode Prioritat està activat"</string> </resources> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index 6662ca10ffc0..6369fe55c7f0 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Panel oznámení."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Rychlé nastavení."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Rychlé nastavení a panel oznámení"</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Obrazovka uzamčení"</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Obrazovka uzamčení pracovního profilu"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Zavřít"</string> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index ee9d8a60b760..514e0cb07675 100644 --- a/packages/SystemUI/res/values-da/strings.xml +++ b/packages/SystemUI/res/values-da/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Notifikationspanel."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Kvikmenu."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Kvikmenu og notifikationspanel."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Låseskærm."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Låseskærm til arbejde"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Luk"</string> @@ -1044,14 +1043,9 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Skift til arbejdsprofil"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Luk"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"Indstillinger for låseskærm"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi er ikke tilgængeligt"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kameraet er blokeret"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Der er blokeret for kameraet og mikrofonen"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofonen er blokeret"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Prioritetstilstand er aktiveret"</string> </resources> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index 66fa2317d284..c7f792c49cfe 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Benachrichtigungsleiste"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Schnelleinstellungen"</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Schnelleinstellungen und Benachrichtigungsleiste."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Sperrbildschirm"</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Sperrbildschirm für Arbeitsprofil"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Schließen"</string> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index 84d661021067..99fa0bfdc741 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Πλαίσιο σκίασης ειδοποιήσεων."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Γρήγορες ρυθμίσεις."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Γρήγορες ρυθμίσεις και πλαίσιο σκίασης ειδοποιήσεων."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Οθόνη κλειδώματος"</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Οθόνη κλειδωμένης εργασίας"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Κλείσιμο"</string> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index 020b9e5ed206..ad386eceded3 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Pantalla de notificaciones"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Configuración rápida"</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Configuración rápida y panel de notificaciones."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Pantalla de bloqueo"</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Pantalla bloqueada del perfil de trabajo"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Cerrar"</string> @@ -1044,14 +1043,9 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Cambiar al perfil de trabajo"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Cerrar"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"Config. de pantalla de bloqueo"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi no disponible"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"La cámara está bloqueada"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"La cámara y el micrófono están bloqueados"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"El micrófono está bloqueado"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"El modo de prioridad está activado"</string> </resources> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index c8e9b23b83e8..e28f1944d70d 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Pantalla de notificaciones"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Ajustes rápidos"</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Ajustes rápidos y pantalla de notificaciones."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Pantalla de bloqueo."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Pantalla de bloqueo para el perfil de trabajo"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Cerrar"</string> @@ -959,7 +958,7 @@ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Datos móviles"</string> <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> <string name="mobile_data_connection_active" msgid="944490013299018227">"Conectado"</string> - <string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Conectada temporalmente"</string> + <string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Conectado temporalmente"</string> <string name="mobile_data_poor_connection" msgid="819617772268371434">"Conexión inestable"</string> <string name="mobile_data_off_summary" msgid="3663995422004150567">"Los datos móviles no se conectarán automáticamente"</string> <string name="mobile_data_no_connection" msgid="1713872434869947377">"Sin conexión"</string> @@ -1044,14 +1043,9 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Cambiar al perfil de trabajo"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Cerrar"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"Ajustes de pantalla de bloqueo"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Red Wi-Fi no disponible"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Cámara bloqueada"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Cámara y micrófono bloqueados"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Micrófono bloqueado"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Modo Prioridad activado"</string> </resources> diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml index a46f53d9aaaf..5fc1abe17d15 100644 --- a/packages/SystemUI/res/values-et/strings.xml +++ b/packages/SystemUI/res/values-et/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Märguande vari."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Kiirseaded."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Kiirseaded ja märguandeala."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Kuva lukustamine."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Töö lukustuskuva"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Sulgemine"</string> @@ -1044,14 +1043,9 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Lülitu tööprofiilile"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Sule"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"Lukustuskuva seaded"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"WiFi pole saadaval"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kaamera on blokeeritud"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kaamera ja mikrofon on blokeeritud"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon on blokeeritud"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Prioriteetne režiim on sisse lülitatud"</string> </resources> diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml index 53ec95e22d7a..a3dcbb62be2b 100644 --- a/packages/SystemUI/res/values-eu/strings.xml +++ b/packages/SystemUI/res/values-eu/strings.xml @@ -780,12 +780,9 @@ <string name="privacy_type_media_projection" msgid="8136723828804251547">"pantaila-grabaketa"</string> <string name="music_controls_no_title" msgid="4166497066552290938">"Ez du izenik"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Egonean"</string> - <!-- no translation found for font_scaling_dialog_title (6273107303850248375) --> - <skip /> - <!-- no translation found for font_scaling_smaller (1012032217622008232) --> - <skip /> - <!-- no translation found for font_scaling_larger (5476242157436806760) --> - <skip /> + <string name="font_scaling_dialog_title" msgid="6273107303850248375">"Letraren tamaina"</string> + <string name="font_scaling_smaller" msgid="1012032217622008232">"Txikitu"</string> + <string name="font_scaling_larger" msgid="5476242157436806760">"Handitu"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Lupa-leihoa"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Lupa-leihoaren aukerak"</string> <string name="accessibility_control_zoom_in" msgid="1189272315480097417">"Handitu"</string> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index 938bc82c2d19..d34573611124 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"مجموعه اعلان."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"تنظیمات سریع."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"تنظیمات فوری و کشوی اعلانات."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"صفحه قفل."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"صفحه قفل کاری"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"بستن"</string> diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index 6f9b38bf0d9d..8aaafe104388 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Ilmoitusalue."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Pika-asetukset."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Pika-asetukset ja ilmoitusalue"</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Lukitse näyttö."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Työlukitusnäyttö"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Sulje"</string> diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml index c6f8cab527a5..d45677ed62cc 100644 --- a/packages/SystemUI/res/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/strings.xml @@ -780,12 +780,9 @@ <string name="privacy_type_media_projection" msgid="8136723828804251547">"enregistrement d\'écran"</string> <string name="music_controls_no_title" msgid="4166497066552290938">"Sans titre"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Veille"</string> - <!-- no translation found for font_scaling_dialog_title (6273107303850248375) --> - <skip /> - <!-- no translation found for font_scaling_smaller (1012032217622008232) --> - <skip /> - <!-- no translation found for font_scaling_larger (5476242157436806760) --> - <skip /> + <string name="font_scaling_dialog_title" msgid="6273107303850248375">"Taille de police"</string> + <string name="font_scaling_smaller" msgid="1012032217622008232">"Rapetisser"</string> + <string name="font_scaling_larger" msgid="5476242157436806760">"Agrandir"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Fenêtre d\'agrandissement"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Commandes pour la fenêtre d\'agrandissement"</string> <string name="accessibility_control_zoom_in" msgid="1189272315480097417">"Effectuer un zoom avant"</string> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index a191259b7f1e..0d612aab505a 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Volet des notifications"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Réglages rapides"</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Réglages rapides et volet des notifications."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Écran de verrouillage"</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Écran de verrouillage du profil professionnel"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Fermer"</string> @@ -1044,14 +1043,9 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Passer au profil professionnel"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Fermer"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"Paramètres écran de verrouillage"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi non disponible"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Caméra bloquée"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Caméra et micro bloqués"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Micro bloqué"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Mode Prioritaire activé"</string> </resources> diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml index 2684b92581c9..b1eb70b0016f 100644 --- a/packages/SystemUI/res/values-gl/strings.xml +++ b/packages/SystemUI/res/values-gl/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Panel despregable"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Configuración rápida"</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Configuración rápida e panel despregable."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Pantalla de bloqueo."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Pantalla de bloqueo do perfil de traballo"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Pechar"</string> @@ -1044,14 +1043,9 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Cambiar ao perfil de traballo"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Pechar"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"Configuración pantalla bloqueo"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wifi non dispoñible"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"A cámara está bloqueada"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"A cámara e o micrófono están bloqueados"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"O micrófono está bloqueado"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"O modo de prioridade está activado"</string> </resources> diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml index cf1000d76a4c..cb2966ebcc4f 100644 --- a/packages/SystemUI/res/values-gu/strings.xml +++ b/packages/SystemUI/res/values-gu/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"નોટિફિકેશન શેડ."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ઝડપી સેટિંગ."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"ઝડપી સેટિંગ અને નોટિફિકેશન શેડ."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"લૉક સ્ક્રીન."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"કાર્ય લૉક સ્ક્રીન"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"બંધ કરો"</string> @@ -1044,14 +1043,9 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"ઑફિસની પ્રોફાઇલ પર સ્વિચ કરો"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"બંધ કરો"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"લૉક સ્ક્રીનના સેટિંગ"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"વાઇ-ફાઇ ઉપલબ્ધ નથી"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"કૅમેરા બ્લૉક કરેલો છે"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"કૅમેરા અને માઇક્રોફોન બ્લૉક કરેલા છે"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"માઇક્રોફોન બ્લૉક કરેલો છે"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"પ્રાધાન્યતા મોડ ચાલુ છે"</string> </resources> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index 7bab739d51d1..7bbd2d13ced1 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"सूचना शेड."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"त्वरित सेटिंग."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"क्विक सेटिंग और नोटिफ़िकेशन शेड."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"लॉक स्क्रीन."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"वर्क लॉक स्क्रीन"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"बंद करें"</string> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index 8a088a1bff9b..16761f59291d 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Értesítési felület."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Gyorsbeállítások."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Gyorsbeállítások és értesítési terület"</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Lezárási képernyő."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Munka lezárási képernyővel"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Bezárás"</string> @@ -1044,14 +1043,9 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Váltás munkaprofilra"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Bezárás"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"Lezárási képernyő beállításai"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Nem áll rendelkezésre Wi-Fi"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera letiltva"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera és mikrofon letiltva"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon letiltva"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Prioritás mód bekapcsolva"</string> </resources> diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml index 819a02990183..7d2d638f92cc 100644 --- a/packages/SystemUI/res/values-hy/strings.xml +++ b/packages/SystemUI/res/values-hy/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Ծանուցումների վահանակ:"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Արագ կարգավորումներ:"</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Արագ կարգավորումներ և ծանուցումների վահանակ։"</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Էկրանի կողպում:"</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Աշխատանքային պրոֆիլի կողպէկրան"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Փակել"</string> @@ -1044,14 +1043,9 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Անցնել աշխատանքային պրոֆիլ"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Փակել"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"Կողպէկրանի կարգավորումներ"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi ցանց հասանելի չէ"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Տեսախցիկն արգելափակված է"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Տեսախցիկն ու խոսափողը արգելափակված են"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Խոսափողն արգելափակված է"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Առաջնահերթության ռեժիմը միացված է"</string> </resources> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index b70173a73829..97e231675407 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Bayangan pemberitahuan."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Setelan cepat."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Setelan cepat dan Menu notifikasi."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Layar kunci."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Layar kunci kantor"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Tutup"</string> @@ -1044,14 +1043,9 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Beralih ke profil kerja"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Tutup"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"Setelan layar kunci"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi tidak tersedia"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera diblokir"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera dan mikrofon diblokir"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon diblokir"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Mode prioritas diaktifkan"</string> </resources> diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml index 85b435ec23cc..28f1fb63aa0e 100644 --- a/packages/SystemUI/res/values-is/strings.xml +++ b/packages/SystemUI/res/values-is/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Tilkynningasvæði."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Flýtistillingar."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Flýtistillingar og tilkynningagluggi."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Lásskjár."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Vinnulásskjár"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Loka"</string> @@ -1044,14 +1043,9 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Skipta yfir í vinnusnið"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Loka"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"Stillingar fyrir lásskjá"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi er ekki til staðar"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Lokað fyrir myndavél"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Lokað fyrir myndavél og hljóðnema"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Lokað fyrir hljóðnema"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Kveikt er á forgangsstillingu"</string> </resources> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index 8c25677fce78..5c8ce7c1bbd1 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -1043,14 +1043,9 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Passa a profilo di lavoro"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Chiudi"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"Impostazioni schermata di blocco"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi non disponibile"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Videocamera bloccata"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Videocamera e microfono bloccati"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Microfono bloccato"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Modalità priorità attivata"</string> </resources> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index 1237ba66f18a..c2392d944974 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"לוח התראות."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"הגדרות מהירות."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"הגדרות מהירות ולוח ההתראות."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"מסך נעילה."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"מסך נעילה של עבודה"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"סגירה"</string> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index 2ce2f536571a..630f1f807e1c 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"通知シェード"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"クイック設定"</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"クイック設定と通知シェード。"</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"ロック画面"</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"仕事用プロファイルのロック画面"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"閉じる"</string> diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml index 59febea1bc91..76277bdf5001 100644 --- a/packages/SystemUI/res/values-ka/strings.xml +++ b/packages/SystemUI/res/values-ka/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"შეტყობინებების ფარდა"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"სწრაფი პარამეტრები"</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"სწრაფი პარამეტრები და შეტყობინებების ფარდა"</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"ეკრანის დაბლოკვა."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"სამსახურის ჩაკეტილი ეკრანი"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"დახურვა"</string> diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml index 6bdb0aa41925..d7c24cf0c75a 100644 --- a/packages/SystemUI/res/values-kk/strings.xml +++ b/packages/SystemUI/res/values-kk/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Хабарландыру тақтасы"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Жылдам параметрлер."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Жылдам параметрлер мен хабарландыру тақтасы."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Бекіту экраны."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Әрекетті құлыптау экраны"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Жабу"</string> @@ -1044,14 +1043,9 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Жұмыс профиліне ауысу"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Жабу"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"Экран құлпының параметрлері"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi қолжетімсіз."</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Камера бөгелген."</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Камера мен микрофон бөгелген."</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Микрофон бөгелген."</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"\"Маңызды\" режимі қосулы."</string> </resources> diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml index 080769a4dd6a..521302eef76a 100644 --- a/packages/SystemUI/res/values-km/strings.xml +++ b/packages/SystemUI/res/values-km/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"ពណ៌ការជូនដំណឹង"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ការកំណត់រហ័ស។"</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"ការកំណត់រហ័ស និងផ្ទាំងជូនដំណឹង។"</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"ចាក់សោអេក្រង់។"</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"អេក្រង់ចាក់សោលក្ខណៈការងារ"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"បិទ"</string> diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml index 4a8bbd862dd2..9f47e94d85cc 100644 --- a/packages/SystemUI/res/values-kn/strings.xml +++ b/packages/SystemUI/res/values-kn/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"ಅಧಿಸೂಚನೆಯ ಛಾಯೆ."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್ಗಳು."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್ಗಳು ಮತ್ತು ಅಧಿಸೂಚನೆಯ ಪರದೆ."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"ಲಾಕ್ ಸ್ಕ್ರೀನ್."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"ಕೆಲಸದ ಲಾಕ್ ಪರದೆ"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"ಮುಚ್ಚು"</string> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index dd68c5a30e22..9d90602dce1b 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"알림 세부정보"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"빠른 설정"</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"빠른 설정 및 알림 창입니다."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"화면을 잠급니다."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"업무용 잠금 화면"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"닫기"</string> @@ -780,12 +779,9 @@ <string name="privacy_type_media_projection" msgid="8136723828804251547">"화면 녹화"</string> <string name="music_controls_no_title" msgid="4166497066552290938">"제목 없음"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"대기"</string> - <!-- no translation found for font_scaling_dialog_title (6273107303850248375) --> - <skip /> - <!-- no translation found for font_scaling_smaller (1012032217622008232) --> - <skip /> - <!-- no translation found for font_scaling_larger (5476242157436806760) --> - <skip /> + <string name="font_scaling_dialog_title" msgid="6273107303850248375">"글꼴 크기"</string> + <string name="font_scaling_smaller" msgid="1012032217622008232">"축소"</string> + <string name="font_scaling_larger" msgid="5476242157436806760">"확대"</string> <string name="magnification_window_title" msgid="4863914360847258333">"확대 창"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"확대 창 컨트롤"</string> <string name="accessibility_control_zoom_in" msgid="1189272315480097417">"확대"</string> @@ -1047,14 +1043,9 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"직장 프로필로 전환"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"닫기"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"잠금 화면 설정"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi를 사용할 수 없음"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"카메라 차단됨"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"카메라 및 마이크 차단됨"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"마이크 차단됨"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"우선순위 모드 설정됨"</string> </resources> diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml index efd9c086ddd3..0b89bd3fb471 100644 --- a/packages/SystemUI/res/values-ky/strings.xml +++ b/packages/SystemUI/res/values-ky/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Билдирмелер тактасы."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Тез тууралоолор."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Ыкчам параметрлер жана билдирмелер тактасы."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Кулпуланган экран."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Жумуштун кулпуланган экраны"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Жабуу"</string> diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml index 00190ec716fe..85910fdd7178 100644 --- a/packages/SystemUI/res/values-lo/strings.xml +++ b/packages/SystemUI/res/values-lo/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"ໜ້າຈໍແຈ້ງເຕືອນ."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ການຕັ້ງຄ່າດ່ວນ."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"ການຕັ້ງຄ່າດ່ວນ ແລະ ເງົາການແຈ້ງເຕືອນ."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"ລັອກໜ້າຈໍ."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"ໜ້າຈໍລັອກວຽກ"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"ປິດ"</string> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index 5bcd893af655..8161025142ad 100644 --- a/packages/SystemUI/res/values-lt/strings.xml +++ b/packages/SystemUI/res/values-lt/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Pranešimų gaubtas."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Spartieji nustatymai."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Spartieji nustatymai ir pranešimų skydelis."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Užrakinimo ekranas."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Darbo profilio užrakinimo ekranas"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Uždaryti"</string> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index 4dcb45413ac7..72ca07192d95 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Paziņojumu panelis"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Ātrie iestatījumi"</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Ātrie iestatījumi un paziņojumu panelis."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Bloķēšanas ekrāns."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Darba profila bloķēšanas ekrāns"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Aizvērt"</string> @@ -1044,14 +1043,9 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Pārslēgties uz darba profilu"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Aizvērt"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"Bloķēšanas ekrāna iestatījumi"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi nav pieejams"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera ir bloķēta"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kameras un mikrofona lietošana ir bloķēta"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofons ir bloķēts"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Prioritātes režīms ir ieslēgts"</string> </resources> diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml index e80be9248e88..e16812148a88 100644 --- a/packages/SystemUI/res/values-mk/strings.xml +++ b/packages/SystemUI/res/values-mk/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Панел за известување"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Брзи поставки."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"„Брзи поставки“ и „Панел со известувања“."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Заклучи екран."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Работен заклучен екран"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Затвори"</string> @@ -1044,14 +1043,9 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Префрли се на работен профил"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Затвори"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"Поставки за заклучен екран"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi не е достапно"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Камерата е блокирана"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Камерата и микрофонот се блокирани"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Микрофонот е блокиран"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Приоритетниот режим е вклучен"</string> </resources> diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml index 6622fb90be17..36c1a5f2c837 100644 --- a/packages/SystemUI/res/values-ml/strings.xml +++ b/packages/SystemUI/res/values-ml/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"അറിയിപ്പ് ഷെയ്ഡ്."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ദ്രുത ക്രമീകരണങ്ങൾ."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"അറിയിപ്പ് ഷെയ്ഡിനുള്ള ദ്രുത ക്രമീകരണം."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"ലോക്ക് സ്ക്രീൻ."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"ഔദ്യോഗിക ലോക്ക് സ്ക്രീൻ"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"അവസാനിപ്പിക്കുക"</string> diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml index 5e875d1e31b0..9042bf5c104f 100644 --- a/packages/SystemUI/res/values-mn/strings.xml +++ b/packages/SystemUI/res/values-mn/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Мэдэгдлийн хураангуй самбар"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Шуурхай тохиргоо."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Шуурхай тохиргоо болон мэдэгдлийн хураангуй самбар."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Дэлгэц түгжих."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Ажлын түгжигдсэн дэлгэц"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Хаах"</string> diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml index 9f3680dbdbed..43fed36e80c7 100644 --- a/packages/SystemUI/res/values-mr/strings.xml +++ b/packages/SystemUI/res/values-mr/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"सूचना शेड."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"क्विक सेटिंग्ज."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"क्विक सेटिंग्ज आणि सूचना शेड."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"लॉक स्क्रीन."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"कार्य लॉक स्क्रीन"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"बंद करा"</string> @@ -1044,14 +1043,9 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"कार्य प्रोफाइलवर स्विच करा"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"बंद करा"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"लॉक स्क्रीन सेटिंग्ज"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"वाय-फाय उपलब्ध नाही"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"कॅमेरा ब्लॉक केला"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"कॅमेरा आणि मायक्रोफोन ब्लॉक केले आहेत"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"मायक्रोफोन ब्लॉक केला"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"प्राधान्य मोड सुरू आहे"</string> </resources> diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml index 109d5193c5ee..5a6ee921c9f8 100644 --- a/packages/SystemUI/res/values-ms/strings.xml +++ b/packages/SystemUI/res/values-ms/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Bidai pemberitahuan."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Tetapan pantas."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Tetapan pantas dan Bidai pemberitahuan."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Kunci skrin."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Skrin kunci kerja"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Tutup"</string> diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml index 4fa84eb0d933..7fe024472ed7 100644 --- a/packages/SystemUI/res/values-my/strings.xml +++ b/packages/SystemUI/res/values-my/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"အကြောင်းကြားစာအကွက်"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"အမြန်လုပ် အပြင်အဆင်"</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"‘အမြန်ဆက်တင်များ’ နှင့် ‘အကြောင်းကြားစာအကွက်’။"</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"မျက်နှာပြင် သော့ပိတ်ရန်"</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"အလုပ်သုံး လော့ခ်မျက်နှာပြင်"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"ပိတ်ရန်"</string> diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index 7e8e5f0c7d06..887cf9d3de53 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Varselskygge."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Hurtiginnstillinger."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Hurtiginnstillinger og varselpanelet"</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Låseskjerm."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Låseskjerm for arbeid"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Lukk"</string> diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml index db4c1a2cffe0..c37aef3a1ff9 100644 --- a/packages/SystemUI/res/values-ne/strings.xml +++ b/packages/SystemUI/res/values-ne/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"सूचना कक्ष।"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"द्रुत सेटिङहरू"</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"द्रुत सेटिङ तथा सूचना कक्ष।"</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"स्क्रीन बन्द गर्नुहोस्।"</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"कार्य प्रोफाइलको लक स्क्रिन"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"बन्द गर्नुहोस्"</string> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index 28a78e1355d0..ee055d7779d1 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Meldingenpaneel."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Snelle instellingen."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Snelle instellingen en meldingenpaneel."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Vergrendelscherm."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Vergrendelscherm voor werk"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Sluiten"</string> diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml index d3ce6fcfcd37..4252f49a056b 100644 --- a/packages/SystemUI/res/values-or/strings.xml +++ b/packages/SystemUI/res/values-or/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"ବିଜ୍ଞପ୍ତି ଶେଡ୍।"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"କ୍ୱିକ୍ ସେଟିଂସ୍।"</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"କୁଇକ ସେଟିଂସ ଏବଂ ବିଜ୍ଞପ୍ତି ସେଡ।"</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"ଲକ୍ ସ୍କ୍ରୀନ୍।"</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"ୱର୍କ ଲକ୍ ସ୍କ୍ରୀନ୍"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"ବନ୍ଦ କରନ୍ତୁ"</string> diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml index 70e15b8fec45..ea8bd3d88d8c 100644 --- a/packages/SystemUI/res/values-pa/strings.xml +++ b/packages/SystemUI/res/values-pa/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"ਸੂਚਨਾ ਸ਼ੇਡ।"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ।"</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ ਅਤੇ ਸੂਚਨਾ ਸ਼ੇਡ।"</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">" ਲਾਕ ਸਕ੍ਰੀਨ।"</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"ਕਾਰਜ-ਸਥਾਨ ਲਾਕ ਸਕ੍ਰੀਨ"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"ਬੰਦ ਕਰੋ"</string> @@ -1044,14 +1043,9 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ \'ਤੇ ਜਾਓ"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"ਬੰਦ ਕਰੋ"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"ਲਾਕ ਸਕ੍ਰੀਨ ਸੈਟਿੰਗਾਂ"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"ਵਾਈ-ਫਾਈ ਉਪਲਬਧ ਨਹੀਂ"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"ਕੈਮਰਾ ਬਲਾਕ ਕੀਤਾ ਗਿਆ"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"ਕੈਮਰਾ ਅਤੇ ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਬਲਾਕ ਕੀਤੇ ਗਏ"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਬਲਾਕ ਕੀਤਾ ਗਿਆ"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"ਤਰਜੀਹ ਮੋਡ ਚਾਲੂ ਹੈ"</string> </resources> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index b67bd0036df9..aa117db339aa 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Obszar powiadomień."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Szybkie ustawienia."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Szybkie ustawienia i obszar powiadomień."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Ekran blokady."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Ekran blokady wyświetlany podczas działania"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Zamknij"</string> @@ -1044,14 +1043,9 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Przełącz na profil służbowy"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Zamknij"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"Ustawienia ekranu blokady"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Sieć Wi-Fi jest niedostępna"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera jest zablokowana"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera i mikrofon są zablokowane"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon jest zablokowany"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Tryb priorytetowy jest włączony"</string> </resources> diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml index f3ef1523a7e6..5b3efde20363 100644 --- a/packages/SystemUI/res/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res/values-pt-rBR/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Aba de notificações."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Configurações rápidas."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Configurações rápidas e aba de notificações."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Tela de bloqueio."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Tela de bloqueio de trabalho"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Fechar"</string> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index ac7886c56b35..eb314bae993d 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Painel de notificações."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Definições rápidas."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Definições rápidas e painel de notificações."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Ecrã de bloqueio."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Ecrã de bloqueio de trabalho"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Fechar"</string> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index f3ef1523a7e6..5b3efde20363 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Aba de notificações."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Configurações rápidas."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Configurações rápidas e aba de notificações."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Tela de bloqueio."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Tela de bloqueio de trabalho"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Fechar"</string> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index 4bdbbc4ee91d..aced6bd29bc9 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Fereastră pentru notificări."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Setări rapide."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Fereastră de Setări rapide și notificări."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Ecranul de blocare."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Ecran de blocare pentru serviciu"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Închide"</string> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index f1a0cc38d8f7..f6459bb07341 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Панель уведомлений"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Быстрые настройки"</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Быстрые настройки и панель уведомлений."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Экран блокировки."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Заблокировано"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Закрыть"</string> diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml index c3351897d912..e4838f982e5b 100644 --- a/packages/SystemUI/res/values-si/strings.xml +++ b/packages/SystemUI/res/values-si/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"දැනුම්දීම් ආවරණය."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ක්ෂණික සැකසීම්."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"ඉක්මන් සැකසීම් සහ දැනුම්දීම් ඡායිතය."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"අගුළු තිරය."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"කාර්යාල අගුලු තිරය"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"වසන්න"</string> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index 1174755f6793..db3b7655fdbf 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Panel upozornení."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Rýchle nastavenia."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Rýchle nastavenia a panel upozornení"</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Uzamknutá obrazovka"</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Uzamknutá obrazovka pracovného profilu"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Zavrieť"</string> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index ffb74aeb164a..1d9c77ca1449 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Zaslon z obvestili."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Hitre nastavitve."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Hitre nastavitve in zaslon z obvestili"</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Zaklenjen zaslon"</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Zaklenjen zaslon delovnega profila"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Zapri"</string> diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml index 84a5f96f4b3d..5524812055bc 100644 --- a/packages/SystemUI/res/values-sq/strings.xml +++ b/packages/SystemUI/res/values-sq/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Streha e njoftimeve."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Cilësimet e shpejta."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"\"Cilësimet e shpejta\" dhe \"Streha e njoftimeve\"."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Ekrani i kyçjes."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Ekrani i kyçjes së punës"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Mbylle"</string> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index be4f200e9bbd..3ef8f3563bb8 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Meddelandepanel."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Snabbinställningar."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Snabbinställningar och meddelandepanel."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Låsskärm."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Låsskärm för arbete"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Stäng"</string> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index 4e04b6467820..46ffaa523470 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Kivuli cha arifa."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Mipangilio ya haraka."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Mipangilio ya haraka na Sehemu ya arifa."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Skrini iliyofungwa."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Skrini iliyofungwa ya kazini"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Funga"</string> @@ -1044,14 +1043,9 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Tumia wasifu wa kazini"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Funga"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"Mipangilio ya skrini iliyofungwa"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi haipatikani"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera imezuiwa"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera na maikrofoni zimezuiwa"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Maikrofoni imezuiwa"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Hali ya kipaumbele imewashwa"</string> </resources> diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml index 9ddbe9b6d491..a07cad6c7dba 100644 --- a/packages/SystemUI/res/values-te/strings.xml +++ b/packages/SystemUI/res/values-te/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"నోటిఫికేషన్ షేడ్."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"శీఘ్ర సెట్టింగ్లు."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"క్విక్ సెట్టింగ్లు, నోటిఫికేషన్ తెర."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"లాక్ స్క్రీన్."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"కార్యాలయ లాక్ స్క్రీన్"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"మూసివేస్తుంది"</string> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index c01929bec67b..33678874b7c5 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -1043,14 +1043,9 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"สลับไปใช้โปรไฟล์งาน"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"ปิด"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"การตั้งค่าหน้าจอล็อก"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi ไม่พร้อมใช้งาน"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"กล้องถูกบล็อกอยู่"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"กล้องและไมโครโฟนถูกบล็อกอยู่"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"ไมโครโฟนถูกบล็อกอยู่"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"โหมดลำดับความสำคัญเปิดอยู่"</string> </resources> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index d65704a89281..0c8bd82b8145 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Notification shade."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Mga mabilisang setting."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Mga mabilisang setting at Notification shade."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Lock screen."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Lock screen sa trabaho"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Isara"</string> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index 34b3b1f862ea..86d38da3ace4 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Bildirim gölgesi."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Hızlı ayarlar."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Hızlı ayarlar ve Bildirim gölgesi."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Kilit ekranı"</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"İş profili kilit ekranı"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Kapat"</string> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index e439bec78585..f544fcd545ca 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Панель сповіщень."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Швидке налаштування."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Швидкі налаштування й панель сповіщень."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Заблокований екран."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Екран блокування завдання"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Закрити"</string> @@ -1044,14 +1043,9 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Перейти в робочий профіль"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Закрити"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"Параметри заблокованого екрана"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Мережа Wi-Fi недоступна"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Камеру заблоковано"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Камеру й мікрофон заблоковано"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Мікрофон заблоковано"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Режим пріоритету ввімкнено"</string> </resources> diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml index 1d4385d60c46..0cc29aa94fe4 100644 --- a/packages/SystemUI/res/values-ur/strings.xml +++ b/packages/SystemUI/res/values-ur/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"اطلاعاتی شیڈ۔"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"فوری ترتیبات۔"</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"فوری ترتیبات اور اطلاعاتی شیڈ۔"</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"مقفل اسکرین۔"</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"دفتری مقفل اسکرین"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"بند کریں"</string> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index 1cb78ceecdf7..ec893ed3f519 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Bóng thông báo."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Cài đặt nhanh."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Cài đặt nhanh và ngăn thông báo."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Màn hình khóa."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Màn hình khóa công việc"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Đóng"</string> @@ -1044,14 +1043,9 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Chuyển sang hồ sơ công việc"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Đóng"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"Cài đặt màn hình khoá"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Không có Wi-Fi"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Máy ảnh bị chặn"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Máy ảnh và micrô bị chặn"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Micrô bị chặn"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Chế độ ưu tiên đang bật"</string> </resources> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index 25ea39d1f75e..7edc6ced44a2 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"通知栏。"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"快捷设置。"</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"快捷设置和通知栏。"</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"锁定屏幕。"</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"工作锁定屏幕"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"关闭"</string> @@ -959,7 +958,7 @@ <string name="mobile_data_settings_title" msgid="3955246641380064901">"移动数据网络"</string> <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string> <string name="mobile_data_connection_active" msgid="944490013299018227">"已连接"</string> - <string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"暂时已连接"</string> + <string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"已暂时连接"</string> <string name="mobile_data_poor_connection" msgid="819617772268371434">"连接状况不佳"</string> <string name="mobile_data_off_summary" msgid="3663995422004150567">"系统将不会自动连接到移动数据网络"</string> <string name="mobile_data_no_connection" msgid="1713872434869947377">"无网络连接"</string> diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml index 2bb1ab896522..a84a3f91291f 100644 --- a/packages/SystemUI/res/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"通知欄。"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"快速設定。"</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"快速設定和通知欄。"</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"上鎖畫面。"</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"工作螢幕鎖定"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"關閉"</string> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index 612005e20fd9..bb6e2d5b6d72 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"通知欄。"</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"快捷設定。"</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"快速設定和通知欄。"</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"螢幕鎖定。"</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Work 螢幕鎖定"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"關閉"</string> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index b3f96b03a9f1..77dfa881a19a 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -197,8 +197,7 @@ <skip /> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Umthunzi wesaziso."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Izilingiselelo ezisheshayo."</string> - <!-- no translation found for accessibility_desc_qs_notification_shade (8327226953072700376) --> - <skip /> + <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"Amasethingi asheshayo Nomthunzi wezaziso."</string> <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Khiya isikrini."</string> <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Ukukhiya isikrini somsebenzi"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"Vala"</string> @@ -1044,14 +1043,9 @@ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Shintshela kuphrofayela yomsebenzi"</string> <string name="call_from_work_profile_close" msgid="7927067108901068098">"Vala"</string> <string name="lock_screen_settings" msgid="9197175446592718435">"Amasethingi okukhiya isikrini"</string> - <!-- no translation found for wifi_unavailable_dream_overlay_content_description (2024166212194640100) --> - <skip /> - <!-- no translation found for camera_blocked_dream_overlay_content_description (4074759493559418130) --> - <skip /> - <!-- no translation found for camera_and_microphone_blocked_dream_overlay_content_description (7891078093416249764) --> - <skip /> - <!-- no translation found for microphone_blocked_dream_overlay_content_description (5466897982130007033) --> - <skip /> - <!-- no translation found for priority_mode_dream_overlay_content_description (6044561000253314632) --> - <skip /> + <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"I-Wi-Fi ayitholakali"</string> + <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Ikhamera ivinjiwe"</string> + <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Ikhamera nemakrofoni zivinjiwe"</string> + <string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Imakrofoni ivinjiwe"</string> + <string name="priority_mode_dream_overlay_content_description" msgid="6044561000253314632">"Imodi ebalulekile ivuliwe"</string> </resources> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 3f84ddb2a067..f545dae05b56 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -774,7 +774,7 @@ <!-- Duration in milliseconds of the dream in complications fade-in animation. --> <integer name="config_dreamOverlayInComplicationsDurationMs">250</integer> <!-- Duration in milliseconds of the y-translation animation when entering a dream --> - <integer name="config_dreamOverlayInTranslationYDurationMs">917</integer> + <integer name="config_dreamOverlayInTranslationYDurationMs">1167</integer> <!-- Delay in milliseconds before switching to the dock user and dreaming if a secondary user is active when the device is locked and docked. 0 indicates disabled. Default is 1 minute. --> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index bf949a0f4368..3b8f1a7d1e4d 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -196,9 +196,6 @@ <!-- Increased height of a small notification in the status bar --> <dimen name="notification_min_height_increased">146dp</dimen> - <!-- Increased height of a collapsed media notification in the status bar --> - <dimen name="notification_min_height_media">160dp</dimen> - <!-- Height of a small notification in the status bar which was used before android N --> <dimen name="notification_min_height_legacy">64dp</dimen> @@ -576,7 +573,7 @@ <dimen name="qs_tile_margin_horizontal">8dp</dimen> <dimen name="qs_tile_margin_vertical">@dimen/qs_tile_margin_horizontal</dimen> <dimen name="qs_tile_margin_top_bottom">4dp</dimen> - <dimen name="qs_brightness_margin_top">12dp</dimen> + <dimen name="qs_brightness_margin_top">8dp</dimen> <dimen name="qs_brightness_margin_bottom">16dp</dimen> <dimen name="qqs_layout_margin_top">16dp</dimen> <dimen name="qqs_layout_padding_bottom">24dp</dimen> @@ -628,7 +625,7 @@ <dimen name="qs_header_row_min_height">48dp</dimen> <dimen name="qs_header_non_clickable_element_height">24dp</dimen> - <dimen name="new_qs_header_non_clickable_element_height">20dp</dimen> + <dimen name="new_qs_header_non_clickable_element_height">24dp</dimen> <dimen name="qs_footer_padding">20dp</dimen> <dimen name="qs_security_footer_height">88dp</dimen> diff --git a/packages/SystemUI/res/values/flags.xml b/packages/SystemUI/res/values/flags.xml index 6354752e1b22..763930db1d55 100644 --- a/packages/SystemUI/res/values/flags.xml +++ b/packages/SystemUI/res/values/flags.xml @@ -30,9 +30,6 @@ <bool name="flag_charging_ripple">false</bool> - <!-- Whether to show chipbar UI whenever the device is unlocked by ActiveUnlock. --> - <bool name="flag_active_unlock_chipbar">true</bool> - <!-- Whether the user switcher chip shows in the status bar. When true, the multi user avatar will no longer show on the lockscreen --> <bool name="flag_user_switcher_chip">false</bool> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 48f257a7f4c9..9a9f5106b7d8 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -405,8 +405,6 @@ <!-- Message shown when the system-provided fingerprint dialog is shown, asking for authentication --> <string name="fingerprint_dialog_touch_sensor">Touch the fingerprint sensor</string> - <!-- Content description of the fingerprint icon when the system-provided fingerprint dialog is showing, for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> - <string name="accessibility_fingerprint_dialog_fingerprint_icon">Fingerprint icon</string> <!-- Message shown to inform the user a face cannot be recognized and fingerprint should instead be used.[CHAR LIMIT=50] --> <string name="fingerprint_dialog_use_fingerprint_instead">Can\u2019t recognize face. Use fingerprint instead.</string> <!-- Message shown to inform the user a face cannot be recognized and fingerprint should instead be used.[CHAR LIMIT=50] --> @@ -2260,7 +2258,7 @@ <!-- Shows in a dialog presented to the user to authorize this app to display a Device controls panel (embedded activity) instead of controls rendered by SystemUI [CHAR LIMIT=NONE] --> - <string name="controls_panel_authorization">When you add <xliff:g id="appName" example="My app">%s</xliff:g>, it can add controls and content to this panel. In some apps, you can choose which controls show up here.</string> + <string name="controls_panel_authorization"><xliff:g id="appName" example="My app">%s</xliff:g>can choose which controls and content show here.</string> <!-- Shows in a dialog presented to the user to authorize this app removal from a Device controls panel [CHAR LIMIT=NONE] --> @@ -2320,7 +2318,7 @@ <!-- Title of the dialog to control certain devices from lock screen without auth [CHAR LIMIT=NONE] --> <string name="controls_settings_trivial_controls_dialog_title">Control devices from lock screen?</string> <!-- Message of the dialog to control certain devices from lock screen without auth [CHAR LIMIT=NONE] --> - <string name="controls_settings_trivial_controls_dialog_message">You can control some devices without unlocking your phone or tablet.\n\nYour device app determines which devices can be controlled in this way.</string> + <string name="controls_settings_trivial_controls_dialog_message">You can control some devices without unlocking your phone or tablet. Your device app determines which devices can be controlled in this way.</string> <!-- Neutral button title of the controls dialog [CHAR LIMIT=NONE] --> <string name="controls_settings_dialog_neutral_button">No thanks</string> <!-- Positive button title of the controls dialog [CHAR LIMIT=NONE] --> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimator.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimator.kt index 12e0b9ab835a..c5979cc50c3c 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimator.kt +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimator.kt @@ -65,35 +65,40 @@ class UnfoldConstantTranslateAnimator( } else { 1 } - viewsToTranslate.forEach { (view, direction, shouldBeAnimated) -> - if (shouldBeAnimated()) { - view.get()?.translationX = xTrans * direction.multiplier * rtlMultiplier - } + viewsToTranslate.forEach { (view, direction) -> + view.get()?.translationX = xTrans * direction.multiplier * rtlMultiplier } } /** Finds in [parent] all views specified by [ids] and register them for the animation. */ private fun registerViewsForAnimation(parent: ViewGroup, ids: Set<ViewIdToTranslate>) { viewsToTranslate = - ids.mapNotNull { (id, dir, pred) -> - parent.findViewById<View>(id)?.let { view -> - ViewToTranslate(WeakReference(view), dir, pred) + ids.asSequence() + .filter { it.shouldBeAnimated() } + .mapNotNull { + parent.findViewById<View>(it.viewId)?.let { view -> + ViewToTranslate(WeakReference(view), it.direction) + } } - } + .toList() } - /** Represents a view to animate. [rootView] should contain a view with [viewId] inside. */ + /** + * Represents a view to animate. [rootView] should contain a view with [viewId] inside. + * [shouldBeAnimated] is only evaluated when the viewsToTranslate is registered in + * [registerViewsForAnimation]. + */ data class ViewIdToTranslate( val viewId: Int, val direction: Direction, val shouldBeAnimated: () -> Boolean = { true } ) - private data class ViewToTranslate( - val view: WeakReference<View>, - val direction: Direction, - val shouldBeAnimated: () -> Boolean - ) + /** + * Represents a view whose animation process is in-progress. It should be immutable because the + * started animation should be completed. + */ + private data class ViewToTranslate(val view: WeakReference<View>, val direction: Direction) /** Direction of the animation. */ enum class Direction(val multiplier: Float) { diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/condition/Evaluator.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/condition/Evaluator.kt index 23742c503ed3..454294f36d2a 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/condition/Evaluator.kt +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/condition/Evaluator.kt @@ -87,7 +87,7 @@ internal object Evaluator { * Helper for evaluating 3-valued logical AND/OR. * * @param returnValueIfAnyMatches AND returns false if any value is false. OR returns true if - * any value is true. + * any value is true. */ private fun threeValuedAndOrOr( conditions: Collection<Condition>, 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 6bfaf5e49820..b2add4f661cb 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 @@ -18,7 +18,6 @@ package com.android.systemui.shared.system; import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED; import static android.app.ActivityManager.LOCK_TASK_MODE_NONE; -import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED; import static android.app.ActivityTaskManager.getService; import android.annotation.NonNull; @@ -45,6 +44,7 @@ import android.os.ServiceManager; import android.os.SystemClock; import android.provider.Settings; import android.util.Log; +import android.view.Display; import android.view.IRecentsAnimationController; import android.view.IRecentsAnimationRunner; import android.view.RemoteAnimationTarget; @@ -112,6 +112,13 @@ public class ActivityManagerWrapper { } /** + * @see #getRunningTasks(boolean , int) + */ + public ActivityManager.RunningTaskInfo[] getRunningTasks(boolean filterOnlyVisibleRecents) { + return getRunningTasks(filterOnlyVisibleRecents, Display.INVALID_DISPLAY); + } + + /** * We ask for {@link #NUM_RECENT_ACTIVITIES_REQUEST} activities because when in split screen, * we'll get back 2 activities for each split app and one for launcher. Launcher might be more * "recently" used than one of the split apps so if we only request 2 tasks, then we might miss @@ -120,10 +127,12 @@ public class ActivityManagerWrapper { * @return an array of up to {@link #NUM_RECENT_ACTIVITIES_REQUEST} running tasks * filtering only for tasks that can be visible in the recent tasks list. */ - public ActivityManager.RunningTaskInfo[] getRunningTasks(boolean filterOnlyVisibleRecents) { + public ActivityManager.RunningTaskInfo[] getRunningTasks(boolean filterOnlyVisibleRecents, + int displayId) { // Note: The set of running tasks from the system is ordered by recency List<ActivityManager.RunningTaskInfo> tasks = - mAtm.getTasks(NUM_RECENT_ACTIVITIES_REQUEST, filterOnlyVisibleRecents); + mAtm.getTasks(NUM_RECENT_ACTIVITIES_REQUEST, + filterOnlyVisibleRecents, /* keepInExtras= */ false, displayId); return tasks.toArray(new RunningTaskInfo[tasks.size()]); } diff --git a/packages/SystemUI/src/com/android/keyguard/FaceAuthReason.kt b/packages/SystemUI/src/com/android/keyguard/FaceAuthReason.kt index e0cf7b6a2bc4..d8085b9f9f2e 100644 --- a/packages/SystemUI/src/com/android/keyguard/FaceAuthReason.kt +++ b/packages/SystemUI/src/com/android/keyguard/FaceAuthReason.kt @@ -132,6 +132,7 @@ private object InternalFaceAuthReasons { /** * UiEvents that are logged to identify why face auth is being triggered. + * * @param extraInfo is logged as the position. See [UiEventLogger#logWithInstanceIdAndPosition] */ enum class FaceAuthUiEvent diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt index fe8b8c944d13..c98e9b40e7ab 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt @@ -40,7 +40,7 @@ data class KeyguardFaceListenModel( var keyguardGoingAway: Boolean = false, var listeningForFaceAssistant: Boolean = false, var occludingAppRequestingFaceAuth: Boolean = false, - val postureAllowsListening: Boolean = false, + var postureAllowsListening: Boolean = false, var primaryUser: Boolean = false, var secureCameraLaunched: Boolean = false, var supportsDetect: Boolean = false, @@ -70,6 +70,7 @@ data class KeyguardFaceListenModel( listeningForFaceAssistant.toString(), occludingAppRequestingFaceAuth.toString(), primaryUser.toString(), + postureAllowsListening.toString(), secureCameraLaunched.toString(), supportsDetect.toString(), switchingUser.toString(), @@ -109,6 +110,7 @@ data class KeyguardFaceListenModel( listeningForFaceAssistant = model.listeningForFaceAssistant occludingAppRequestingFaceAuth = model.occludingAppRequestingFaceAuth primaryUser = model.primaryUser + postureAllowsListening = model.postureAllowsListening secureCameraLaunched = model.secureCameraLaunched supportsDetect = model.supportsDetect switchingUser = model.switchingUser @@ -152,6 +154,7 @@ data class KeyguardFaceListenModel( "listeningForFaceAssistant", "occludingAppRequestingFaceAuth", "primaryUser", + "postureAllowsListening", "secureCameraLaunched", "supportsDetect", "switchingUser", diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java index c1fae9e44bd3..33bea027cd20 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java @@ -69,6 +69,7 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView { private Interpolator mLinearOutSlowInInterpolator; private Interpolator mFastOutLinearInInterpolator; + private DisappearAnimationListener mDisappearAnimationListener; public KeyguardPasswordView(Context context) { this(context, null); @@ -186,9 +187,13 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView { return; } Insets shownInsets = controller.getShownStateInsets(); - Insets insets = Insets.add(shownInsets, Insets.of(0, 0, 0, - (int) (-shownInsets.bottom / 4 - * anim.getAnimatedFraction()))); + int dist = (int) (-shownInsets.bottom / 4 + * anim.getAnimatedFraction()); + Insets insets = Insets.add(shownInsets, Insets.of(0, 0, 0, dist)); + if (mDisappearAnimationListener != null) { + mDisappearAnimationListener.setTranslationY(-dist); + } + controller.setInsetsAndAlpha(insets, (float) animation.getAnimatedValue(), anim.getAnimatedFraction()); @@ -209,6 +214,7 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView { controller.finish(false); runOnFinishImeAnimationRunnable(); finishRunnable.run(); + mDisappearAnimationListener = null; Trace.endSection(); }); } @@ -286,4 +292,19 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView { } }); } + + /** + * Listens to the progress of the disappear animation and handles it. + */ + interface DisappearAnimationListener { + void setTranslationY(int transY); + } + + /** + * Set an instance of the disappear animation listener to this class. This will be + * removed when the animation completes. + */ + public void setDisappearAnimationListener(DisappearAnimationListener listener) { + mDisappearAnimationListener = listener; + } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java index f164e7d33642..66d5d097ab04 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java @@ -39,7 +39,6 @@ import static java.lang.Integer.max; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; -import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.app.Activity; @@ -174,6 +173,17 @@ public class KeyguardSecurityContainer extends ConstraintLayout { private @Mode int mCurrentMode = MODE_UNINITIALIZED; private int mWidth = -1; + /** + * This callback is used to animate KeyguardSecurityContainer and its child views based on + * the interaction with the ime. After + * {@link WindowInsetsAnimation.Callback#onPrepare(WindowInsetsAnimation)}, + * {@link #onApplyWindowInsets} is called where we + * set the bottom padding to be the height of the keyboard. We use this padding to determine + * the delta of vertical distance for y-translation animations. + * Note that bottom padding is not set when the disappear animation is started because + * we are deferring the y translation logic to the animator in + * {@link KeyguardPasswordView#startDisappearAnimation(Runnable)} + */ private final WindowInsetsAnimation.Callback mWindowInsetsAnimationCallback = new WindowInsetsAnimation.Callback(DISPATCH_MODE_STOP) { @@ -214,7 +224,6 @@ public class KeyguardSecurityContainer extends ConstraintLayout { continue; } interpolatedFraction = animation.getInterpolatedFraction(); - final int paddingBottom = (int) MathUtils.lerp( start, end, interpolatedFraction); @@ -569,13 +578,21 @@ public class KeyguardSecurityContainer extends ConstraintLayout { */ public void startDisappearAnimation(SecurityMode securitySelection) { mDisappearAnimRunning = true; - mViewMode.startDisappearAnimation(securitySelection); + if (securitySelection == SecurityMode.Password + && mSecurityViewFlipper.getSecurityView() instanceof KeyguardPasswordView) { + ((KeyguardPasswordView) mSecurityViewFlipper.getSecurityView()) + .setDisappearAnimationListener(this::setTranslationY); + } else { + mViewMode.startDisappearAnimation(securitySelection); + } } /** * This will run when the bouncer shows in all cases except when the user drags the bouncer up. */ public void startAppearAnimation(SecurityMode securityMode) { + setTranslationY(0f); + setAlpha(1f); updateChildren(0 /* translationY */, 1f /* alpha */); mViewMode.startAppearAnimation(securityMode); } @@ -624,7 +641,13 @@ public class KeyguardSecurityContainer extends ConstraintLayout { int inset = max(bottomInset, imeInset); int paddingBottom = max(inset, getContext().getResources() .getDimensionPixelSize(R.dimen.keyguard_security_view_bottom_margin)); - setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), paddingBottom); + // If security mode is password, we rely on the animation value of defined in + // KeyguardPasswordView to determine the y translation animation. + // This means that we will prevent the WindowInsetsAnimationCallback from setting any y + // translation values by preventing the setting of the padding here. + if (!mDisappearAnimRunning) { + setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), paddingBottom); + } return insets.inset(0, 0, 0, inset); } @@ -1044,13 +1067,10 @@ public class KeyguardSecurityContainer extends ConstraintLayout { int yTranslation = mResources.getDimensionPixelSize(R.dimen.disappear_y_translation); - AnimatorSet anims = new AnimatorSet(); ObjectAnimator yAnim = ObjectAnimator.ofFloat(mView, View.TRANSLATION_Y, yTranslation); - ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(mView, View.ALPHA, 0f); - - anims.setInterpolator(Interpolators.STANDARD_ACCELERATE); - anims.playTogether(alphaAnim, yAnim); - anims.start(); + yAnim.setInterpolator(Interpolators.STANDARD_ACCELERATE); + yAnim.setDuration(500); + yAnim.start(); } private void setupUserSwitcher() { diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java index b8bb2603fa03..c32b8530d589 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java @@ -636,12 +636,17 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard public void startAppearAnimation() { if (mCurrentSecurityMode != SecurityMode.None) { - mView.setAlpha(1f); + setAlpha(1f); mView.startAppearAnimation(mCurrentSecurityMode); getCurrentSecurityController().startAppearAnimation(); } } + /** Set the alpha of the security container view */ + public void setAlpha(float alpha) { + mView.setAlpha(alpha); + } + public boolean startDisappearAnimation(Runnable onFinishRunnable) { boolean didRunAnimation = false; diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index be013770519f..2370c8a27da7 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -153,6 +153,7 @@ import com.android.systemui.shared.system.TaskStackChangeListeners; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.policy.DevicePostureController; +import com.android.systemui.statusbar.policy.DevicePostureController.DevicePostureInt; import com.android.systemui.telephony.TelephonyListenerManager; import com.android.systemui.util.Assert; import com.android.systemui.util.settings.SecureSettings; @@ -359,7 +360,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab private final FaceManager mFaceManager; private final LockPatternUtils mLockPatternUtils; @VisibleForTesting - @DevicePostureController.DevicePostureInt + @DevicePostureInt protected int mConfigFaceAuthSupportedPosture; private KeyguardBypassController mKeyguardBypassController; @@ -676,7 +677,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab public void onTrustManagedChanged(boolean managed, int userId) { Assert.isMainThread(); mUserTrustIsManaged.put(userId, managed); - mUserTrustIsUsuallyManaged.put(userId, mTrustManager.isTrustUsuallyManaged(userId)); + boolean trustUsuallyManaged = mTrustManager.isTrustUsuallyManaged(userId); + mLogger.logTrustUsuallyManagedUpdated(userId, mUserTrustIsUsuallyManaged.get(userId), + trustUsuallyManaged, "onTrustManagedChanged"); + mUserTrustIsUsuallyManaged.put(userId, trustUsuallyManaged); for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); if (cb != null) { @@ -864,7 +868,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab private void reportSuccessfulBiometricUnlock(boolean isStrongBiometric, int userId) { mBackgroundExecutor.execute( - () -> mLockPatternUtils.reportSuccessfulBiometricUnlock(isStrongBiometric, userId)); + () -> { + mLogger.logReportSuccessfulBiometricUnlock(isStrongBiometric, userId); + mLockPatternUtils.reportSuccessfulBiometricUnlock(isStrongBiometric, userId); + }); } private void handleFingerprintAuthFailed() { @@ -1840,10 +1847,15 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab final DevicePostureController.Callback mPostureCallback = new DevicePostureController.Callback() { @Override - public void onPostureChanged(int posture) { + public void onPostureChanged(@DevicePostureInt int posture) { + boolean currentPostureAllowsFaceAuth = doesPostureAllowFaceAuth(mPostureState); + boolean newPostureAllowsFaceAuth = doesPostureAllowFaceAuth(posture); mPostureState = posture; - updateFaceListeningState(BIOMETRIC_ACTION_UPDATE, - FACE_AUTH_UPDATED_POSTURE_CHANGED); + if (currentPostureAllowsFaceAuth && !newPostureAllowsFaceAuth) { + mLogger.d("New posture does not allow face auth, stopping it"); + updateFaceListeningState(BIOMETRIC_ACTION_STOP, + FACE_AUTH_UPDATED_POSTURE_CHANGED); + } } }; @@ -2372,8 +2384,12 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab updateSecondaryLockscreenRequirement(user); List<UserInfo> allUsers = mUserManager.getUsers(); for (UserInfo userInfo : allUsers) { + boolean trustUsuallyManaged = mTrustManager.isTrustUsuallyManaged(userInfo.id); + mLogger.logTrustUsuallyManagedUpdated(userInfo.id, + mUserTrustIsUsuallyManaged.get(userInfo.id), + trustUsuallyManaged, "init from constructor"); mUserTrustIsUsuallyManaged.put(userInfo.id, - mTrustManager.isTrustUsuallyManaged(userInfo.id)); + trustUsuallyManaged); } updateAirplaneModeState(); @@ -2413,10 +2429,12 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } private void updateFaceEnrolled(int userId) { - mIsFaceEnrolled = whitelistIpcs( + Boolean isFaceEnrolled = whitelistIpcs( () -> mFaceManager != null && mFaceManager.isHardwareDetected() && mFaceManager.hasEnrolledTemplates(userId) && mBiometricEnabledForUser.get(userId)); + mIsFaceEnrolled = isFaceEnrolled; + mLogger.logFaceEnrolledUpdated(mIsFaceEnrolled, isFaceEnrolled); } public boolean isFaceSupported() { @@ -2495,11 +2513,13 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab // If this message exists, we should not authenticate again until this message is // consumed by the handler if (mHandler.hasMessages(MSG_BIOMETRIC_AUTHENTICATION_CONTINUE)) { + mLogger.logHandlerHasAuthContinueMsgs(action); return; } // don't start running fingerprint until they're registered if (!mAuthController.areAllFingerprintAuthenticatorsRegistered()) { + mLogger.d("All FP authenticators not registered, skipping FP listening state update"); return; } final boolean shouldListenForFingerprint = shouldListenForFingerprint(isUdfpsSupported()); @@ -2872,9 +2892,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab final boolean biometricEnabledForUser = mBiometricEnabledForUser.get(user); final boolean shouldListenForFaceAssistant = shouldListenForFaceAssistant(); final boolean isUdfpsFingerDown = mAuthController.isUdfpsFingerDown(); - final boolean isPostureAllowedForFaceAuth = - mConfigFaceAuthSupportedPosture == 0 /* DEVICE_POSTURE_UNKNOWN */ ? true - : (mPostureState == mConfigFaceAuthSupportedPosture); + final boolean isPostureAllowedForFaceAuth = doesPostureAllowFaceAuth(mPostureState); // Only listen if this KeyguardUpdateMonitor belongs to the primary user. There is an // instance of KeyguardUpdateMonitor for each user but KeyguardUpdateMonitor is user-aware. final boolean shouldListen = @@ -2923,6 +2941,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab return shouldListen; } + private boolean doesPostureAllowFaceAuth(@DevicePostureInt int posture) { + return mConfigFaceAuthSupportedPosture == DEVICE_POSTURE_UNKNOWN + || (posture == mConfigFaceAuthSupportedPosture); + } + private void logListenerModelData(@NonNull KeyguardListenModel model) { mLogger.logKeyguardListenerModel(model); if (model instanceof KeyguardFingerprintListenModel) { @@ -3071,8 +3094,12 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab @VisibleForTesting boolean isUnlockWithFingerprintPossible(int userId) { // TODO (b/242022358), make this rely on onEnrollmentChanged event and update it only once. - mIsUnlockWithFingerprintPossible.put(userId, mFpm != null && mFpm.isHardwareDetected() - && !isFingerprintDisabled(userId) && mFpm.hasEnrolledTemplates(userId)); + boolean fpEnrolled = mFpm != null && mFpm.isHardwareDetected() + && !isFingerprintDisabled(userId) && mFpm.hasEnrolledTemplates(userId); + mLogger.logFpEnrolledUpdated(userId, + mIsUnlockWithFingerprintPossible.getOrDefault(userId, false), + fpEnrolled); + mIsUnlockWithFingerprintPossible.put(userId, fpEnrolled); return mIsUnlockWithFingerprintPossible.get(userId); } @@ -3188,7 +3215,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab void handleUserSwitching(int userId, CountDownLatch latch) { Assert.isMainThread(); clearBiometricRecognized(); - mUserTrustIsUsuallyManaged.put(userId, mTrustManager.isTrustUsuallyManaged(userId)); + boolean trustUsuallyManaged = mTrustManager.isTrustUsuallyManaged(userId); + mLogger.logTrustUsuallyManagedUpdated(userId, mUserTrustIsUsuallyManaged.get(userId), + trustUsuallyManaged, "userSwitching"); + mUserTrustIsUsuallyManaged.put(userId, trustUsuallyManaged); for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); if (cb != null) { diff --git a/packages/SystemUI/src/com/android/keyguard/logging/BiometricUnlockLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/BiometricUnlockLogger.kt index bc0bd8c53d26..20f90072161b 100644 --- a/packages/SystemUI/src/com/android/keyguard/logging/BiometricUnlockLogger.kt +++ b/packages/SystemUI/src/com/android/keyguard/logging/BiometricUnlockLogger.kt @@ -16,6 +16,7 @@ package com.android.keyguard.logging +import android.hardware.biometrics.BiometricSourceType import com.android.systemui.dagger.SysUISingleton import com.android.systemui.log.dagger.BiometricLog import com.android.systemui.plugins.log.LogBuffer @@ -157,6 +158,36 @@ class BiometricUnlockLogger @Inject constructor(@BiometricLog private val logBuf } ) } + + fun deferringAuthenticationDueToSleep( + userId: Int, + biometricSourceType: BiometricSourceType, + alreadyPendingAuth: Boolean + ) { + logBuffer.log( + TAG, + DEBUG, + { + int1 = userId + str1 = biometricSourceType.name + bool2 = alreadyPendingAuth + }, + { + "onBiometricAuthenticated, deferring auth: userId: $int1, " + + "biometricSourceType: $str1, " + + "goingToSleep: true, " + + "mPendingAuthentication != null: $bool2" + } + ) + } + + fun finishedGoingToSleepWithPendingAuth() { + logBuffer.log( + TAG, + LogLevel.DEBUG, + "onFinishedGoingToSleep with pendingAuthenticated != null" + ) + } } private fun wakeAndUnlockModeToString(mode: Int): String { diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt index 379c78ad8d0e..51aca070b180 100644 --- a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt +++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt @@ -16,6 +16,7 @@ package com.android.keyguard.logging +import com.android.systemui.biometrics.AuthRippleController import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController import com.android.systemui.log.dagger.KeyguardLog import com.android.systemui.plugins.log.LogBuffer @@ -120,4 +121,29 @@ constructor( "type=${KeyguardIndicationRotateTextViewController.indicationTypeToString(type)}" } } + + fun notShowingUnlockRipple(keyguardNotShowing: Boolean, unlockNotAllowed: Boolean) { + buffer.log( + AuthRippleController.TAG, + LogLevel.DEBUG, + { + bool1 = keyguardNotShowing + bool2 = unlockNotAllowed + }, + { "Not showing unlock ripple: keyguardNotShowing: $bool1, unlockNotAllowed: $bool2" } + ) + } + + fun showingUnlockRippleAt(x: Int, y: Int, context: String) { + buffer.log( + AuthRippleController.TAG, + LogLevel.DEBUG, + { + int1 = x + int2 = y + str1 = context + }, + { "Showing unlock ripple with center (x, y): ($int1, $int2), context: $str1" } + ) + } } diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt index e53f6adb62a4..2403d1116360 100644 --- a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt +++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt @@ -26,6 +26,7 @@ import com.android.keyguard.FaceAuthUiEvent import com.android.keyguard.KeyguardListenModel import com.android.keyguard.KeyguardUpdateMonitorCallback import com.android.keyguard.TrustGrantFlags +import com.android.systemui.log.dagger.KeyguardUpdateMonitorLog import com.android.systemui.plugins.log.LogBuffer import com.android.systemui.plugins.log.LogLevel import com.android.systemui.plugins.log.LogLevel.DEBUG @@ -33,18 +34,15 @@ import com.android.systemui.plugins.log.LogLevel.ERROR import com.android.systemui.plugins.log.LogLevel.INFO import com.android.systemui.plugins.log.LogLevel.VERBOSE import com.android.systemui.plugins.log.LogLevel.WARNING -import com.android.systemui.log.dagger.KeyguardUpdateMonitorLog import com.google.errorprone.annotations.CompileTimeConstant import javax.inject.Inject private const val TAG = "KeyguardUpdateMonitorLog" -/** - * Helper class for logging for [com.android.keyguard.KeyguardUpdateMonitor] - */ -class KeyguardUpdateMonitorLogger @Inject constructor( - @KeyguardUpdateMonitorLog private val logBuffer: LogBuffer -) { +/** Helper class for logging for [com.android.keyguard.KeyguardUpdateMonitor] */ +class KeyguardUpdateMonitorLogger +@Inject +constructor(@KeyguardUpdateMonitorLog private val logBuffer: LogBuffer) { fun d(@CompileTimeConstant msg: String) = log(msg, DEBUG) fun e(@CompileTimeConstant msg: String) = log(msg, ERROR) @@ -56,15 +54,16 @@ class KeyguardUpdateMonitorLogger @Inject constructor( fun log(@CompileTimeConstant msg: String, level: LogLevel) = logBuffer.log(TAG, level, msg) fun logActiveUnlockTriggered(reason: String?) { - logBuffer.log("ActiveUnlock", DEBUG, - { str1 = reason }, - { "initiate active unlock triggerReason=$str1" }) + logBuffer.log( + "ActiveUnlock", + DEBUG, + { str1 = reason }, + { "initiate active unlock triggerReason=$str1" } + ) } fun logAuthInterruptDetected(active: Boolean) { - logBuffer.log(TAG, DEBUG, - { bool1 = active }, - { "onAuthInterruptDetected($bool1)" }) + logBuffer.log(TAG, DEBUG, { bool1 = active }, { "onAuthInterruptDetected($bool1)" }) } fun logBroadcastReceived(action: String?) { @@ -72,9 +71,12 @@ class KeyguardUpdateMonitorLogger @Inject constructor( } fun logDeviceProvisionedState(deviceProvisioned: Boolean) { - logBuffer.log(TAG, DEBUG, - { bool1 = deviceProvisioned }, - { "DEVICE_PROVISIONED state = $bool1" }) + logBuffer.log( + TAG, + DEBUG, + { bool1 = deviceProvisioned }, + { "DEVICE_PROVISIONED state = $bool1" } + ) } fun logException(ex: Exception, @CompileTimeConstant logMsg: String) { @@ -82,46 +84,56 @@ class KeyguardUpdateMonitorLogger @Inject constructor( } fun logFaceAcquired(acquireInfo: Int) { - logBuffer.log(TAG, DEBUG, - { int1 = acquireInfo }, - { "Face acquired acquireInfo=$int1" }) + logBuffer.log(TAG, DEBUG, { int1 = acquireInfo }, { "Face acquired acquireInfo=$int1" }) } fun logFaceAuthDisabledForUser(userId: Int) { - logBuffer.log(TAG, DEBUG, - { int1 = userId }, - { "Face authentication disabled by DPM for userId: $int1" }) + logBuffer.log( + TAG, + DEBUG, + { int1 = userId }, + { "Face authentication disabled by DPM for userId: $int1" } + ) } fun logFaceAuthError(msgId: Int, originalErrMsg: String) { - logBuffer.log(TAG, DEBUG, { - str1 = originalErrMsg - int1 = msgId - }, { "Face error received: $str1 msgId= $int1" }) + logBuffer.log( + TAG, + DEBUG, + { + str1 = originalErrMsg + int1 = msgId + }, + { "Face error received: $str1 msgId= $int1" } + ) } fun logFaceAuthForWrongUser(authUserId: Int) { - logBuffer.log(TAG, DEBUG, - { int1 = authUserId }, - { "Face authenticated for wrong user: $int1" }) + logBuffer.log( + TAG, + DEBUG, + { int1 = authUserId }, + { "Face authenticated for wrong user: $int1" } + ) } fun logFaceAuthHelpMsg(msgId: Int, helpMsg: String?) { - logBuffer.log(TAG, DEBUG, { - int1 = msgId - str1 = helpMsg - }, { "Face help received, msgId: $int1 msg: $str1" }) + logBuffer.log( + TAG, + DEBUG, + { + int1 = msgId + str1 = helpMsg + }, + { "Face help received, msgId: $int1 msg: $str1" } + ) } fun logFaceAuthRequested(reason: String?) { - logBuffer.log(TAG, DEBUG, { - str1 = reason - }, { "requestFaceAuth() reason=$str1" }) + logBuffer.log(TAG, DEBUG, { str1 = reason }, { "requestFaceAuth() reason=$str1" }) } fun logFaceAuthSuccess(userId: Int) { - logBuffer.log(TAG, DEBUG, - { int1 = userId }, - { "Face auth succeeded for user $int1" }) + logBuffer.log(TAG, DEBUG, { int1 = userId }, { "Face auth succeeded for user $int1" }) } fun logFaceLockoutReset(@LockoutMode mode: Int) { @@ -133,21 +145,30 @@ class KeyguardUpdateMonitorLogger @Inject constructor( } fun logFaceUnlockPossible(isFaceUnlockPossible: Boolean) { - logBuffer.log(TAG, DEBUG, - { bool1 = isFaceUnlockPossible }, - {"isUnlockWithFacePossible: $bool1"}) + logBuffer.log( + TAG, + DEBUG, + { bool1 = isFaceUnlockPossible }, + { "isUnlockWithFacePossible: $bool1" } + ) } fun logFingerprintAuthForWrongUser(authUserId: Int) { - logBuffer.log(TAG, DEBUG, - { int1 = authUserId }, - { "Fingerprint authenticated for wrong user: $int1" }) + logBuffer.log( + TAG, + DEBUG, + { int1 = authUserId }, + { "Fingerprint authenticated for wrong user: $int1" } + ) } fun logFingerprintDisabledForUser(userId: Int) { - logBuffer.log(TAG, DEBUG, - { int1 = userId }, - { "Fingerprint disabled by DPM for userId: $int1" }) + logBuffer.log( + TAG, + DEBUG, + { int1 = userId }, + { "Fingerprint disabled by DPM for userId: $int1" } + ) } fun logFingerprintLockoutReset(@LockoutMode mode: Int) { @@ -155,16 +176,24 @@ class KeyguardUpdateMonitorLogger @Inject constructor( } fun logFingerprintRunningState(fingerprintRunningState: Int) { - logBuffer.log(TAG, DEBUG, - { int1 = fingerprintRunningState }, - { "fingerprintRunningState: $int1" }) + logBuffer.log( + TAG, + DEBUG, + { int1 = fingerprintRunningState }, + { "fingerprintRunningState: $int1" } + ) } fun logFingerprintSuccess(userId: Int, isStrongBiometric: Boolean) { - logBuffer.log(TAG, DEBUG, { - int1 = userId - bool1 = isStrongBiometric - }, {"Fingerprint auth successful: userId: $int1, isStrongBiometric: $bool1"}) + logBuffer.log( + TAG, + DEBUG, + { + int1 = userId + bool1 = isStrongBiometric + }, + { "Fingerprint auth successful: userId: $int1, isStrongBiometric: $bool1" } + ) } fun logFaceDetected(userId: Int, isStrongBiometric: Boolean) { @@ -182,29 +211,42 @@ class KeyguardUpdateMonitorLogger @Inject constructor( } fun logFingerprintError(msgId: Int, originalErrMsg: String) { - logBuffer.log(TAG, DEBUG, { - str1 = originalErrMsg - int1 = msgId - }, { "Fingerprint error received: $str1 msgId= $int1" }) + logBuffer.log( + TAG, + DEBUG, + { + str1 = originalErrMsg + int1 = msgId + }, + { "Fingerprint error received: $str1 msgId= $int1" } + ) } fun logInvalidSubId(subId: Int) { - logBuffer.log(TAG, INFO, - { int1 = subId }, - { "Previously active sub id $int1 is now invalid, will remove" }) + logBuffer.log( + TAG, + INFO, + { int1 = subId }, + { "Previously active sub id $int1 is now invalid, will remove" } + ) } fun logPrimaryKeyguardBouncerChanged( - primaryBouncerIsOrWillBeShowing: Boolean, - primaryBouncerFullyShown: Boolean + primaryBouncerIsOrWillBeShowing: Boolean, + primaryBouncerFullyShown: Boolean ) { - logBuffer.log(TAG, DEBUG, { - bool1 = primaryBouncerIsOrWillBeShowing - bool2 = primaryBouncerFullyShown - }, { - "handlePrimaryBouncerChanged " + + logBuffer.log( + TAG, + DEBUG, + { + bool1 = primaryBouncerIsOrWillBeShowing + bool2 = primaryBouncerFullyShown + }, + { + "handlePrimaryBouncerChanged " + "primaryBouncerIsOrWillBeShowing=$bool1 primaryBouncerFullyShown=$bool2" - }) + } + ) } fun logKeyguardListenerModel(model: KeyguardListenModel) { @@ -212,98 +254,134 @@ class KeyguardUpdateMonitorLogger @Inject constructor( } fun logKeyguardShowingChanged(showing: Boolean, occluded: Boolean, visible: Boolean) { - logBuffer.log(TAG, DEBUG, { - bool1 = showing - bool2 = occluded - bool3 = visible - }, { - "keyguardShowingChanged(showing=$bool1 occluded=$bool2 visible=$bool3)" - }) + logBuffer.log( + TAG, + DEBUG, + { + bool1 = showing + bool2 = occluded + bool3 = visible + }, + { "keyguardShowingChanged(showing=$bool1 occluded=$bool2 visible=$bool3)" } + ) } fun logMissingSupervisorAppError(userId: Int) { - logBuffer.log(TAG, ERROR, - { int1 = userId }, - { "No Profile Owner or Device Owner supervision app found for User $int1" }) + logBuffer.log( + TAG, + ERROR, + { int1 = userId }, + { "No Profile Owner or Device Owner supervision app found for User $int1" } + ) } fun logPhoneStateChanged(newState: String?) { - logBuffer.log(TAG, DEBUG, - { str1 = newState }, - { "handlePhoneStateChanged($str1)" }) + logBuffer.log(TAG, DEBUG, { str1 = newState }, { "handlePhoneStateChanged($str1)" }) } fun logRegisterCallback(callback: KeyguardUpdateMonitorCallback?) { - logBuffer.log(TAG, VERBOSE, - { str1 = "$callback" }, - { "*** register callback for $str1" }) + logBuffer.log(TAG, VERBOSE, { str1 = "$callback" }, { "*** register callback for $str1" }) } fun logRetryingAfterFaceHwUnavailable(retryCount: Int) { - logBuffer.log(TAG, WARNING, - { int1 = retryCount }, - { "Retrying face after HW unavailable, attempt $int1" }) + logBuffer.log( + TAG, + WARNING, + { int1 = retryCount }, + { "Retrying face after HW unavailable, attempt $int1" } + ) } fun logRetryAfterFpErrorWithDelay(msgId: Int, errString: String?, delay: Int) { - logBuffer.log(TAG, DEBUG, { - int1 = msgId - int2 = delay - str1 = "$errString" - }, { - "Fingerprint scheduling retry auth after $int2 ms due to($int1) -> $str1" - }) + logBuffer.log( + TAG, + DEBUG, + { + int1 = msgId + int2 = delay + str1 = "$errString" + }, + { "Fingerprint scheduling retry auth after $int2 ms due to($int1) -> $str1" } + ) } fun logRetryAfterFpHwUnavailable(retryCount: Int) { - logBuffer.log(TAG, WARNING, - { int1 = retryCount }, - { "Retrying fingerprint attempt: $int1" }) + logBuffer.log( + TAG, + WARNING, + { int1 = retryCount }, + { "Retrying fingerprint attempt: $int1" } + ) } fun logSendPrimaryBouncerChanged( primaryBouncerIsOrWillBeShowing: Boolean, primaryBouncerFullyShown: Boolean, ) { - logBuffer.log(TAG, DEBUG, { - bool1 = primaryBouncerIsOrWillBeShowing - bool2 = primaryBouncerFullyShown - }, { - "sendPrimaryBouncerChanged primaryBouncerIsOrWillBeShowing=$bool1 " + + logBuffer.log( + TAG, + DEBUG, + { + bool1 = primaryBouncerIsOrWillBeShowing + bool2 = primaryBouncerFullyShown + }, + { + "sendPrimaryBouncerChanged primaryBouncerIsOrWillBeShowing=$bool1 " + "primaryBouncerFullyShown=$bool2" - }) + } + ) } fun logServiceStateChange(subId: Int, serviceState: ServiceState?) { - logBuffer.log(TAG, DEBUG, { - int1 = subId - str1 = "$serviceState" - }, { "handleServiceStateChange(subId=$int1, serviceState=$str1)" }) + logBuffer.log( + TAG, + DEBUG, + { + int1 = subId + str1 = "$serviceState" + }, + { "handleServiceStateChange(subId=$int1, serviceState=$str1)" } + ) } fun logServiceStateIntent(action: String?, serviceState: ServiceState?, subId: Int) { - logBuffer.log(TAG, VERBOSE, { - str1 = action - str2 = "$serviceState" - int1 = subId - }, { "action $str1 serviceState=$str2 subId=$int1" }) + logBuffer.log( + TAG, + VERBOSE, + { + str1 = action + str2 = "$serviceState" + int1 = subId + }, + { "action $str1 serviceState=$str2 subId=$int1" } + ) } fun logSimState(subId: Int, slotId: Int, state: Int) { - logBuffer.log(TAG, DEBUG, { - int1 = subId - int2 = slotId - long1 = state.toLong() - }, { "handleSimStateChange(subId=$int1, slotId=$int2, state=$long1)" }) + logBuffer.log( + TAG, + DEBUG, + { + int1 = subId + int2 = slotId + long1 = state.toLong() + }, + { "handleSimStateChange(subId=$int1, slotId=$int2, state=$long1)" } + ) } fun logSimStateFromIntent(action: String?, extraSimState: String?, slotId: Int, subId: Int) { - logBuffer.log(TAG, VERBOSE, { - str1 = action - str2 = extraSimState - int1 = slotId - int2 = subId - }, { "action $str1 state: $str2 slotId: $int1 subid: $int2" }) + logBuffer.log( + TAG, + VERBOSE, + { + str1 = action + str2 = extraSimState + int1 = slotId + int2 = subId + }, + { "action $str1 state: $str2 slotId: $int1 subid: $int2" } + ) } fun logSimUnlocked(subId: Int) { @@ -311,78 +389,98 @@ class KeyguardUpdateMonitorLogger @Inject constructor( } fun logStartedListeningForFace(faceRunningState: Int, faceAuthUiEvent: FaceAuthUiEvent) { - logBuffer.log(TAG, VERBOSE, { - int1 = faceRunningState - str1 = faceAuthUiEvent.reason - str2 = faceAuthUiEvent.extraInfoToString() - }, { "startListeningForFace(): $int1, reason: $str1 $str2" }) + logBuffer.log( + TAG, + VERBOSE, + { + int1 = faceRunningState + str1 = faceAuthUiEvent.reason + str2 = faceAuthUiEvent.extraInfoToString() + }, + { "startListeningForFace(): $int1, reason: $str1 $str2" } + ) } fun logStartedListeningForFaceFromWakeUp(faceRunningState: Int, @WakeReason pmWakeReason: Int) { - logBuffer.log(TAG, VERBOSE, { - int1 = faceRunningState - str1 = PowerManager.wakeReasonToString(pmWakeReason) - }, { "startListeningForFace(): $int1, reason: wakeUp-$str1" }) + logBuffer.log( + TAG, + VERBOSE, + { + int1 = faceRunningState + str1 = PowerManager.wakeReasonToString(pmWakeReason) + }, + { "startListeningForFace(): $int1, reason: wakeUp-$str1" } + ) } fun logStoppedListeningForFace(faceRunningState: Int, faceAuthReason: String) { - logBuffer.log(TAG, VERBOSE, { - int1 = faceRunningState - str1 = faceAuthReason - }, { "stopListeningForFace(): currentFaceRunningState: $int1, reason: $str1" }) + logBuffer.log( + TAG, + VERBOSE, + { + int1 = faceRunningState + str1 = faceAuthReason + }, + { "stopListeningForFace(): currentFaceRunningState: $int1, reason: $str1" } + ) } fun logSubInfo(subInfo: SubscriptionInfo?) { - logBuffer.log(TAG, VERBOSE, - { str1 = "$subInfo" }, - { "SubInfo:$str1" }) + logBuffer.log(TAG, VERBOSE, { str1 = "$subInfo" }, { "SubInfo:$str1" }) } fun logTimeFormatChanged(newTimeFormat: String?) { - logBuffer.log(TAG, DEBUG, - { str1 = newTimeFormat }, - { "handleTimeFormatUpdate timeFormat=$str1" }) + logBuffer.log( + TAG, + DEBUG, + { str1 = newTimeFormat }, + { "handleTimeFormatUpdate timeFormat=$str1" } + ) } fun logUdfpsPointerDown(sensorId: Int) { - logBuffer.log(TAG, DEBUG, - { int1 = sensorId }, - { "onUdfpsPointerDown, sensorId: $int1" }) + logBuffer.log(TAG, DEBUG, { int1 = sensorId }, { "onUdfpsPointerDown, sensorId: $int1" }) } fun logUdfpsPointerUp(sensorId: Int) { - logBuffer.log(TAG, DEBUG, - { int1 = sensorId }, - { "onUdfpsPointerUp, sensorId: $int1" }) + logBuffer.log(TAG, DEBUG, { int1 = sensorId }, { "onUdfpsPointerUp, sensorId: $int1" }) } fun logUnexpectedFaceCancellationSignalState(faceRunningState: Int, unlockPossible: Boolean) { - logBuffer.log(TAG, ERROR, { - int1 = faceRunningState - bool1 = unlockPossible - }, { - "Cancellation signal is not null, high chance of bug in " + - "face auth lifecycle management. " + - "Face state: $int1, unlockPossible: $bool1" - }) + logBuffer.log( + TAG, + ERROR, + { + int1 = faceRunningState + bool1 = unlockPossible + }, + { + "Cancellation signal is not null, high chance of bug in " + + "face auth lifecycle management. " + + "Face state: $int1, unlockPossible: $bool1" + } + ) } fun logUnexpectedFpCancellationSignalState( fingerprintRunningState: Int, unlockPossible: Boolean ) { - logBuffer.log(TAG, ERROR, { - int1 = fingerprintRunningState - bool1 = unlockPossible - }, { - "Cancellation signal is not null, high chance of bug in " + - "fp auth lifecycle management. FP state: $int1, unlockPossible: $bool1" - }) + logBuffer.log( + TAG, + ERROR, + { + int1 = fingerprintRunningState + bool1 = unlockPossible + }, + { + "Cancellation signal is not null, high chance of bug in " + + "fp auth lifecycle management. FP state: $int1, unlockPossible: $bool1" + } + ) } fun logUnregisterCallback(callback: KeyguardUpdateMonitorCallback?) { - logBuffer.log(TAG, VERBOSE, - { str1 = "$callback" }, - { "*** unregister callback for $str1" }) + logBuffer.log(TAG, VERBOSE, { str1 = "$callback" }, { "*** unregister callback for $str1" }) } fun logUserRequestedUnlock( @@ -390,75 +488,173 @@ class KeyguardUpdateMonitorLogger @Inject constructor( reason: String?, dismissKeyguard: Boolean ) { - logBuffer.log("ActiveUnlock", DEBUG, { - str1 = requestOrigin?.name - str2 = reason - bool1 = dismissKeyguard - }, { "reportUserRequestedUnlock origin=$str1 reason=$str2 dismissKeyguard=$bool1" }) + logBuffer.log( + "ActiveUnlock", + DEBUG, + { + str1 = requestOrigin?.name + str2 = reason + bool1 = dismissKeyguard + }, + { "reportUserRequestedUnlock origin=$str1 reason=$str2 dismissKeyguard=$bool1" } + ) } fun logTrustGrantedWithFlags( - flags: Int, - newlyUnlocked: Boolean, - userId: Int, - message: String? + flags: Int, + newlyUnlocked: Boolean, + userId: Int, + message: String? ) { - logBuffer.log(TAG, DEBUG, { - int1 = flags - bool1 = newlyUnlocked - int2 = userId - str1 = message - }, { "trustGrantedWithFlags[user=$int2] newlyUnlocked=$bool1 " + - "flags=${TrustGrantFlags(int1)} message=$str1" }) - } - - fun logTrustChanged( - wasTrusted: Boolean, - isNowTrusted: Boolean, - userId: Int - ) { - logBuffer.log(TAG, DEBUG, { - bool1 = wasTrusted - bool2 = isNowTrusted - int1 = userId - }, { "onTrustChanged[user=$int1] wasTrusted=$bool1 isNowTrusted=$bool2" }) + logBuffer.log( + TAG, + DEBUG, + { + int1 = flags + bool1 = newlyUnlocked + int2 = userId + str1 = message + }, + { + "trustGrantedWithFlags[user=$int2] newlyUnlocked=$bool1 " + + "flags=${TrustGrantFlags(int1)} message=$str1" + } + ) + } + + fun logTrustChanged(wasTrusted: Boolean, isNowTrusted: Boolean, userId: Int) { + logBuffer.log( + TAG, + DEBUG, + { + bool1 = wasTrusted + bool2 = isNowTrusted + int1 = userId + }, + { "onTrustChanged[user=$int1] wasTrusted=$bool1 isNowTrusted=$bool2" } + ) } fun logKeyguardStateUpdate( - secure: Boolean, - canDismissLockScreen: Boolean, - trusted: Boolean, - trustManaged: Boolean - + secure: Boolean, + canDismissLockScreen: Boolean, + trusted: Boolean, + trustManaged: Boolean ) { - logBuffer.log("KeyguardState", DEBUG, { - bool1 = secure - bool2 = canDismissLockScreen - bool3 = trusted - bool4 = trustManaged - }, { "#update secure=$bool1 canDismissKeyguard=$bool2" + - " trusted=$bool3 trustManaged=$bool4" }) + logBuffer.log( + "KeyguardState", + DEBUG, + { + bool1 = secure + bool2 = canDismissLockScreen + bool3 = trusted + bool4 = trustManaged + }, + { + "#update secure=$bool1 canDismissKeyguard=$bool2" + + " trusted=$bool3 trustManaged=$bool4" + } + ) } fun logSkipUpdateFaceListeningOnWakeup(@WakeReason pmWakeReason: Int) { - logBuffer.log(TAG, VERBOSE, { - str1 = PowerManager.wakeReasonToString(pmWakeReason) - }, { "Skip updating face listening state on wakeup from $str1"}) + logBuffer.log( + TAG, + VERBOSE, + { str1 = PowerManager.wakeReasonToString(pmWakeReason) }, + { "Skip updating face listening state on wakeup from $str1" } + ) } fun logTaskStackChangedForAssistant(assistantVisible: Boolean) { - logBuffer.log(TAG, VERBOSE, { - bool1 = assistantVisible - }, { - "TaskStackChanged for ACTIVITY_TYPE_ASSISTANT, assistant visible: $bool1" - }) + logBuffer.log( + TAG, + VERBOSE, + { bool1 = assistantVisible }, + { "TaskStackChanged for ACTIVITY_TYPE_ASSISTANT, assistant visible: $bool1" } + ) } fun logAssistantVisible(assistantVisible: Boolean) { - logBuffer.log(TAG, VERBOSE, { - bool1 = assistantVisible - }, { - "Updating mAssistantVisible to new value: $bool1" - }) + logBuffer.log( + TAG, + VERBOSE, + { bool1 = assistantVisible }, + { "Updating mAssistantVisible to new value: $bool1" } + ) + } + + fun logReportSuccessfulBiometricUnlock(isStrongBiometric: Boolean, userId: Int) { + logBuffer.log( + TAG, + DEBUG, + { + bool1 = isStrongBiometric + int1 = userId + }, + { "reporting successful biometric unlock: isStrongBiometric: $bool1, userId: $int1" } + ) + } + + fun logHandlerHasAuthContinueMsgs(action: Int) { + logBuffer.log( + TAG, + DEBUG, + { int1 = action }, + { + "MSG_BIOMETRIC_AUTHENTICATION_CONTINUE already queued up, " + + "ignoring updating FP listening state to $int1" + } + ) + } + + fun logFaceEnrolledUpdated(oldValue: Boolean, newValue: Boolean) { + logBuffer.log( + TAG, + DEBUG, + { + bool1 = oldValue + bool2 = newValue + }, + { "Face enrolled state changed: old: $bool1, new: $bool2" } + ) + } + + fun logFpEnrolledUpdated(userId: Int, oldValue: Boolean, newValue: Boolean) { + logBuffer.log( + TAG, + DEBUG, + { + int1 = userId + bool1 = oldValue + bool2 = newValue + }, + { "Fp enrolled state changed for userId: $int1 old: $bool1, new: $bool2" } + ) + } + + fun logTrustUsuallyManagedUpdated( + userId: Int, + oldValue: Boolean, + newValue: Boolean, + context: String + ) { + logBuffer.log( + TAG, + DEBUG, + { + int1 = userId + bool1 = oldValue + bool2 = newValue + str1 = context + }, + { + "trustUsuallyManaged changed for " + + "userId: $int1 " + + "old: $bool1, " + + "new: $bool2 " + + "context: $context" + } + ) } } diff --git a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java index ce4253477a41..0002ae95f476 100644 --- a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java +++ b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java @@ -38,7 +38,6 @@ import android.util.AttributeSet; import android.util.TypedValue; import android.view.Gravity; import android.view.LayoutInflater; -import android.view.ViewGroup; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; @@ -347,10 +346,9 @@ public class BatteryMeterView extends LinearLayout implements DarkReceiver { } if (mTextColor != 0) mBatteryPercentView.setTextColor(mTextColor); updatePercentText(); - addView(mBatteryPercentView, - new ViewGroup.LayoutParams( - LayoutParams.WRAP_CONTENT, - LayoutParams.MATCH_PARENT)); + addView(mBatteryPercentView, new LayoutParams( + LayoutParams.WRAP_CONTENT, + LayoutParams.MATCH_PARENT)); } } else { if (showing) { diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt index 709ddf5ce748..52312b8e8add 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt @@ -97,7 +97,6 @@ open class AuthBiometricFingerprintIconController( val iconContentDescription = getIconContentDescription(newState) if (iconContentDescription != null) { iconView.contentDescription = iconContentDescription - iconViewOverlay.contentDescription = iconContentDescription } iconView.frame = 0 @@ -152,7 +151,7 @@ open class AuthBiometricFingerprintIconController( STATE_AUTHENTICATING_ANIMATING_IN, STATE_AUTHENTICATING, STATE_PENDING_CONFIRMATION, - STATE_AUTHENTICATED -> R.string.accessibility_fingerprint_dialog_fingerprint_icon + STATE_AUTHENTICATED -> R.string.security_settings_sfps_enroll_find_sensor_message STATE_ERROR, STATE_HELP -> R.string.biometric_dialog_try_again else -> null diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt index d68fcd0a5922..8f6b5c956853 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt @@ -26,6 +26,7 @@ import android.hardware.biometrics.BiometricSourceType import androidx.annotation.VisibleForTesting import com.android.keyguard.KeyguardUpdateMonitor import com.android.keyguard.KeyguardUpdateMonitorCallback +import com.android.keyguard.logging.KeyguardLogger import com.android.settingslib.Utils import com.android.systemui.R import com.android.systemui.animation.Interpolators @@ -74,6 +75,7 @@ class AuthRippleController @Inject constructor( private val udfpsControllerProvider: Provider<UdfpsController>, private val statusBarStateController: StatusBarStateController, private val featureFlags: FeatureFlags, + private val logger: KeyguardLogger, rippleView: AuthRippleView? ) : ViewController<AuthRippleView>(rippleView), KeyguardStateController.Callback, WakefulnessLifecycle.Observer { @@ -120,8 +122,11 @@ class AuthRippleController @Inject constructor( } fun showUnlockRipple(biometricSourceType: BiometricSourceType) { - if (!keyguardStateController.isShowing || - !keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(biometricSourceType)) { + val keyguardNotShowing = !keyguardStateController.isShowing + val unlockNotAllowed = !keyguardUpdateMonitor + .isUnlockingWithBiometricAllowed(biometricSourceType) + if (keyguardNotShowing || unlockNotAllowed) { + logger.notShowingUnlockRipple(keyguardNotShowing, unlockNotAllowed) return } @@ -138,6 +143,7 @@ class AuthRippleController @Inject constructor( Math.max(it.y, centralSurfaces.displayHeight.toInt() - it.y) ) ) + logger.showingUnlockRippleAt(it.x, it.y, "FP sensor radius: $udfpsRadius") showUnlockedRipple() } } else if (biometricSourceType == BiometricSourceType.FACE) { @@ -155,6 +161,7 @@ class AuthRippleController @Inject constructor( Math.max(it.y, centralSurfaces.displayHeight.toInt() - it.y) ) ) + logger.showingUnlockRippleAt(it.x, it.y, "Face unlock ripple") showUnlockedRipple() } } @@ -391,5 +398,6 @@ class AuthRippleController @Inject constructor( companion object { const val RIPPLE_ANIMATION_DURATION: Long = 1533 + const val TAG = "AuthRippleController" } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/FaceHelpMessageDeferral.kt b/packages/SystemUI/src/com/android/systemui/biometrics/FaceHelpMessageDeferral.kt index fabc1c1bb908..e16121d1104e 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/FaceHelpMessageDeferral.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/FaceHelpMessageDeferral.kt @@ -49,8 +49,8 @@ constructor( /** * @property messagesToDefer messages that shouldn't show immediately when received, but may be - * shown later if the message is the most frequent acquiredInfo processed and meets [threshold] - * percentage of all passed acquired frames. + * shown later if the message is the most frequent acquiredInfo processed and meets [threshold] + * percentage of all passed acquired frames. */ open class BiometricMessageDeferral( private val messagesToDefer: Set<Int>, @@ -127,8 +127,9 @@ open class BiometricMessageDeferral( /** * Get the most frequent deferred message that meets the [threshold] percentage of processed * frames. + * * @return null if no acquiredInfo have been deferred OR deferred messages didn't meet the - * [threshold] percentage. + * [threshold] percentage. */ fun getDeferredMessage(): CharSequence? { mostFrequentAcquiredInfoToDefer?.let { diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt index ac6a22c1474b..f7d87fc69e55 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt @@ -492,7 +492,9 @@ class OrientationReasonListener( displayManager, handler, BiometricDisplayListener.SensorType.SideFingerprint(sensorProps) - ) { onOrientationChanged(reason) } + ) { + onOrientationChanged(reason) + } } /** diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt index addbee954fea..71cb35f3041c 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt @@ -347,6 +347,7 @@ constructor( /** * Overrides non-bouncer show logic in shouldPauseAuth to still show icon. + * * @return whether the udfpsBouncer has been newly shown or hidden */ private fun showUdfpsBouncer(show: Boolean): Boolean { diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java index bc0f9950f865..f83885b7bb32 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java @@ -38,6 +38,7 @@ import javax.inject.Inject; public class FalsingDataProvider { private static final long MOTION_EVENT_AGE_MS = 1000; + private static final long DROP_EVENT_THRESHOLD_MS = 50; private static final float THREE_HUNDRED_SIXTY_DEG = (float) (2 * Math.PI); private final int mWidthPixels; @@ -60,6 +61,7 @@ public class FalsingDataProvider { private float mAngle = 0; private MotionEvent mFirstRecentMotionEvent; private MotionEvent mLastMotionEvent; + private boolean mDropLastEvent; private boolean mJustUnlockedWithFace; private boolean mA11YAction; @@ -95,6 +97,12 @@ public class FalsingDataProvider { // Ensure prior gesture was completed. May be a no-op. completePriorGesture(); } + + // Drop the gesture closing event if it is close in time to a previous ACTION_MOVE event. + // The reason is that the closing ACTION_UP event of a swipe can be a bit offseted from the + // previous ACTION_MOVE event and when it happens, it makes some classifiers fail. + mDropLastEvent = shouldDropEvent(motionEvent); + mRecentMotionEvents.addAll(motionEvents); FalsingClassifier.logVerbose("Size: " + mRecentMotionEvents.size()); @@ -129,6 +137,7 @@ public class FalsingDataProvider { mPriorMotionEvents = mRecentMotionEvents; mRecentMotionEvents = new TimeLimitedMotionEventBuffer(MOTION_EVENT_AGE_MS); } + mDropLastEvent = false; mA11YAction = false; } @@ -150,8 +159,18 @@ public class FalsingDataProvider { return mYdpi; } + /** + * Get the {@link MotionEvent}s of the most recent gesture. + * + * Note that this list may not include the last recorded event. + * @see #mDropLastEvent + */ public List<MotionEvent> getRecentMotionEvents() { - return mRecentMotionEvents; + if (!mDropLastEvent || mRecentMotionEvents.isEmpty()) { + return mRecentMotionEvents; + } else { + return mRecentMotionEvents.subList(0, mRecentMotionEvents.size() - 1); + } } public List<MotionEvent> getPriorMotionEvents() { @@ -169,7 +188,12 @@ public class FalsingDataProvider { return mFirstRecentMotionEvent; } - /** Get the last recorded {@link MotionEvent}. */ + /** + * Get the last {@link MotionEvent} of the most recent gesture. + * + * Note that this may be the event prior to the last recorded event. + * @see #mDropLastEvent + */ public MotionEvent getLastMotionEvent() { recalculateData(); return mLastMotionEvent; @@ -236,12 +260,13 @@ public class FalsingDataProvider { return; } - if (mRecentMotionEvents.isEmpty()) { + List<MotionEvent> recentMotionEvents = getRecentMotionEvents(); + if (recentMotionEvents.isEmpty()) { mFirstRecentMotionEvent = null; mLastMotionEvent = null; } else { - mFirstRecentMotionEvent = mRecentMotionEvents.get(0); - mLastMotionEvent = mRecentMotionEvents.get(mRecentMotionEvents.size() - 1); + mFirstRecentMotionEvent = recentMotionEvents.get(0); + mLastMotionEvent = recentMotionEvents.get(recentMotionEvents.size() - 1); } calculateAngleInternal(); @@ -249,6 +274,17 @@ public class FalsingDataProvider { mDirty = false; } + private boolean shouldDropEvent(MotionEvent event) { + if (mRecentMotionEvents.size() < 3) return false; + + MotionEvent lastEvent = mRecentMotionEvents.get(mRecentMotionEvents.size() - 1); + boolean isCompletingGesture = event.getActionMasked() == MotionEvent.ACTION_UP + && lastEvent.getActionMasked() == MotionEvent.ACTION_MOVE; + boolean isRecentEvent = + event.getEventTime() - lastEvent.getEventTime() < DROP_EVENT_THRESHOLD_MS; + return isCompletingGesture && isRecentEvent; + } + private void calculateAngleInternal() { if (mRecentMotionEvents.size() < 2) { mAngle = Float.MAX_VALUE; diff --git a/packages/SystemUI/src/com/android/systemui/classifier/TimeLimitedMotionEventBuffer.java b/packages/SystemUI/src/com/android/systemui/classifier/TimeLimitedMotionEventBuffer.java index e5da38936593..addd8e26490a 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/TimeLimitedMotionEventBuffer.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/TimeLimitedMotionEventBuffer.java @@ -183,7 +183,7 @@ public class TimeLimitedMotionEventBuffer implements List<MotionEvent> { @Override public List<MotionEvent> subList(int fromIndex, int toIndex) { - throw new UnsupportedOperationException(); + return mMotionEvents.subList(fromIndex, toIndex); } class Iter implements ListIterator<MotionEvent> { diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java index c214f5341450..e049ae09b1de 100644 --- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java +++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java @@ -263,10 +263,11 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv @Override // ClipboardListener.ClipboardOverlay public void setClipData(ClipData data, String source) { ClipboardModel model = ClipboardModel.fromClipData(mContext, mClipboardUtils, data, source); - if (mExitAnimator != null && mExitAnimator.isRunning()) { + boolean wasExiting = (mExitAnimator != null && mExitAnimator.isRunning()); + if (wasExiting) { mExitAnimator.cancel(); } - boolean shouldAnimate = !model.dataMatches(mClipboardModel); + boolean shouldAnimate = !model.dataMatches(mClipboardModel) || wasExiting; mClipboardModel = model; mClipboardLogger.setClipSource(mClipboardModel.getSource()); if (shouldAnimate) { @@ -313,15 +314,19 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv mOnPreviewTapped = this::editText; break; case IMAGE: - if (model.isSensitive() || model.loadThumbnail(mContext) != null) { - mView.showImagePreview( - model.isSensitive() ? null : model.loadThumbnail(mContext)); - mView.setEditAccessibilityAction(true); - mOnPreviewTapped = () -> editImage(model.getUri()); - } else { - // image loading failed - mView.showDefaultTextPreview(); - } + mBgExecutor.execute(() -> { + if (model.isSensitive() || model.loadThumbnail(mContext) != null) { + mView.post(() -> { + mView.showImagePreview( + model.isSensitive() ? null : model.loadThumbnail(mContext)); + mView.setEditAccessibilityAction(true); + }); + mOnPreviewTapped = () -> editImage(model.getUri()); + } else { + // image loading failed + mView.post(mView::showDefaultTextPreview); + } + }); break; case URI: case OTHER: @@ -346,9 +351,20 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv } private void animateFromMinimized() { - mIsMinimized = false; - setExpandedView(); - animateIn(); + if (mEnterAnimator != null && mEnterAnimator.isRunning()) { + mEnterAnimator.cancel(); + } + mEnterAnimator = mView.getMinimizedFadeoutAnimation(); + mEnterAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + mIsMinimized = false; + setExpandedView(); + animateIn(); + } + }); + mEnterAnimator.start(); } private String getAccessibilityAnnouncement(ClipboardModel.Type type) { @@ -363,15 +379,15 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv private void classifyText(ClipboardModel model) { mBgExecutor.execute(() -> { - Optional<RemoteAction> remoteAction = mClipboardUtils.getAction( - model.getText(), model.getTextLinks(), model.getSource()); + Optional<RemoteAction> remoteAction = + mClipboardUtils.getAction(model.getTextLinks(), model.getSource()); if (model.equals(mClipboardModel)) { remoteAction.ifPresent(action -> { mClipboardLogger.logUnguarded(CLIPBOARD_OVERLAY_ACTION_SHOWN); - mView.setActionChip(action, () -> { + mView.post(() -> mView.setActionChip(action, () -> { mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_ACTION_TAPPED); animateOut(); - }); + })); }); } }); diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtils.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtils.java index a85f8b9357f5..25caaeac2c38 100644 --- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtils.java +++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtils.java @@ -39,6 +39,9 @@ import javax.inject.Inject; class ClipboardOverlayUtils { + // minimum proportion of entire text an entity must take up, to be considered for smart actions + private static final float MINIMUM_ENTITY_PROPORTION = .8f; + private final TextClassifier mTextClassifier; @Inject @@ -65,19 +68,23 @@ class ClipboardOverlayUtils { return false; } - public Optional<RemoteAction> getAction(CharSequence text, TextLinks textLinks, String source) { - return getActions(text, textLinks).stream().filter(remoteAction -> { + public Optional<RemoteAction> getAction(TextLinks textLinks, String source) { + return getActions(textLinks).stream().filter(remoteAction -> { ComponentName component = remoteAction.getActionIntent().getIntent().getComponent(); return component != null && !TextUtils.equals(source, component.getPackageName()); }).findFirst(); } - private ArrayList<RemoteAction> getActions(CharSequence text, TextLinks textLinks) { + private ArrayList<RemoteAction> getActions(TextLinks textLinks) { ArrayList<RemoteAction> actions = new ArrayList<>(); for (TextLinks.TextLink link : textLinks.getLinks()) { - TextClassification classification = mTextClassifier.classifyText( - text, link.getStart(), link.getEnd(), null); - actions.addAll(classification.getActions()); + // skip classification for incidental entities + if (link.getEnd() - link.getStart() + >= textLinks.getText().length() * MINIMUM_ENTITY_PROPORTION) { + TextClassification classification = mTextClassifier.classifyText( + textLinks.getText(), link.getStart(), link.getEnd(), null); + actions.addAll(classification.getActions()); + } } return actions; } @@ -92,9 +99,13 @@ class ClipboardOverlayUtils { private ArrayList<RemoteAction> getActions(ClipData.Item item) { ArrayList<RemoteAction> actions = new ArrayList<>(); for (TextLinks.TextLink link : item.getTextLinks().getLinks()) { - TextClassification classification = mTextClassifier.classifyText( - item.getText(), link.getStart(), link.getEnd(), null); - actions.addAll(classification.getActions()); + // skip classification for incidental entities + if (link.getEnd() - link.getStart() + >= item.getText().length() * MINIMUM_ENTITY_PROPORTION) { + TextClassification classification = mTextClassifier.classifyText( + item.getText(), link.getStart(), link.getEnd(), null); + actions.addAll(classification.getActions()); + } } return actions; } diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java index f372bb4bc7f2..28c57d31a4f3 100644 --- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java +++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java @@ -21,6 +21,7 @@ import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; import android.animation.TimeInterpolator; import android.animation.ValueAnimator; import android.annotation.Nullable; @@ -286,6 +287,20 @@ public class ClipboardOverlayView extends DraggableConstraintLayout { mActionChips.clear(); } + Animator getMinimizedFadeoutAnimation() { + ObjectAnimator anim = ObjectAnimator.ofFloat(mMinimizedPreview, "alpha", 1, 0); + anim.setDuration(66); + anim.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + mMinimizedPreview.setVisibility(View.GONE); + mMinimizedPreview.setAlpha(1); + } + }); + return anim; + } + Animator getEnterAnimation() { if (mAccessibilityManager.isEnabled()) { mDismissButton.setVisibility(View.VISIBLE); diff --git a/packages/SystemUI/src/com/android/systemui/common/coroutine/ChannelExt.kt b/packages/SystemUI/src/com/android/systemui/common/coroutine/ChannelExt.kt index a0b19dc5c96e..c0e1717ea014 100644 --- a/packages/SystemUI/src/com/android/systemui/common/coroutine/ChannelExt.kt +++ b/packages/SystemUI/src/com/android/systemui/common/coroutine/ChannelExt.kt @@ -26,7 +26,6 @@ object ChannelExt { /** * Convenience wrapper around [SendChannel.trySend] that also logs on failure. This is the * equivalent of calling: - * * ``` * sendChannel.trySend(element).onFailure { * Log.e( diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/AuxiliaryPersistenceWrapper.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/AuxiliaryPersistenceWrapper.kt index b3c18fb3cd98..3744344421a9 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/controller/AuxiliaryPersistenceWrapper.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/controller/AuxiliaryPersistenceWrapper.kt @@ -86,6 +86,7 @@ internal constructor(wrapper: ControlsFavoritePersistenceWrapper) { * * When the favorites for that application are returned, they will be removed from the auxiliary * file immediately, so they won't be retrieved again. + * * @param componentName the name of the service that provided the controls * @return a list of structures with favorites */ diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt index 3555d0a7e7fb..2d37c292a6b8 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt @@ -173,12 +173,6 @@ interface ControlsController : UserAwareController { fun removeFavorites(componentName: ComponentName): Boolean /** - * Checks if the favorites can be removed. You can't remove components from the preferred list. - * @param componentName the name of the service that provides the [Control] - */ - fun canRemoveFavorites(componentName: ComponentName): Boolean - - /** * Replaces the favorites for the given structure. * * Calling this method will eliminate the previous selection of favorites and replace it with a diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt index 854790360f6a..e8c97bf77271 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt @@ -37,6 +37,7 @@ import com.android.systemui.controls.ControlStatus import com.android.systemui.controls.ControlsServiceInfo import com.android.systemui.controls.management.ControlsListingController import com.android.systemui.controls.panels.AuthorizedPanelsRepository +import com.android.systemui.controls.panels.SelectedComponentRepository import com.android.systemui.controls.ui.ControlsUiController import com.android.systemui.controls.ui.SelectedItem import com.android.systemui.dagger.SysUISingleton @@ -55,16 +56,17 @@ import javax.inject.Inject @SysUISingleton class ControlsControllerImpl @Inject constructor ( - private val context: Context, - @Background private val executor: DelayableExecutor, - private val uiController: ControlsUiController, - private val bindingController: ControlsBindingController, - private val listingController: ControlsListingController, - private val userFileManager: UserFileManager, - private val userTracker: UserTracker, - private val authorizedPanelsRepository: AuthorizedPanelsRepository, - optionalWrapper: Optional<ControlsFavoritePersistenceWrapper>, - dumpManager: DumpManager, + private val context: Context, + @Background private val executor: DelayableExecutor, + private val uiController: ControlsUiController, + private val selectedComponentRepository: SelectedComponentRepository, + private val bindingController: ControlsBindingController, + private val listingController: ControlsListingController, + private val userFileManager: UserFileManager, + private val userTracker: UserTracker, + private val authorizedPanelsRepository: AuthorizedPanelsRepository, + optionalWrapper: Optional<ControlsFavoritePersistenceWrapper>, + dumpManager: DumpManager, ) : Dumpable, ControlsController { companion object { @@ -497,17 +499,14 @@ class ControlsControllerImpl @Inject constructor ( } } - override fun canRemoveFavorites(componentName: ComponentName): Boolean = - !authorizedPanelsRepository.getPreferredPackages().contains(componentName.packageName) - override fun removeFavorites(componentName: ComponentName): Boolean { if (!confirmAvailability()) return false - if (!canRemoveFavorites(componentName)) return false executor.execute { - Favorites.removeStructures(componentName) + if (Favorites.removeStructures(componentName)) { + persistenceWrapper.storeFavorites(Favorites.getAllStructures()) + } authorizedPanelsRepository.removeAuthorizedPanels(setOf(componentName.packageName)) - persistenceWrapper.storeFavorites(Favorites.getAllStructures()) } return true } @@ -574,7 +573,9 @@ class ControlsControllerImpl @Inject constructor ( } override fun setPreferredSelection(selectedItem: SelectedItem) { - uiController.updatePreferences(selectedItem) + selectedComponentRepository.setSelectedComponent( + SelectedComponentRepository.SelectedComponent(selectedItem) + ) } override fun dump(pw: PrintWriter, args: Array<out String>) { diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt index 72c3a943c30b..217f4d89e24c 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt @@ -84,7 +84,7 @@ class ControlsProviderLifecycleManager( private val BIND_FLAGS_PANEL = Context.BIND_AUTO_CREATE or Context.BIND_NOT_PERCEPTIBLE } - private val intent = Intent().apply { + private val intent = Intent(ControlsProviderService.SERVICE_CONTROLS).apply { component = componentName putExtra(CALLBACK_BUNDLE, Bundle().apply { putBinder(CALLBACK_TOKEN, token) diff --git a/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt b/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt index d949d1119222..2af49aa5fa1a 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt @@ -36,6 +36,8 @@ import com.android.systemui.controls.management.ControlsProviderSelectorActivity import com.android.systemui.controls.management.ControlsRequestDialog import com.android.systemui.controls.panels.AuthorizedPanelsRepository import com.android.systemui.controls.panels.AuthorizedPanelsRepositoryImpl +import com.android.systemui.controls.panels.SelectedComponentRepository +import com.android.systemui.controls.panels.SelectedComponentRepositoryImpl import com.android.systemui.controls.settings.ControlsSettingsDialogManager import com.android.systemui.controls.settings.ControlsSettingsDialogManagerImpl import com.android.systemui.controls.ui.ControlActionCoordinator @@ -114,6 +116,11 @@ abstract class ControlsModule { repository: AuthorizedPanelsRepositoryImpl ): AuthorizedPanelsRepository + @Binds + abstract fun providePreferredPanelRepository( + repository: SelectedComponentRepositoryImpl + ): SelectedComponentRepository + @BindsOptionalOf abstract fun optionalPersistenceWrapper(): ControlsFavoritePersistenceWrapper diff --git a/packages/SystemUI/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImpl.kt index e51e8326c0a5..5c2402ba4149 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImpl.kt @@ -20,6 +20,8 @@ package com.android.systemui.controls.panels import android.content.Context import android.content.SharedPreferences import com.android.systemui.R +import com.android.systemui.flags.FeatureFlags +import com.android.systemui.flags.Flags import com.android.systemui.settings.UserFileManager import com.android.systemui.settings.UserTracker import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl @@ -30,7 +32,8 @@ class AuthorizedPanelsRepositoryImpl constructor( private val context: Context, private val userFileManager: UserFileManager, - private val userTracker: UserTracker + private val userTracker: UserTracker, + private val featureFlags: FeatureFlags, ) : AuthorizedPanelsRepository { override fun getAuthorizedPanels(): Set<String> { @@ -71,8 +74,18 @@ constructor( userTracker.userId, ) - // If we've never run this (i.e., the key doesn't exist), add the default packages - if (sharedPref.getStringSet(KEY, null) == null) { + // We should add default packages in two cases: + // 1) We've never run this + // 2) APP_PANELS_REMOVE_APPS_ALLOWED got disabled after user removed all apps + val needToSetup = + if (featureFlags.isEnabled(Flags.APP_PANELS_REMOVE_APPS_ALLOWED)) { + sharedPref.getStringSet(KEY, null) == null + } else { + // There might be an empty set that need to be overridden after the feature has been + // turned off after being turned on + sharedPref.getStringSet(KEY, null).isNullOrEmpty() + } + if (needToSetup) { sharedPref.edit().putStringSet(KEY, getPreferredPackages()).apply() } return sharedPref diff --git a/packages/SystemUI/src/com/android/systemui/controls/panels/SelectedComponentRepository.kt b/packages/SystemUI/src/com/android/systemui/controls/panels/SelectedComponentRepository.kt new file mode 100644 index 000000000000..5bb6eece9098 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/controls/panels/SelectedComponentRepository.kt @@ -0,0 +1,64 @@ +/* + * 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.systemui.controls.panels + +import android.content.ComponentName +import com.android.systemui.controls.ui.ControlsUiController +import com.android.systemui.controls.ui.SelectedItem +import com.android.systemui.flags.Flags + +/** Stores user-selected preferred component. */ +interface SelectedComponentRepository { + + /** + * Returns currently set preferred component, or null when nothing is set. Consider using + * [ControlsUiController.getPreferredSelectedItem] to get domain specific data + */ + fun getSelectedComponent(): SelectedComponent? + + /** Sets preferred component. Use [getSelectedComponent] to get current one */ + fun setSelectedComponent(selectedComponent: SelectedComponent) + + /** Clears current preferred component. [getSelectedComponent] will return null afterwards */ + fun removeSelectedComponent() + + /** + * Return true when default preferred component should be set up and false the otherwise. This + * is always true when [Flags.APP_PANELS_REMOVE_APPS_ALLOWED] is disabled + */ + fun shouldAddDefaultComponent(): Boolean + + /** + * Sets if default component should be added. This is ignored when + * [Flags.APP_PANELS_REMOVE_APPS_ALLOWED] is disabled + */ + fun setShouldAddDefaultComponent(shouldAdd: Boolean) + + data class SelectedComponent( + val name: String, + val componentName: ComponentName?, + val isPanel: Boolean, + ) { + constructor( + selectedItem: SelectedItem + ) : this( + name = selectedItem.name.toString(), + componentName = selectedItem.componentName, + isPanel = selectedItem is SelectedItem.PanelItem, + ) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/controls/panels/SelectedComponentRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/panels/SelectedComponentRepositoryImpl.kt new file mode 100644 index 000000000000..0fb5b66ef93c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/controls/panels/SelectedComponentRepositoryImpl.kt @@ -0,0 +1,95 @@ +/* + * 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.systemui.controls.panels + +import android.content.ComponentName +import android.content.Context +import android.content.SharedPreferences +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.flags.FeatureFlags +import com.android.systemui.flags.Flags +import com.android.systemui.settings.UserFileManager +import com.android.systemui.settings.UserTracker +import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl +import javax.inject.Inject + +@SysUISingleton +class SelectedComponentRepositoryImpl +@Inject +constructor( + private val userFileManager: UserFileManager, + private val userTracker: UserTracker, + private val featureFlags: FeatureFlags, +) : SelectedComponentRepository { + + private companion object { + const val PREF_COMPONENT = "controls_component" + const val PREF_STRUCTURE_OR_APP_NAME = "controls_structure" + const val PREF_IS_PANEL = "controls_is_panel" + const val SHOULD_ADD_DEFAULT_PANEL = "should_add_default_panel" + } + + private val sharedPreferences: SharedPreferences + get() = + userFileManager.getSharedPreferences( + fileName = DeviceControlsControllerImpl.PREFS_CONTROLS_FILE, + mode = Context.MODE_PRIVATE, + userId = userTracker.userId + ) + + override fun getSelectedComponent(): SelectedComponentRepository.SelectedComponent? { + with(sharedPreferences) { + val componentString = getString(PREF_COMPONENT, null) ?: return null + return SelectedComponentRepository.SelectedComponent( + name = getString(PREF_STRUCTURE_OR_APP_NAME, "")!!, + componentName = ComponentName.unflattenFromString(componentString), + isPanel = getBoolean(PREF_IS_PANEL, false) + ) + } + } + + override fun setSelectedComponent( + selectedComponent: SelectedComponentRepository.SelectedComponent + ) { + sharedPreferences + .edit() + .putString(PREF_COMPONENT, selectedComponent.componentName?.flattenToString()) + .putString(PREF_STRUCTURE_OR_APP_NAME, selectedComponent.name) + .putBoolean(PREF_IS_PANEL, selectedComponent.isPanel) + .apply() + } + + override fun removeSelectedComponent() { + sharedPreferences + .edit() + .remove(PREF_COMPONENT) + .remove(PREF_STRUCTURE_OR_APP_NAME) + .remove(PREF_IS_PANEL) + .apply() + } + + override fun shouldAddDefaultComponent(): Boolean = + if (featureFlags.isEnabled(Flags.APP_PANELS_REMOVE_APPS_ALLOWED)) { + sharedPreferences.getBoolean(SHOULD_ADD_DEFAULT_PANEL, true) + } else { + true + } + + override fun setShouldAddDefaultComponent(shouldAdd: Boolean) { + sharedPreferences.edit().putBoolean(SHOULD_ADD_DEFAULT_PANEL, shouldAdd).apply() + } +} diff --git a/packages/SystemUI/src/com/android/systemui/controls/settings/ControlsSettingsDialogManager.kt b/packages/SystemUI/src/com/android/systemui/controls/settings/ControlsSettingsDialogManager.kt index bb2e2d701aa0..06d4a0888197 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/settings/ControlsSettingsDialogManager.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/settings/ControlsSettingsDialogManager.kt @@ -38,7 +38,6 @@ import javax.inject.Inject /** * Manager to display a dialog to prompt user to enable controls related Settings: - * * * [Settings.Secure.LOCKSCREEN_SHOW_CONTROLS] * * [Settings.Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS] */ @@ -46,20 +45,19 @@ interface ControlsSettingsDialogManager { /** * Shows the corresponding dialog. In order for a dialog to appear, the following must be true - * * * At least one of the Settings in [ControlsSettingsRepository] are `false`. * * The dialog has not been seen by the user too many times (as defined by - * [MAX_NUMBER_ATTEMPTS_CONTROLS_DIALOG]). + * [MAX_NUMBER_ATTEMPTS_CONTROLS_DIALOG]). * * When the dialogs are shown, the following outcomes are possible: * * User cancels the dialog by clicking outside or going back: we register that the dialog was - * seen but the settings don't change. + * seen but the settings don't change. * * User responds negatively to the dialog: we register that the user doesn't want to change - * the settings (dialog will not appear again) and the settings don't change. + * the settings (dialog will not appear again) and the settings don't change. * * User responds positively to the dialog: the settings are set to `true` and the dialog will - * not appear again. + * not appear again. * * SystemUI closes the dialogs (for example, the activity showing it is closed). In this case, - * we don't modify anything. + * we don't modify anything. * * Of those four scenarios, only the first three will cause [onAttemptCompleted] to be called. * It will also be called if the dialogs are not shown. diff --git a/packages/SystemUI/src/com/android/systemui/controls/start/ControlsStartable.kt b/packages/SystemUI/src/com/android/systemui/controls/start/ControlsStartable.kt index 9d99253de741..3a4a00c0ccd3 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/start/ControlsStartable.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/start/ControlsStartable.kt @@ -18,17 +18,16 @@ package com.android.systemui.controls.start import android.content.Context -import android.content.res.Resources import android.os.UserHandle import com.android.systemui.CoreStartable -import com.android.systemui.R import com.android.systemui.controls.controller.ControlsController import com.android.systemui.controls.dagger.ControlsComponent import com.android.systemui.controls.management.ControlsListingController +import com.android.systemui.controls.panels.AuthorizedPanelsRepository +import com.android.systemui.controls.panels.SelectedComponentRepository import com.android.systemui.controls.ui.SelectedItem import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background -import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.settings.UserTracker import java.util.concurrent.Executor import javax.inject.Inject @@ -37,7 +36,7 @@ import javax.inject.Inject * Started with SystemUI to perform early operations for device controls subsystem (only if enabled) * * In particular, it will perform the following: - * * If there is no preferred selection for provider and at least one of the preferred packages + * * If there is no preferred selection for provider and at least one of the preferred packages * provides a panel, it will select the first one that does. * * If the preferred selection provides a panel, it will bind to that service (to reduce latency on * displaying the panel). @@ -48,10 +47,11 @@ import javax.inject.Inject class ControlsStartable @Inject constructor( - @Main private val resources: Resources, - @Background private val executor: Executor, - private val controlsComponent: ControlsComponent, - private val userTracker: UserTracker + @Background private val executor: Executor, + private val controlsComponent: ControlsComponent, + private val userTracker: UserTracker, + private val authorizedPanelsRepository: AuthorizedPanelsRepository, + private val selectedComponentRepository: SelectedComponentRepository, ) : CoreStartable { // These two controllers can only be accessed after `start` method once we've checked if the @@ -85,12 +85,15 @@ constructor( } private fun selectDefaultPanelIfNecessary() { + if (!selectedComponentRepository.shouldAddDefaultComponent()) { + return + } val currentSelection = controlsController.getPreferredSelection() if (currentSelection == SelectedItem.EMPTY_SELECTION) { val availableServices = controlsListingController.getCurrentServices() val panels = availableServices.filter { it.panelActivity != null } - resources - .getStringArray(R.array.config_controlsPreferredPackages) + authorizedPanelsRepository + .getPreferredPackages() // Looking for the first element in the string array such that there is one package // that has a panel. It will return null if there are no packages in the array, // or if no packages in the array have a panel associated with it. diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt index 58673bb6f567..0d5311752ab9 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt @@ -64,8 +64,6 @@ interface ControlsUiController { * This element will be the one that appears when the user first opens the controls activity. */ fun getPreferredSelectedItem(structures: List<StructureInfo>): SelectedItem - - fun updatePreferences(selectedItem: SelectedItem) } sealed class SelectedItem { diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt index c61dad6fc075..5da86de933e6 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt @@ -64,6 +64,7 @@ import com.android.systemui.controls.management.ControlsFavoritingActivity import com.android.systemui.controls.management.ControlsListingController import com.android.systemui.controls.management.ControlsProviderSelectorActivity import com.android.systemui.controls.panels.AuthorizedPanelsRepository +import com.android.systemui.controls.panels.SelectedComponentRepository import com.android.systemui.controls.settings.ControlsSettingsRepository import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background @@ -73,9 +74,7 @@ import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags import com.android.systemui.globalactions.GlobalActionsPopupMenu import com.android.systemui.plugins.ActivityStarter -import com.android.systemui.settings.UserFileManager import com.android.systemui.settings.UserTracker -import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.asIndenting import com.android.systemui.util.concurrency.DelayableExecutor @@ -84,7 +83,7 @@ import com.android.wm.shell.TaskViewFactory import dagger.Lazy import java.io.PrintWriter import java.text.Collator -import java.util.* +import java.util.Optional import java.util.function.Consumer import javax.inject.Inject @@ -98,25 +97,22 @@ class ControlsUiControllerImpl @Inject constructor ( @Main val uiExecutor: DelayableExecutor, @Background val bgExecutor: DelayableExecutor, val controlsListingController: Lazy<ControlsListingController>, - val controlActionCoordinator: ControlActionCoordinator, + private val controlActionCoordinator: ControlActionCoordinator, private val activityStarter: ActivityStarter, private val iconCache: CustomIconCache, private val controlsMetricsLogger: ControlsMetricsLogger, private val keyguardStateController: KeyguardStateController, - private val userFileManager: UserFileManager, private val userTracker: UserTracker, private val taskViewFactory: Optional<TaskViewFactory>, private val controlsSettingsRepository: ControlsSettingsRepository, private val authorizedPanelsRepository: AuthorizedPanelsRepository, + private val selectedComponentRepository: SelectedComponentRepository, private val featureFlags: FeatureFlags, private val dialogsFactory: ControlsDialogsFactory, dumpManager: DumpManager ) : ControlsUiController, Dumpable { companion object { - private const val PREF_COMPONENT = "controls_component" - private const val PREF_STRUCTURE_OR_APP_NAME = "controls_structure" - private const val PREF_IS_PANEL = "controls_is_panel" private const val FADE_IN_MILLIS = 200L @@ -138,12 +134,6 @@ class ControlsUiControllerImpl @Inject constructor ( private val popupThemedContext = ContextThemeWrapper(context, R.style.Control_ListPopupWindow) private var retainCache = false private var lastSelections = emptyList<SelectionItem>() - private val sharedPreferences - get() = userFileManager.getSharedPreferences( - fileName = DeviceControlsControllerImpl.PREFS_CONTROLS_FILE, - mode = 0, - userId = userTracker.userId - ) private var taskViewController: PanelTaskViewController? = null @@ -341,20 +331,18 @@ class ControlsUiControllerImpl @Inject constructor ( if (!controlsController.get().removeFavorites(componentName)) { return@createRemoveAppDialog } - if ( - sharedPreferences.getString(PREF_COMPONENT, "") == - componentName.flattenToString() - ) { - sharedPreferences - .edit() - .remove(PREF_COMPONENT) - .remove(PREF_STRUCTURE_OR_APP_NAME) - .remove(PREF_IS_PANEL) - .commit() + + if (selectedComponentRepository.getSelectedComponent()?.componentName == + componentName) { + selectedComponentRepository.removeSelectedComponent() } - allStructures = controlsController.get().getFavorites() - selectedItem = getPreferredSelectedItem(allStructures) + val selectedItem = getPreferredSelectedItem(controlsController.get().getFavorites()) + if (selectedItem == SelectedItem.EMPTY_SELECTION) { + // User removed the last panel. In this case we start app selection flow and don't + // want to auto-add it again + selectedComponentRepository.setShouldAddDefaultComponent(false) + } reload(parent) }.apply { show() } } @@ -522,8 +510,7 @@ class ControlsUiControllerImpl @Inject constructor ( ADD_APP_ID )) } - if (featureFlags.isEnabled(Flags.APP_PANELS_REMOVE_APPS_ALLOWED) && - controlsController.get().canRemoveFavorites(selectedItem.componentName)) { + if (featureFlags.isEnabled(Flags.APP_PANELS_REMOVE_APPS_ALLOWED)) { add(OverflowMenuAdapter.MenuItem( context.getText(R.string.controls_menu_remove), REMOVE_APP_ID, @@ -569,7 +556,7 @@ class ControlsUiControllerImpl @Inject constructor ( ADD_CONTROLS_ID -> startFavoritingActivity(selectedStructure) EDIT_CONTROLS_ID -> startEditingActivity(selectedStructure) REMOVE_APP_ID -> startRemovingApp( - selectedStructure.componentName, selectionItem.appName + selectionItem.componentName, selectionItem.appName ) } dismiss() @@ -714,29 +701,22 @@ class ControlsUiControllerImpl @Inject constructor ( } override fun getPreferredSelectedItem(structures: List<StructureInfo>): SelectedItem { - val sp = sharedPreferences - - val component = sp.getString(PREF_COMPONENT, null)?.let { - ComponentName.unflattenFromString(it) - } ?: EMPTY_COMPONENT - val name = sp.getString(PREF_STRUCTURE_OR_APP_NAME, "")!! - val isPanel = sp.getBoolean(PREF_IS_PANEL, false) - return if (isPanel) { - SelectedItem.PanelItem(name, component) + val preferredPanel = selectedComponentRepository.getSelectedComponent() + val component = preferredPanel?.componentName ?: EMPTY_COMPONENT + return if (preferredPanel?.isPanel == true) { + SelectedItem.PanelItem(preferredPanel.name, component) } else { if (structures.isEmpty()) return SelectedItem.EMPTY_SELECTION SelectedItem.StructureItem(structures.firstOrNull { - component == it.componentName && name == it.structure - } ?: structures.get(0)) + component == it.componentName && preferredPanel?.name == it.structure + } ?: structures[0]) } } - override fun updatePreferences(selectedItem: SelectedItem) { - sharedPreferences.edit() - .putString(PREF_COMPONENT, selectedItem.componentName.flattenToString()) - .putString(PREF_STRUCTURE_OR_APP_NAME, selectedItem.name.toString()) - .putBoolean(PREF_IS_PANEL, selectedItem is SelectedItem.PanelItem) - .apply() + private fun updatePreferences(selectedItem: SelectedItem) { + selectedComponentRepository.setSelectedComponent( + SelectedComponentRepository.SelectedComponent(selectedItem) + ) } private fun maybeUpdateSelectedItem(item: SelectionItem): Boolean { diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java index fb016911f913..cb2d6732b130 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java @@ -29,6 +29,7 @@ import com.android.systemui.sensorprivacy.television.TvUnblockSensorActivity; import com.android.systemui.settings.brightness.BrightnessDialog; import com.android.systemui.statusbar.tv.notifications.TvNotificationPanelActivity; import com.android.systemui.tuner.TunerActivity; +import com.android.systemui.usb.UsbAccessoryUriActivity; import com.android.systemui.usb.UsbConfirmActivity; import com.android.systemui.usb.UsbDebuggingActivity; import com.android.systemui.usb.UsbDebuggingSecondaryUserActivity; @@ -94,6 +95,12 @@ public abstract class DefaultActivityBinder { @ClassKey(UsbConfirmActivity.class) public abstract Activity bindUsbConfirmActivity(UsbConfirmActivity activity); + /** Inject into UsbAccessoryUriActivity. */ + @Binds + @IntoMap + @ClassKey(UsbAccessoryUriActivity.class) + public abstract Activity bindUsbAccessoryUriActivity(UsbAccessoryUriActivity activity); + /** Inject into CreateUserActivity. */ @Binds @IntoMap diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java index f0ee44305b10..cedc226ae0a9 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java @@ -75,6 +75,7 @@ import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.connectivity.ConnectivityModule; +import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler; import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder; import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl; @@ -256,9 +257,7 @@ public abstract class SystemUIModule { abstract FingerprintInteractiveToAuthProvider optionalFingerprintInteractiveToAuthProvider(); @BindsOptionalOf - //TODO(b/269430792 remove full qualifier. Full qualifier is used to avoid merge conflict.) - abstract com.android.systemui.statusbar.events.SystemStatusAnimationScheduler - optionalSystemStatusAnimationScheduler(); + abstract SystemStatusAnimationScheduler optionalSystemStatusAnimationScheduler(); @SysUISingleton @Binds diff --git a/packages/SystemUI/src/com/android/systemui/demomode/DemoModeController.kt b/packages/SystemUI/src/com/android/systemui/demomode/DemoModeController.kt index 84f83f1ae956..45ff963c2a9f 100644 --- a/packages/SystemUI/src/com/android/systemui/demomode/DemoModeController.kt +++ b/packages/SystemUI/src/com/android/systemui/demomode/DemoModeController.kt @@ -128,7 +128,6 @@ constructor( * * This is equivalent of creating a listener manually and adding an event handler for the given * command, like so: - * * ``` * class Demoable { * private val demoHandler = object : DemoMode { diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt index c3bd5d96590e..d0a92f0846d0 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt +++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt @@ -43,7 +43,6 @@ import com.android.systemui.util.concurrency.DelayableExecutor import javax.inject.Inject import javax.inject.Named import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.launch @@ -131,9 +130,17 @@ constructor( } } - /** Starts the dream content and dream overlay entry animations. */ + /** + * Starts the dream content and dream overlay entry animations. + * + * @param downwards if true, the entry animation translations downwards into position rather + * than upwards. + */ @JvmOverloads - fun startEntryAnimations(animatorBuilder: () -> AnimatorSet = { AnimatorSet() }) { + fun startEntryAnimations( + downwards: Boolean, + animatorBuilder: () -> AnimatorSet = { AnimatorSet() } + ) { cancelAnimations() mAnimator = @@ -153,7 +160,7 @@ constructor( interpolator = Interpolators.LINEAR ), translationYAnimator( - from = mDreamInTranslationYDistance.toFloat(), + from = mDreamInTranslationYDistance.toFloat() * (if (downwards) -1 else 1), to = 0f, durationMs = mDreamInTranslationYDurationMs, interpolator = Interpolators.EMPHASIZED_DECELERATE @@ -167,6 +174,71 @@ constructor( } } + /** + * Starts the dream content and dream overlay exit animations. + * + * This should only be used when the low light dream is entering, animations to/from other SysUI + * views is controlled by `transitionViewModel`. + */ + // TODO(b/256916668): integrate with the keyguard transition model once dream surfaces work is + // done. + @JvmOverloads + fun startExitAnimations(animatorBuilder: () -> AnimatorSet = { AnimatorSet() }): Animator { + cancelAnimations() + + mAnimator = + animatorBuilder().apply { + playTogether( + translationYAnimator( + from = 0f, + to = -mDreamInTranslationYDistance.toFloat(), + durationMs = mDreamInTranslationYDurationMs, + delayMs = 0, + interpolator = Interpolators.EMPHASIZED + ), + alphaAnimator( + from = + mCurrentAlphaAtPosition.getOrDefault( + key = POSITION_BOTTOM, + defaultValue = 1f + ), + to = 0f, + durationMs = mDreamInComplicationsAnimDurationMs, + delayMs = 0, + positions = POSITION_BOTTOM + ) + .apply { + doOnEnd { + // The logical end of the animation is once the alpha and blur + // animations finish, end the animation so that any listeners are + // notified. The Y translation animation is much longer than all of + // the other animations due to how the spec is defined, but is not + // expected to run to completion. + mAnimator?.end() + } + }, + alphaAnimator( + from = + mCurrentAlphaAtPosition.getOrDefault( + key = POSITION_TOP, + defaultValue = 1f + ), + to = 0f, + durationMs = mDreamInComplicationsAnimDurationMs, + delayMs = 0, + positions = POSITION_TOP + ) + ) + doOnEnd { + mAnimator = null + mOverlayStateController.setExitAnimationsRunning(false) + } + start() + } + mOverlayStateController.setExitAnimationsRunning(true) + return mAnimator as AnimatorSet + } + /** Starts the dream content and dream overlay exit animations. */ fun wakeUp(doneCallback: Runnable, executor: DelayableExecutor) { cancelAnimations() @@ -182,18 +254,6 @@ constructor( } } - /** - * Ends the dream content and dream overlay animations, if they're currently running. - * @see [AnimatorSet.end] - */ - fun endAnimations() { - mAnimator = - mAnimator?.let { - it.end() - null - } - } - private fun blurAnimator( view: View, fromBlurRadius: Float, diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java index 50cfb6a905c9..4b478cdca9f9 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java @@ -23,6 +23,7 @@ import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset; import static com.android.systemui.dreams.complication.ComplicationLayoutParams.POSITION_BOTTOM; import static com.android.systemui.dreams.complication.ComplicationLayoutParams.POSITION_TOP; +import android.animation.Animator; import android.content.res.Resources; import android.os.Handler; import android.util.MathUtils; @@ -31,6 +32,7 @@ import android.view.ViewGroup; import androidx.annotation.NonNull; +import com.android.dream.lowlight.LowLightTransitionCoordinator; import com.android.systemui.R; import com.android.systemui.animation.Interpolators; import com.android.systemui.dagger.qualifiers.Main; @@ -54,11 +56,14 @@ import javax.inject.Named; * View controller for {@link DreamOverlayContainerView}. */ @DreamOverlayComponent.DreamOverlayScope -public class DreamOverlayContainerViewController extends ViewController<DreamOverlayContainerView> { +public class DreamOverlayContainerViewController extends + ViewController<DreamOverlayContainerView> implements + LowLightTransitionCoordinator.LowLightEnterListener { private final DreamOverlayStatusBarViewController mStatusBarViewController; private final BlurUtils mBlurUtils; private final DreamOverlayAnimationsController mDreamOverlayAnimationsController; private final DreamOverlayStateController mStateController; + private final LowLightTransitionCoordinator mLowLightTransitionCoordinator; private final ComplicationHostViewController mComplicationHostViewController; @@ -143,19 +148,18 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve }; /** - * If true, overlay entry animations should be skipped once. - * - * This is turned on when exiting low light and should be turned off once the entry animations - * are skipped once. + * If {@code true}, the dream has just transitioned from the low light dream back to the user + * dream and we should play an entry animation where the overlay slides in downwards from the + * top instead of the typicla slide in upwards from the bottom. */ - private boolean mSkipEntryAnimations; + private boolean mExitingLowLight; private final DreamOverlayStateController.Callback mDreamOverlayStateCallback = new DreamOverlayStateController.Callback() { @Override public void onExitLowLight() { - mSkipEntryAnimations = true; + mExitingLowLight = true; } }; @@ -165,6 +169,7 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve ComplicationHostViewController complicationHostViewController, @Named(DreamOverlayModule.DREAM_OVERLAY_CONTENT_VIEW) ViewGroup contentView, DreamOverlayStatusBarViewController statusBarViewController, + LowLightTransitionCoordinator lowLightTransitionCoordinator, BlurUtils blurUtils, @Main Handler handler, @Main Resources resources, @@ -182,6 +187,7 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve mBlurUtils = blurUtils; mDreamOverlayAnimationsController = animationsController; mStateController = stateController; + mLowLightTransitionCoordinator = lowLightTransitionCoordinator; mBouncerlessScrimController = bouncerlessScrimController; mBouncerlessScrimController.addCallback(mBouncerlessExpansionCallback); @@ -208,6 +214,7 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve mStatusBarViewController.init(); mComplicationHostViewController.init(); mDreamOverlayAnimationsController.init(mView); + mLowLightTransitionCoordinator.setLowLightEnterListener(this); } @Override @@ -219,14 +226,10 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve // Start dream entry animations. Skip animations for low light clock. if (!mStateController.isLowLightActive()) { - mDreamOverlayAnimationsController.startEntryAnimations(); - - if (mSkipEntryAnimations) { - // If we're transitioning from the low light dream back to the user dream, skip the - // overlay animations and show immediately. - mDreamOverlayAnimationsController.endAnimations(); - mSkipEntryAnimations = false; - } + // If this is transitioning from the low light dream to the user dream, the overlay + // should translate in downwards instead of upwards. + mDreamOverlayAnimationsController.startEntryAnimations(mExitingLowLight); + mExitingLowLight = false; } } @@ -310,4 +313,12 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve mDreamOverlayAnimationsController.wakeUp(onAnimationEnd, callbackExecutor); } + + @Override + public Animator onBeforeEnterLowLight() { + // Return the animator so that the transition coordinator waits for the overlay exit + // animations to finish before entering low light, as otherwise the default DreamActivity + // animation plays immediately and there's no time for this animation to play. + return mDreamOverlayAnimationsController.startExitAnimations(); + } } diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationHostViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationHostViewController.java index a2e11b21ea59..24e90f066622 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationHostViewController.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationHostViewController.java @@ -22,14 +22,18 @@ import static com.android.systemui.dreams.complication.dagger.ComplicationModule import android.graphics.Rect; import android.graphics.Region; import android.os.Debug; +import android.os.UserHandle; +import android.provider.Settings; import android.util.Log; import android.view.View; import androidx.constraintlayout.widget.ConstraintLayout; import androidx.lifecycle.LifecycleOwner; +import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.dreams.DreamOverlayStateController; import com.android.systemui.util.ViewController; +import com.android.systemui.util.settings.SecureSettings; import java.util.Collection; import java.util.HashMap; @@ -54,6 +58,8 @@ public class ComplicationHostViewController extends ViewController<ConstraintLay private final LifecycleOwner mLifecycleOwner; private final ComplicationCollectionViewModel mComplicationCollectionViewModel; private final HashMap<ComplicationId, Complication.ViewHolder> mComplications = new HashMap<>(); + @VisibleForTesting + boolean mIsAnimationEnabled; // Whether dream entry animations are finished. private boolean mEntryAnimationsFinished = false; @@ -64,7 +70,8 @@ public class ComplicationHostViewController extends ViewController<ConstraintLay ComplicationLayoutEngine layoutEngine, DreamOverlayStateController dreamOverlayStateController, LifecycleOwner lifecycleOwner, - @Named(SCOPED_COMPLICATIONS_MODEL) ComplicationCollectionViewModel viewModel) { + @Named(SCOPED_COMPLICATIONS_MODEL) ComplicationCollectionViewModel viewModel, + SecureSettings secureSettings) { super(view); mLayoutEngine = layoutEngine; mLifecycleOwner = lifecycleOwner; @@ -78,6 +85,10 @@ public class ComplicationHostViewController extends ViewController<ConstraintLay mDreamOverlayStateController.areEntryAnimationsFinished(); } }); + + // Whether animations are enabled. + mIsAnimationEnabled = secureSettings.getFloatForUser( + Settings.Global.ANIMATOR_DURATION_SCALE, 1.0f, UserHandle.USER_CURRENT) != 0.0f; } @Override @@ -148,7 +159,7 @@ public class ComplicationHostViewController extends ViewController<ConstraintLay // Complications to be added before dream entry animations are finished are set // to invisible and are animated in. - if (!mEntryAnimationsFinished) { + if (!mEntryAnimationsFinished && mIsAnimationEnabled) { view.setVisibility(View.INVISIBLE); } mComplications.put(id, viewHolder); diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java index 73c2289ad6bd..a7b3bbcbc37b 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java @@ -254,7 +254,10 @@ public class BouncerSwipeTouchHandler implements DreamTouchHandler { mCurrentScrimController = mScrimManager.getCurrentController(); session.registerCallback(() -> { - mVelocityTracker.recycle(); + if (mVelocityTracker != null) { + mVelocityTracker.recycle(); + mVelocityTracker = null; + } mScrimManager.removeCallback(mScrimManagerCallback); mCapture = null; mNotificationShadeWindowController.setForcePluginOpen(false, this); diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt index 4fb763ff6038..7e41d5ee644d 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt @@ -74,8 +74,12 @@ object Flags { val NOTIFICATION_MEMORY_MONITOR_ENABLED = releasedFlag(112, "notification_memory_monitor_enabled") + /** + * This flag is server-controlled and should stay as [unreleasedFlag] since we never want to + * enable it on release builds. + */ val NOTIFICATION_MEMORY_LOGGING_ENABLED = - unreleasedFlag(119, "notification_memory_logging_enabled", teamfood = true) + unreleasedFlag(119, "notification_memory_logging_enabled") // TODO(b/254512731): Tracking Bug @JvmField val NOTIFICATION_DISMISSAL_FADE = releasedFlag(113, "notification_dismissal_fade") @@ -109,6 +113,10 @@ object Flags { @JvmField val NOTIFICATION_ANIMATE_BIG_PICTURE = unreleasedFlag(120, "notification_animate_big_picture") + @JvmField + val ANIMATED_NOTIFICATION_SHADE_INSETS = + unreleasedFlag(270682168, "animated_notification_shade_insets", teamfood = true) + // 200 - keyguard/lockscreen // ** Flag retired ** // public static final BooleanFlag KEYGUARD_LAYOUT = @@ -157,12 +165,6 @@ object Flags { val CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES = unreleasedFlag(216, "customizable_lock_screen_quick_affordances", teamfood = true) - /** Shows chipbar UI whenever the device is unlocked by ActiveUnlock (watch). */ - // TODO(b/256513609): Tracking Bug - @JvmField - val ACTIVE_UNLOCK_CHIPBAR = - resourceBooleanFlag(217, R.bool.flag_active_unlock_chipbar, "active_unlock_chipbar") - /** * Migrates control of the LightRevealScrim's reveal effect and amount from legacy code to the * new KeyguardTransitionRepository. @@ -272,8 +274,7 @@ object Flags { /** Enables new QS Edit Mode visual refresh */ // TODO(b/269787742): Tracking Bug @JvmField - val ENABLE_NEW_QS_EDIT_MODE = - unreleasedFlag(510, "enable_new_qs_edit_mode", teamfood = false) + val ENABLE_NEW_QS_EDIT_MODE = unreleasedFlag(510, "enable_new_qs_edit_mode", teamfood = false) // 600- status bar @@ -359,7 +360,7 @@ object Flags { val MEDIA_TTT_RECEIVER_SUCCESS_RIPPLE = releasedFlag(910, "media_ttt_receiver_success_ripple") // TODO(b/263512203): Tracking Bug - val MEDIA_EXPLICIT_INDICATOR = unreleasedFlag(911, "media_explicit_indicator", teamfood = true) + val MEDIA_EXPLICIT_INDICATOR = unreleasedFlag(911, "media_explicit_indicator") // TODO(b/265813373): Tracking Bug val MEDIA_TAP_TO_TRANSFER_DISMISS_GESTURE = releasedFlag(912, "media_ttt_dismiss_gesture") @@ -386,9 +387,18 @@ object Flags { // TODO(b/254512758): Tracking Bug @JvmField val ROUNDED_BOX_RIPPLE = releasedFlag(1002, "rounded_box_ripple") + // TODO(b/270882464): Tracking Bug + val ENABLE_DOCK_SETUP_V2 = unreleasedFlag(1005, "enable_dock_setup_v2") + // TODO(b/265045965): Tracking Bug val SHOW_LOWLIGHT_ON_DIRECT_BOOT = releasedFlag(1003, "show_lowlight_on_direct_boot") + @JvmField + // TODO(b/271428141): Tracking Bug + val ENABLE_LOW_LIGHT_CLOCK_UNDOCKED = unreleasedFlag( + 1004, + "enable_low_light_clock_undocked", teamfood = true) + // 1100 - windowing @Keep @JvmField @@ -442,7 +452,9 @@ object Flags { ) // TODO(b/256873975): Tracking Bug - @JvmField @Keep val WM_BUBBLE_BAR = unreleasedFlag(1111, "wm_bubble_bar") + @JvmField + @Keep + val WM_BUBBLE_BAR = sysPropBooleanFlag(1111, "persist.wm.debug.bubble_bar", default = false) // TODO(b/260271148): Tracking bug @Keep @@ -465,13 +477,13 @@ object Flags { @Keep @JvmField val ENABLE_PIP_SIZE_LARGE_SCREEN = - sysPropBooleanFlag(1114, "persist.wm.debug.enable_pip_size_large_screen", default = false) + sysPropBooleanFlag(1114, "persist.wm.debug.enable_pip_size_large_screen", default = true) // TODO(b/265998256): Tracking bug @Keep @JvmField val ENABLE_PIP_APP_ICON_OVERLAY = - sysPropBooleanFlag(1115, "persist.wm.debug.enable_pip_app_icon_overlay", default = false) + sysPropBooleanFlag(1115, "persist.wm.debug.enable_pip_app_icon_overlay", default = true) // 1200 - predictive back @Keep @@ -548,7 +560,7 @@ object Flags { // 1500 - chooser aka sharesheet // TODO(b/254512507): Tracking Bug - val CHOOSER_UNBUNDLED = releasedFlag(1500, "chooser_unbundled") + val CHOOSER_UNBUNDLED = unreleasedFlag(1500, "chooser_unbundled") // TODO(b/266983432) Tracking Bug val SHARESHEET_CUSTOM_ACTIONS = @@ -636,11 +648,6 @@ object Flags { @JvmField val OUTPUT_SWITCHER_DEVICE_STATUS = unreleasedFlag(2502, "output_switcher_device_status") - // TODO(b/20911786): Tracking Bug - @JvmField - val OUTPUT_SWITCHER_SHOW_API_ENABLED = - releasedFlag(2503, "output_switcher_show_api_enabled", teamfood = true) - // 2700 - unfold transitions // TODO(b/265764985): Tracking Bug @Keep diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java index e80e71c7b599..03b45b512010 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java @@ -2054,6 +2054,10 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene || Intent.ACTION_SCREEN_OFF.equals(action)) { String reason = intent.getStringExtra(SYSTEM_DIALOG_REASON_KEY); if (!SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS.equals(reason)) { + // These broadcasts are usually received when locking the device, swiping up to + // home (which collapses the shade), etc. In those cases, we usually don't want + // to animate this dialog back into the view, so we disable the exit animations. + mDialogLaunchAnimator.disableAllCurrentDialogsExitAnimations(); mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_DISMISS, reason)); } } else if (TelephonyManager.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED.equals(action)) { diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/PhysicalKeyboardCoreStartable.kt b/packages/SystemUI/src/com/android/systemui/keyboard/PhysicalKeyboardCoreStartable.kt index b0f9c4edb073..d078688e5944 100644 --- a/packages/SystemUI/src/com/android/systemui/keyboard/PhysicalKeyboardCoreStartable.kt +++ b/packages/SystemUI/src/com/android/systemui/keyboard/PhysicalKeyboardCoreStartable.kt @@ -21,6 +21,7 @@ import com.android.systemui.CoreStartable import com.android.systemui.dagger.SysUISingleton import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags +import com.android.systemui.keyboard.backlight.ui.KeyboardBacklightDialogCoordinator import javax.inject.Inject /** A [CoreStartable] that launches components interested in physical keyboard interaction. */ @@ -28,11 +29,12 @@ import javax.inject.Inject class PhysicalKeyboardCoreStartable @Inject constructor( + private val keyboardBacklightDialogCoordinator: KeyboardBacklightDialogCoordinator, private val featureFlags: FeatureFlags, ) : CoreStartable { override fun start() { if (featureFlags.isEnabled(Flags.KEYBOARD_BACKLIGHT_INDICATOR)) { - // TODO(b/268645743) start listening for keyboard backlight brightness + keyboardBacklightDialogCoordinator.startListening() } } } diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/backlight/domain/interactor/KeyboardBacklightInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/domain/interactor/KeyboardBacklightInteractor.kt new file mode 100644 index 000000000000..65e70b319923 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/domain/interactor/KeyboardBacklightInteractor.kt @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.android.systemui.keyboard.backlight.domain.interactor + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.keyboard.data.repository.KeyboardRepository +import com.android.systemui.keyboard.shared.model.BacklightModel +import javax.inject.Inject +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flowOf + +/** Allows listening to changes to keyboard backlight level */ +@SysUISingleton +class KeyboardBacklightInteractor +@Inject +constructor( + private val keyboardRepository: KeyboardRepository, +) { + + /** Emits current backlight level as [BacklightModel] or null if keyboard is not connected */ + val backlight: Flow<BacklightModel?> = + keyboardRepository.keyboardConnected.flatMapLatest { connected -> + if (connected) keyboardRepository.backlight else flowOf(null) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/KeyboardBacklightDialogCoordinator.kt b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/KeyboardBacklightDialogCoordinator.kt new file mode 100644 index 000000000000..85d0379a77db --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/KeyboardBacklightDialogCoordinator.kt @@ -0,0 +1,59 @@ +/* + * 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.systemui.keyboard.backlight.ui + +import android.content.Context +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.keyboard.backlight.ui.view.KeyboardBacklightDialog +import com.android.systemui.keyboard.backlight.ui.viewmodel.BacklightDialogViewModel +import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch + +/** + * Based on the state produced from [BacklightDialogViewModel] shows or hides keyboard backlight + * indicator + */ +@SysUISingleton +class KeyboardBacklightDialogCoordinator +@Inject +constructor( + @Application private val applicationScope: CoroutineScope, + private val context: Context, + private val viewModel: BacklightDialogViewModel, +) { + + var dialog: KeyboardBacklightDialog? = null + + fun startListening() { + applicationScope.launch { + viewModel.dialogContent.collect { dialogViewModel -> + if (dialogViewModel != null) { + if (dialog == null) { + dialog = KeyboardBacklightDialog(context, dialogViewModel) + // pass viewModel and show + } + } else { + dialog?.dismiss() + dialog = null + } + } + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt new file mode 100644 index 000000000000..b68a2a84b5d1 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt @@ -0,0 +1,32 @@ +/* + * 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.systemui.keyboard.backlight.ui.view + +import android.app.Dialog +import android.content.Context +import android.os.Bundle +import com.android.systemui.keyboard.backlight.ui.viewmodel.BacklightDialogContentViewModel + +class KeyboardBacklightDialog(context: Context, val viewModel: BacklightDialogContentViewModel) : + Dialog(context) { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + // TODO(b/268650355) Implement the dialog + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogContentViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogContentViewModel.kt new file mode 100644 index 000000000000..3ef0ca39b8f3 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogContentViewModel.kt @@ -0,0 +1,20 @@ +/* + * 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.systemui.keyboard.backlight.ui.viewmodel + +data class BacklightDialogContentViewModel(val currentValue: Int, val maxValue: Int) diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogViewModel.kt new file mode 100644 index 000000000000..86abca5faaf3 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogViewModel.kt @@ -0,0 +1,72 @@ +/* + * 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.systemui.keyboard.backlight.ui.viewmodel + +import android.view.accessibility.AccessibilityManager +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.keyboard.backlight.domain.interactor.KeyboardBacklightInteractor +import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper +import javax.inject.Inject +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.filterNotNull +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.map + +/** + * Responsible for dialog visibility and content - emits [BacklightDialogContentViewModel] if dialog + * should be shown and hidden otherwise + */ +@SysUISingleton +class BacklightDialogViewModel +@Inject +constructor( + interactor: KeyboardBacklightInteractor, + private val accessibilityManagerWrapper: AccessibilityManagerWrapper, +) { + + private val timeoutMillis: Long + get() = + accessibilityManagerWrapper + .getRecommendedTimeoutMillis( + DEFAULT_DIALOG_TIMEOUT_MILLIS, + AccessibilityManager.FLAG_CONTENT_ICONS + ) + .toLong() + + val dialogContent: Flow<BacklightDialogContentViewModel?> = + interactor.backlight + .filterNotNull() + .map { BacklightDialogContentViewModel(it.level, it.maxLevel) } + .timeout(timeoutMillis, emitAfterTimeout = null) + + private fun <T> Flow<T>.timeout(timeoutMillis: Long, emitAfterTimeout: T): Flow<T> { + return flatMapLatest { + flow { + emit(it) + delay(timeoutMillis) + emit(emitAfterTimeout) + } + } + } + + private companion object { + const val DEFAULT_DIALOG_TIMEOUT_MILLIS = 3000 + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/data/repository/KeyboardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyboard/data/repository/KeyboardRepository.kt index 70faf406d621..9449ece0933b 100644 --- a/packages/SystemUI/src/com/android/systemui/keyboard/data/repository/KeyboardRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyboard/data/repository/KeyboardRepository.kt @@ -23,7 +23,7 @@ import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCall import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background -import com.android.systemui.keyboard.data.model.BacklightModel +import com.android.systemui.keyboard.shared.model.BacklightModel import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/data/model/BacklightModel.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shared/model/BacklightModel.kt index ea15a9f18584..4a32f79285e3 100644 --- a/packages/SystemUI/src/com/android/systemui/keyboard/data/model/BacklightModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shared/model/BacklightModel.kt @@ -15,7 +15,7 @@ * */ -package com.android.systemui.keyboard.data.model +package com.android.systemui.keyboard.shared.model /** * Model for current state of keyboard backlight brightness. [level] indicates current level of diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index d914bf5d8d9a..2815df68ad0a 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -964,13 +964,24 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, public void onAnimationStart(int transit, RemoteAnimationTarget[] apps, RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps, IRemoteAnimationFinishedCallback finishedCallback) throws RemoteException { + if (!handleOnAnimationStart( + transit, apps, wallpapers, nonApps, finishedCallback)) { + // Usually we rely on animation completion to synchronize occluded status, + // but there was no animation to play, so just update it now. + setOccluded(true /* isOccluded */, false /* animate */); + } + } + + private boolean handleOnAnimationStart(int transit, RemoteAnimationTarget[] apps, + RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps, + IRemoteAnimationFinishedCallback finishedCallback) throws RemoteException { if (apps == null || apps.length == 0 || apps[0] == null) { if (DEBUG) { Log.d(TAG, "No apps provided to the OccludeByDream runner; " + "skipping occluding animation."); } finishedCallback.onAnimationFinished(); - return; + return false; } final RemoteAnimationTarget primary = apps[0]; @@ -980,7 +991,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, Log.w(TAG, "The occluding app isn't Dream; " + "finishing up. Please check that the config is correct."); finishedCallback.onAnimationFinished(); - return; + return false; } final SyncRtSurfaceTransactionApplier applier = @@ -1029,6 +1040,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, mOccludeByDreamAnimator.start(); }); + return true; } }; @@ -1920,20 +1932,24 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, // If the keyguard is already showing, see if we don't need to bother re-showing it. Check // flags in both files to account for the hiding animation which results in a delay and - // discrepancy between flags. + // discrepancy between flags. If we're in the middle of hiding, do not short circuit so that + // we explicitly re-set state. if (mShowing && mKeyguardStateController.isShowing()) { - if (mPM.isInteractive()) { + if (mPM.isInteractive() && !mHiding) { // It's already showing, and we're not trying to show it while the screen is off. // We can simply reset all of the views. - if (DEBUG) Log.d(TAG, "doKeyguard: not showing because it is already showing"); + if (DEBUG) Log.d(TAG, "doKeyguard: not showing (instead, resetting) because it is " + + "already showing, we're interactive, and we were not previously hiding. " + + "It should be safe to short-circuit here."); resetStateLocked(); return; } else { - // We are trying to show the keyguard while the screen is off - this results from - // race conditions involving locking while unlocking. Don't short-circuit here and - // ensure the keyguard is fully re-shown. + // We are trying to show the keyguard while the screen is off or while we were in + // the middle of hiding - this results from race conditions involving locking while + // unlocking. Don't short-circuit here and ensure the keyguard is fully re-shown. Log.e(TAG, - "doKeyguard: already showing, but re-showing since we're not interactive"); + "doKeyguard: already showing, but re-showing because we're interactive or " + + "were in the middle of hiding."); } } @@ -2427,11 +2443,19 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, if (DEBUG) Log.d(TAG, "handleShow"); } - mHiding = false; mKeyguardExitAnimationRunner = null; mWakeAndUnlocking = false; setPendingLock(false); - setShowingLocked(true); + + // Force if we we're showing in the middle of hiding, to ensure we end up in the correct + // state. + setShowingLocked(true, mHiding /* force */); + if (mHiding) { + Log.d(TAG, "Forcing setShowingLocked because mHiding=true, which means we're " + + "showing in the middle of hiding."); + } + mHiding = false; + mKeyguardViewControllerLazy.get().show(options); resetKeyguardDonePendingLocked(); mHideAnimationRun = false; diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfig.kt index be73f851fa82..ef0c9a175141 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfig.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfig.kt @@ -134,7 +134,9 @@ constructor( .flowOn(backgroundDispatcher) .distinctUntilChanged() .onEach { settingsValue = it } - ) { callbackFlowValue, _ -> callbackFlowValue } + ) { callbackFlowValue, _ -> + callbackFlowValue + } override suspend fun getPickerScreenState(): KeyguardQuickAffordanceConfig.PickerScreenState { return if (controller.isZenAvailable) { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManager.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManager.kt index 006678546de8..356a8fb65883 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManager.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManager.kt @@ -102,7 +102,8 @@ constructor( // setup). emit(Unit) } - ) { _, _ -> } + ) { _, _ -> + } .flatMapLatest { conflatedCallbackFlow { // We want to instantiate a new SharedPreferences instance each time either the diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepository.kt index 0e85347c24b0..86e5cd738120 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepository.kt @@ -53,6 +53,7 @@ interface KeyguardBouncerRepository { val primaryBouncerScrimmed: StateFlow<Boolean> /** * Set how much of the notification panel is showing on the screen. + * * ``` * 0f = panel fully hidden = bouncer fully showing * 1f = panel fully showing = bouncer fully hidden @@ -134,6 +135,7 @@ constructor( override val primaryBouncerScrimmed = _primaryBouncerScrimmed.asStateFlow() /** * Set how much of the notification panel is showing on the screen. + * * ``` * 0f = panel fully hidden = bouncer fully showing * 1f = panel fully showing = bouncer fully hidden diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt index a3b3d0fd0681..76f20d25b0ec 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt @@ -80,6 +80,9 @@ interface KeyguardRepository { */ val isKeyguardShowing: Flow<Boolean> + /** Is the keyguard in a unlocked state? */ + val isKeyguardUnlocked: Flow<Boolean> + /** Is an activity showing over the keyguard? */ val isKeyguardOccluded: Flow<Boolean> @@ -278,6 +281,31 @@ constructor( } .distinctUntilChanged() + override val isKeyguardUnlocked: Flow<Boolean> = + conflatedCallbackFlow { + val callback = + object : KeyguardStateController.Callback { + override fun onUnlockedChanged() { + trySendWithFailureLogging( + keyguardStateController.isUnlocked, + TAG, + "updated isKeyguardUnlocked" + ) + } + } + + keyguardStateController.addCallback(callback) + // Adding the callback does not send an initial update. + trySendWithFailureLogging( + keyguardStateController.isUnlocked, + TAG, + "initial isKeyguardUnlocked" + ) + + awaitClose { keyguardStateController.removeCallback(callback) } + } + .distinctUntilChanged() + override val isKeyguardGoingAway: Flow<Boolean> = conflatedCallbackFlow { val callback = object : KeyguardStateController.Callback { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt index 0c4bca616e12..100bc596103d 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt @@ -68,8 +68,11 @@ interface KeyguardTransitionRepository { /** * Begin a transition from one state to another. Transitions are interruptible, and will issue a * [TransitionStep] with state = [TransitionState.CANCELED] before beginning the next one. + * + * When canceled, there are two options: to continue from the current position of the prior + * transition, or to reset the position. When [resetIfCanceled] == true, it will do the latter. */ - fun startTransition(info: TransitionInfo): UUID? + fun startTransition(info: TransitionInfo, resetIfCanceled: Boolean = false): UUID? /** * Allows manual control of a transition. When calling [startTransition], the consumer must pass @@ -130,7 +133,10 @@ class KeyguardTransitionRepositoryImpl @Inject constructor() : KeyguardTransitio ) } - override fun startTransition(info: TransitionInfo): UUID? { + override fun startTransition( + info: TransitionInfo, + resetIfCanceled: Boolean, + ): UUID? { if (lastStep.from == info.from && lastStep.to == info.to) { Log.i(TAG, "Duplicate call to start the transition, rejecting: $info") return null @@ -138,7 +144,11 @@ class KeyguardTransitionRepositoryImpl @Inject constructor() : KeyguardTransitio val startingValue = if (lastStep.transitionState != TransitionState.FINISHED) { Log.i(TAG, "Transition still active: $lastStep, canceling") - lastStep.value + if (resetIfCanceled) { + 0f + } else { + lastStep.value + } } else { 0f } @@ -227,10 +237,7 @@ class KeyguardTransitionRepositoryImpl @Inject constructor() : KeyguardTransitio } private fun trace(step: TransitionStep, isManual: Boolean) { - if ( - step.transitionState != TransitionState.STARTED && - step.transitionState != TransitionState.FINISHED - ) { + if (step.transitionState == TransitionState.RUNNING) { return } val traceName = @@ -243,7 +250,10 @@ class KeyguardTransitionRepositoryImpl @Inject constructor() : KeyguardTransitio val traceCookie = traceName.hashCode() if (step.transitionState == TransitionState.STARTED) { Trace.beginAsyncSection(traceName, traceCookie) - } else if (step.transitionState == TransitionState.FINISHED) { + } else if ( + step.transitionState == TransitionState.FINISHED || + step.transitionState == TransitionState.CANCELED + ) { Trace.endAsyncSection(traceName, traceCookie) } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt index 014052956d2f..eae40d61cdb6 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt @@ -50,6 +50,7 @@ constructor( /** * Sets the correct bouncer states to show the alternate bouncer if it can show. + * * @return whether alternateBouncer is visible */ fun show(): Boolean { @@ -74,6 +75,7 @@ constructor( * Sets the correct bouncer states to hide the bouncer. Should only be called through * StatusBarKeyguardViewManager until ScrimController is refactored to use * alternateBouncerInteractor. + * * @return true if the alternate bouncer was newly hidden, else false. */ fun hide(): Boolean { 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 310f44da6e66..e6568f20bc20 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 @@ -71,8 +71,7 @@ constructor( isPrimaryBouncerShowing, lastStartedTransitionStep, wakefulnessState, - isAodAvailable - ) -> + isAodAvailable) -> if ( !isAlternateBouncerShowing && !isPrimaryBouncerShowing && 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 8715d1f55069..3beac0b1322e 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 @@ -34,7 +34,6 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.delay import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch @@ -57,14 +56,7 @@ constructor( private fun listenForDreamingToLockscreen() { scope.launch { - // Dependending on the dream, either dream state or occluded change will change first, - // so listen for both - combine(keyguardInteractor.isAbleToDream, keyguardInteractor.isKeyguardOccluded) { - isAbleToDream, - isKeyguardOccluded -> - isAbleToDream && isKeyguardOccluded - } - .distinctUntilChanged() + keyguardInteractor.isAbleToDream .sample( combine( keyguardInteractor.dozeTransitionModel, 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 d01f48970c97..911861ddde47 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 @@ -130,55 +130,59 @@ constructor( shadeRepository.shadeModel .sample( combine( - keyguardTransitionInteractor.finishedKeyguardState, + keyguardTransitionInteractor.startedKeyguardTransitionStep, keyguardInteractor.statusBarState, - ::Pair + keyguardInteractor.isKeyguardUnlocked, + ::toTriple ), - ::toTriple + ::toQuad ) - .collect { (shadeModel, keyguardState, statusBarState) -> + .collect { (shadeModel, keyguardState, statusBarState, isKeyguardUnlocked) -> val id = transitionId if (id != null) { - // An existing `id` means a transition is started, and calls to - // `updateTransition` will control it until FINISHED or CANCELED - var nextState = - if (shadeModel.expansionAmount == 0f) { - TransitionState.FINISHED - } else if (shadeModel.expansionAmount == 1f) { - TransitionState.CANCELED - } else { - TransitionState.RUNNING - } - keyguardTransitionRepository.updateTransition( - id, - 1f - shadeModel.expansionAmount, - nextState, - ) + if (keyguardState.to == KeyguardState.PRIMARY_BOUNCER) { + // An existing `id` means a transition is started, and calls to + // `updateTransition` will control it until FINISHED or CANCELED + var nextState = + if (shadeModel.expansionAmount == 0f) { + TransitionState.FINISHED + } else if (shadeModel.expansionAmount == 1f) { + TransitionState.CANCELED + } else { + TransitionState.RUNNING + } + keyguardTransitionRepository.updateTransition( + id, + 1f - shadeModel.expansionAmount, + nextState, + ) - if ( - nextState == TransitionState.CANCELED || - nextState == TransitionState.FINISHED - ) { - transitionId = null - } + if ( + nextState == TransitionState.CANCELED || + nextState == TransitionState.FINISHED + ) { + transitionId = null + } - // If canceled, just put the state back - if (nextState == TransitionState.CANCELED) { - keyguardTransitionRepository.startTransition( - TransitionInfo( - ownerName = name, - from = KeyguardState.PRIMARY_BOUNCER, - to = KeyguardState.LOCKSCREEN, - animator = getAnimator(0.milliseconds) + // If canceled, just put the state back + if (nextState == TransitionState.CANCELED) { + keyguardTransitionRepository.startTransition( + TransitionInfo( + ownerName = name, + from = KeyguardState.PRIMARY_BOUNCER, + to = KeyguardState.LOCKSCREEN, + animator = getAnimator(0.milliseconds) + ) ) - ) + } } } else { // TODO (b/251849525): Remove statusbarstate check when that state is // integrated into KeyguardTransitionRepository if ( - keyguardState == KeyguardState.LOCKSCREEN && + keyguardState.to == KeyguardState.LOCKSCREEN && shadeModel.isUserDragging && + !isKeyguardUnlocked && statusBarState == KEYGUARD ) { transitionId = 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 b59b413d7a40..94961cbf4240 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 @@ -17,6 +17,9 @@ package com.android.systemui.keyguard.domain.interactor import android.animation.ValueAnimator +import com.android.keyguard.KeyguardSecurityModel +import com.android.keyguard.KeyguardSecurityModel.SecurityMode.Password +import com.android.keyguard.KeyguardUpdateMonitor import com.android.systemui.animation.Interpolators import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application @@ -26,6 +29,8 @@ import com.android.systemui.keyguard.shared.model.TransitionInfo import com.android.systemui.keyguard.shared.model.WakefulnessState import com.android.systemui.util.kotlin.sample import javax.inject.Inject +import kotlin.time.Duration +import kotlin.time.Duration.Companion.milliseconds import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.combine import kotlinx.coroutines.launch @@ -37,7 +42,8 @@ constructor( @Application private val scope: CoroutineScope, private val keyguardInteractor: KeyguardInteractor, private val keyguardTransitionRepository: KeyguardTransitionRepository, - private val keyguardTransitionInteractor: KeyguardTransitionInteractor + private val keyguardTransitionInteractor: KeyguardTransitionInteractor, + private val keyguardSecurityModel: KeyguardSecurityModel, ) : TransitionInteractor(FromPrimaryBouncerTransitionInteractor::class.simpleName!!) { override fun start() { @@ -93,31 +99,47 @@ constructor( private fun listenForPrimaryBouncerToGone() { scope.launch { keyguardInteractor.isKeyguardGoingAway - .sample(keyguardTransitionInteractor.finishedKeyguardState) { a, b -> Pair(a, b) } - .collect { pair -> - val (isKeyguardGoingAway, keyguardState) = pair - if (isKeyguardGoingAway && keyguardState == KeyguardState.PRIMARY_BOUNCER) { + .sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair) + .collect { (isKeyguardGoingAway, lastStartedTransitionStep) -> + if ( + isKeyguardGoingAway && + lastStartedTransitionStep.to == KeyguardState.PRIMARY_BOUNCER + ) { + val securityMode = + keyguardSecurityModel.getSecurityMode( + KeyguardUpdateMonitor.getCurrentUser() + ) + // IME for password requires a slightly faster animation + val duration = + if (securityMode == Password) { + TO_GONE_SHORT_DURATION + } else { + TO_GONE_DURATION + } keyguardTransitionRepository.startTransition( TransitionInfo( ownerName = name, from = KeyguardState.PRIMARY_BOUNCER, to = KeyguardState.GONE, - animator = getAnimator(), - ) + animator = getAnimator(duration), + ), + resetIfCanceled = true, ) } } } } - private fun getAnimator(): ValueAnimator { + private fun getAnimator(duration: Duration = DEFAULT_DURATION): ValueAnimator { return ValueAnimator().apply { setInterpolator(Interpolators.LINEAR) - setDuration(TRANSITION_DURATION_MS) + setDuration(duration.inWholeMilliseconds) } } companion object { - private const val TRANSITION_DURATION_MS = 300L + private val DEFAULT_DURATION = 300.milliseconds + val TO_GONE_DURATION = 250.milliseconds + val TO_GONE_SHORT_DURATION = 200.milliseconds } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt index d25aff0add86..ec99049b42e3 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt @@ -33,7 +33,9 @@ import com.android.systemui.keyguard.shared.model.DozeStateModel.Companion.isDoz import com.android.systemui.keyguard.shared.model.DozeTransitionModel import com.android.systemui.keyguard.shared.model.StatusBarState import com.android.systemui.keyguard.shared.model.WakefulnessModel +import com.android.systemui.keyguard.shared.model.WakefulnessModel.Companion.isWakingOrStartingToWake import com.android.systemui.statusbar.CommandQueue +import com.android.systemui.util.kotlin.sample import javax.inject.Inject import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.delay @@ -95,6 +97,9 @@ constructor( awaitClose { commandQueue.removeCallback(callback) } } + /** The device wake/sleep state */ + val wakefulnessModel: Flow<WakefulnessModel> = repository.wakefulness + /** * Dozing and dreaming have overlapping events. If the doze state remains in FINISH, it means * that doze mode is not running and DREAMING is ok to commence. @@ -109,6 +114,12 @@ constructor( isDreaming && isDozeOff(dozeTransitionModel.to) } ) + .sample( + wakefulnessModel, + { isAbleToDream, wakefulnessModel -> + isAbleToDream && isWakingOrStartingToWake(wakefulnessModel) + } + ) .flatMapLatest { isAbleToDream -> flow { delay(50) @@ -119,6 +130,8 @@ constructor( /** Whether the keyguard is showing or not. */ val isKeyguardShowing: Flow<Boolean> = repository.isKeyguardShowing + /** Whether the keyguard is unlocked or not. */ + val isKeyguardUnlocked: Flow<Boolean> = repository.isKeyguardUnlocked /** Whether the keyguard is occluded (covered by an activity). */ val isKeyguardOccluded: Flow<Boolean> = repository.isKeyguardOccluded /** Whether the keyguard is going away. */ @@ -127,8 +140,6 @@ constructor( val primaryBouncerShowing: Flow<Boolean> = bouncerRepository.primaryBouncerVisible /** Whether the alternate bouncer is showing or not. */ val alternateBouncerShowing: Flow<Boolean> = bouncerRepository.alternateBouncerVisible - /** The device wake/sleep state */ - val wakefulnessModel: Flow<WakefulnessModel> = repository.wakefulness /** Observable for the [StatusBarState] */ val statusBarState: Flow<StatusBarState> = repository.statusBarState /** diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt index dfbe1c216847..568cc0f42639 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt @@ -119,7 +119,7 @@ constructor( * Notifies that a quick affordance has been "triggered" (clicked) by the user. * * @param configKey The configuration key corresponding to the [KeyguardQuickAffordanceModel] of - * the affordance that was clicked + * the affordance that was clicked * @param expandable An optional [Expandable] for the activity- or dialog-launch animation */ fun onQuickAffordanceTriggered( @@ -198,9 +198,9 @@ constructor( * * @param slotId The ID of the slot. * @param affordanceId The ID of the affordance to remove; if `null`, removes all affordances - * from the slot. + * from the slot. * @return `true` if the affordance was successfully removed; `false` otherwise (for example, if - * the affordance was not on the slot to begin with). + * the affordance was not on the slot to begin with). */ suspend fun unselect(slotId: String, affordanceId: String?): Boolean { check(isUsingRepository) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt index 51b02779a89f..e650b9fc0e47 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt @@ -61,7 +61,15 @@ constructor( } scope.launch { - keyguardInteractor.isDreaming.collect { logger.log(TAG, VERBOSE, "isDreaming", it) } + keyguardInteractor.isAbleToDream.collect { + logger.log(TAG, VERBOSE, "isAbleToDream", it) + } + } + + scope.launch { + keyguardInteractor.isKeyguardOccluded.collect { + logger.log(TAG, VERBOSE, "isOccluded", it) + } } scope.launch { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt index 1b7da5b65a03..3c0ec350c5c5 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt @@ -78,6 +78,10 @@ constructor( val occludedToLockscreenTransition: Flow<TransitionStep> = repository.transition(OCCLUDED, LOCKSCREEN) + /** PRIMARY_BOUNCER->GONE transition information. */ + val primaryBouncerToGoneTransition: Flow<TransitionStep> = + repository.transition(PRIMARY_BOUNCER, GONE) + /** * AOD<->LOCKSCREEN transition information, mapped to dozeAmount range of AOD (1f) <-> * Lockscreen (0f). diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt index ca1e27c9d19c..38b9d508f81c 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt @@ -47,6 +47,7 @@ class KeyguardTransitionAnimationFlow( duration: Duration, onStep: (Float) -> Float, startTime: Duration = 0.milliseconds, + onStart: (() -> Unit)? = null, onCancel: (() -> Float)? = null, onFinish: (() -> Float)? = null, interpolator: Interpolator = LINEAR, @@ -73,6 +74,7 @@ class KeyguardTransitionAnimationFlow( // the ViewModels of the last update STARTED -> { isComplete = false + onStart?.invoke() max(0f, min(1f, value)) } // Always send a final value of 1. Because of rounding, [value] may never be diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt index ab009f4a6a66..2a9060f6db47 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt @@ -342,7 +342,13 @@ object KeyguardBottomAreaViewBinder { if (viewModel.isClickable) { if (viewModel.useLongPress) { view.setOnTouchListener( - OnTouchListener(view, viewModel, messageDisplayer, vibratorHelper) + OnTouchListener( + view, + viewModel, + messageDisplayer, + vibratorHelper, + falsingManager, + ) ) } else { view.setOnClickListener(OnClickListener(viewModel, checkNotNull(falsingManager))) @@ -371,6 +377,7 @@ object KeyguardBottomAreaViewBinder { private val viewModel: KeyguardQuickAffordanceViewModel, private val messageDisplayer: (Int) -> Unit, private val vibratorHelper: VibratorHelper?, + private val falsingManager: FalsingManager?, ) : View.OnTouchListener { private val longPressDurationMs = ViewConfiguration.getLongPressTimeout().toLong() @@ -395,7 +402,14 @@ object KeyguardBottomAreaViewBinder { .scaleY(PRESSED_SCALE) .setDuration(longPressDurationMs) .withEndAction { - dispatchClick(viewModel.configKey) + if ( + falsingManager + ?.isFalseLongTap( + FalsingManager.MODERATE_PENALTY + ) == false + ) { + dispatchClick(viewModel.configKey) + } cancel() } } @@ -421,7 +435,8 @@ object KeyguardBottomAreaViewBinder { // the pointer performs a click. if ( viewModel.configKey != null && - distanceMoved(event) <= ViewConfiguration.getTouchSlop() + distanceMoved(event) <= ViewConfiguration.getTouchSlop() && + falsingManager?.isFalseTap(FalsingManager.NO_PENALTY) == false ) { dispatchClick(viewModel.configKey) } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt index 7db567b2a0e9..2337ffc35fa6 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt @@ -31,6 +31,7 @@ import com.android.settingslib.Utils import com.android.systemui.keyguard.data.BouncerViewDelegate import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE import com.android.systemui.keyguard.ui.viewmodel.KeyguardBouncerViewModel +import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.plugins.ActivityStarter import kotlinx.coroutines.awaitCancellation @@ -44,6 +45,7 @@ object KeyguardBouncerViewBinder { fun bind( view: ViewGroup, viewModel: KeyguardBouncerViewModel, + primaryBouncerToGoneTransitionViewModel: PrimaryBouncerToGoneTransitionViewModel, componentFactory: KeyguardBouncerComponent.Factory ) { // Builds the KeyguardSecurityContainerController from bouncer view group. @@ -145,6 +147,12 @@ object KeyguardBouncerViewBinder { } launch { + primaryBouncerToGoneTransitionViewModel.bouncerAlpha.collect { alpha -> + securityContainerController.setAlpha(alpha) + } + } + + launch { viewModel.bouncerExpansionAmount .filter { it == EXPANSION_VISIBLE } .collect { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardLongPressViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardLongPressViewBinder.kt index ef3f242a39a9..86717537efd3 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardLongPressViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardLongPressViewBinder.kt @@ -34,7 +34,7 @@ object KeyguardLongPressViewBinder { * @param viewModel The view-model that models the UI state. * @param onSingleTap A callback to invoke when the system decides that there was a single tap. * @param falsingManager [FalsingManager] for making sure the long-press didn't just happen in - * the user's pocket. + * the user's pocket. */ @JvmStatic fun bind( diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt index e7184f74ca59..ab9e6a4ce045 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt @@ -135,7 +135,7 @@ constructor( * * @param initiallySelectedSlotId The ID of the initial slot to render as the selected one. * @param shouldHighlightSelectedAffordance Whether the selected quick affordance should be - * highlighted (while all others are dimmed to make the selected one stand out). + * highlighted (while all others are dimmed to make the selected one stand out). */ fun enablePreviewMode( initiallySelectedSlotId: String?, diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt new file mode 100644 index 000000000000..92038e24edf3 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt @@ -0,0 +1,69 @@ +/* + * 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.systemui.keyguard.ui.viewmodel + +import com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor.Companion.TO_GONE_DURATION +import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor +import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow +import com.android.systemui.statusbar.SysuiStatusBarStateController +import javax.inject.Inject +import kotlin.time.Duration.Companion.milliseconds +import kotlinx.coroutines.flow.Flow + +/** + * Breaks down PRIMARY_BOUNCER->GONE transition into discrete steps for corresponding views to + * consume. + */ +@SysUISingleton +class PrimaryBouncerToGoneTransitionViewModel +@Inject +constructor( + private val interactor: KeyguardTransitionInteractor, + private val statusBarStateController: SysuiStatusBarStateController, +) { + private val transitionAnimation = + KeyguardTransitionAnimationFlow( + transitionDuration = TO_GONE_DURATION, + transitionFlow = interactor.primaryBouncerToGoneTransition, + ) + + private var leaveShadeOpen: Boolean = false + + /** Bouncer container alpha */ + val bouncerAlpha: Flow<Float> = + transitionAnimation.createFlow( + duration = 200.milliseconds, + onStep = { 1f - it }, + ) + + /** Scrim behind alpha */ + val scrimBehindAlpha: Flow<Float> = + transitionAnimation.createFlow( + duration = TO_GONE_DURATION, + interpolator = EMPHASIZED_ACCELERATE, + onStart = { leaveShadeOpen = statusBarStateController.leaveOpenOnKeyguardHide() }, + onStep = { + if (leaveShadeOpen) { + 1f + } else { + 1f - it + } + }, + ) +} diff --git a/packages/SystemUI/src/com/android/systemui/lifecycle/RepeatWhenAttached.kt b/packages/SystemUI/src/com/android/systemui/lifecycle/RepeatWhenAttached.kt index d69ac7fe035d..34a67403fc84 100644 --- a/packages/SystemUI/src/com/android/systemui/lifecycle/RepeatWhenAttached.kt +++ b/packages/SystemUI/src/com/android/systemui/lifecycle/RepeatWhenAttached.kt @@ -47,13 +47,13 @@ import kotlinx.coroutines.launch * fresh one. * * @param coroutineContext An optional [CoroutineContext] to replace the dispatcher [block] is - * invoked on. + * invoked on. * @param block The block of code that should be run when the view becomes attached. It can end up - * being invoked multiple times if the view is reattached after being detached. + * being invoked multiple times if the view is reattached after being detached. * @return A [DisposableHandle] to invoke when the caller of the function destroys its [View] and is - * no longer interested in the [block] being run the next time its attached. Calling this is an - * optional optimization as the logic will be properly cleaned up and destroyed each time the view - * is detached. Using this is not *thread-safe* and should only be used on the main thread. + * no longer interested in the [block] being run the next time its attached. Calling this is an + * optional optimization as the logic will be properly cleaned up and destroyed each time the view + * is detached. Using this is not *thread-safe* and should only be used on the main thread. */ @MainThread fun View.repeatWhenAttached( @@ -125,7 +125,6 @@ private fun createLifecycleOwnerAndRun( * The implementation requires the caller to call [onCreate] and [onDestroy] when the view is * attached to or detached from a view hierarchy. After [onCreate] and before [onDestroy] is called, * the implementation monitors window state in the following way - * * * If the window is not visible, we are in the [Lifecycle.State.CREATED] state * * If the window is visible but not focused, we are in the [Lifecycle.State.STARTED] state * * If the window is visible and focused, we are in the [Lifecycle.State.RESUMED] state diff --git a/packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt b/packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt index f7349a2a7ae6..647e3a15ba2f 100644 --- a/packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt @@ -16,7 +16,6 @@ private const val TAG = "KeyguardFaceAuthManagerLog" * Helper class for logging for [com.android.keyguard.faceauth.KeyguardFaceAuthManager] * * To enable logcat echoing for an entire buffer: - * * ``` * adb shell settings put global systemui/buffer/KeyguardFaceAuthManagerLog <logLevel> * diff --git a/packages/SystemUI/src/com/android/systemui/log/ScreenDecorationsLogger.kt b/packages/SystemUI/src/com/android/systemui/log/ScreenDecorationsLogger.kt index 5acaa46c25d6..edc278d1ae4f 100644 --- a/packages/SystemUI/src/com/android/systemui/log/ScreenDecorationsLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/log/ScreenDecorationsLogger.kt @@ -33,7 +33,6 @@ private const val TAG = "ScreenDecorationsLog" * Helper class for logging for [com.android.systemui.ScreenDecorations] * * To enable logcat echoing for an entire buffer: - * * ``` * adb shell settings put global systemui/buffer/ScreenDecorationsLog <logLevel> * diff --git a/services/people/java/com/android/server/people/data/PerPackageThrottler.java b/packages/SystemUI/src/com/android/systemui/log/dagger/DeviceStateAutoRotationLog.java index 3d6cd84d326a..beb725e61e4a 100644 --- a/services/people/java/com/android/server/people/data/PerPackageThrottler.java +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/DeviceStateAutoRotationLog.java @@ -14,15 +14,17 @@ * limitations under the License. */ -package com.android.server.people.data; +package com.android.systemui.log.dagger; -import android.util.Pair; +import static java.lang.annotation.RetentionPolicy.RUNTIME; -/** The interface for throttling expensive runnables per package. */ -interface PerPackageThrottler { - /** - * Schedule a runnable to run in the future, and debounce runnables for same {@code pkgUserId} - * that occur until that future has run. - */ - void scheduleDebounced(Pair<String, Integer> pkgUserId, Runnable runnable); +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; + +import javax.inject.Qualifier; + +@Qualifier +@Documented +@Retention(RUNTIME) +public @interface DeviceStateAutoRotationLog { } 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 642c9f73f625..98b6d70317b8 100644 --- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java @@ -370,6 +370,16 @@ public class LogModule { } /** + * Provides a {@link LogBuffer} for Device State Auto-Rotation logs. + */ + @Provides + @SysUISingleton + @DeviceStateAutoRotationLog + public static LogBuffer provideDeviceStateAutoRotationLogBuffer(LogBufferFactory factory) { + return factory.create("DeviceStateAutoRotationLog", 100); + } + + /** * Provides a {@link LogBuffer} for bluetooth-related logs. */ @Provides diff --git a/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt b/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt index 1712dab8aff9..29f273a5ed41 100644 --- a/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt +++ b/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt @@ -29,7 +29,6 @@ import kotlinx.coroutines.flow.Flow * * Some parts of System UI maintain a lot of pieces of state at once. * [com.android.systemui.plugins.log.LogBuffer] allows us to easily log change events: - * * - 10-10 10:10:10.456: state2 updated to newVal2 * - 10-10 10:11:00.000: stateN updated to StateN(val1=true, val2=1) * - 10-10 10:11:02.123: stateN updated to StateN(val1=true, val2=2) @@ -37,7 +36,6 @@ import kotlinx.coroutines.flow.Flow * - 10-10 10:11:06.000: stateN updated to StateN(val1=false, val2=3) * * However, it can sometimes be more useful to view the state changes in table format: - * * - timestamp--------- | state1- | state2- | ... | stateN.val1 | stateN.val2 * - ------------------------------------------------------------------------- * - 10-10 10:10:10.123 | val1--- | val2--- | ... | false------ | 0----------- @@ -56,23 +54,18 @@ import kotlinx.coroutines.flow.Flow * individual fields. * * How it works: - * * 1) Create an instance of this buffer via [TableLogBufferFactory]. - * * 2) For any states being logged, implement [Diffable]. Implementing [Diffable] allows the state to - * only log the fields that have *changed* since the previous update, instead of always logging all - * fields. - * + * only log the fields that have *changed* since the previous update, instead of always logging + * all fields. * 3) Each time a change in a state happens, call [logDiffs]. If your state is emitted using a - * [Flow], you should use the [logDiffsForTable] extension function to automatically log diffs any - * time your flow emits a new value. + * [Flow], you should use the [logDiffsForTable] extension function to automatically log diffs + * any time your flow emits a new value. * * When a dump occurs, there will be two dumps: - * * 1) The change events under the dumpable name "$name-changes". - * * 2) This class will coalesce all the diffs into a table format and log them under the dumpable - * name "$name-table". + * name "$name-table". * * @param maxSize the maximum size of the buffer. Must be > 0. */ @@ -99,11 +92,10 @@ class TableLogBuffer( * The [newVal] object's method [Diffable.logDiffs] will be used to fetch the diffs. * * @param columnPrefix a prefix that will be applied to every column name that gets logged. This - * ensures that all the columns related to the same state object will be grouped together in the - * table. - * + * ensures that all the columns related to the same state object will be grouped together in + * the table. * @throws IllegalArgumentException if [columnPrefix] or column name contain "|". "|" is used as - * the separator token for parsing, so it can't be present in any part of the column name. + * the separator token for parsing, so it can't be present in any part of the column name. */ @Synchronized fun <T : Diffable<T>> logDiffs(columnPrefix: String, prevVal: T, newVal: T) { @@ -117,7 +109,7 @@ class TableLogBuffer( * Logs change(s) to the buffer using [rowInitializer]. * * @param rowInitializer a function that will be called immediately to store relevant data on - * the row. + * the row. */ @Synchronized fun logChange(columnPrefix: String, rowInitializer: (TableRowLogger) -> Unit) { diff --git a/packages/SystemUI/src/com/android/systemui/log/table/TableLogBufferFactory.kt b/packages/SystemUI/src/com/android/systemui/log/table/TableLogBufferFactory.kt index 7ccc43ce62c2..06668d33408d 100644 --- a/packages/SystemUI/src/com/android/systemui/log/table/TableLogBufferFactory.kt +++ b/packages/SystemUI/src/com/android/systemui/log/table/TableLogBufferFactory.kt @@ -38,7 +38,6 @@ constructor( * * @param name a unique table name * @param maxSize the buffer max size. See [adjustMaxSize] - * * @return a new [TableLogBuffer] registered with [DumpManager] */ fun create( diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/models/player/SeekBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/controls/models/player/SeekBarViewModel.kt index a057c9f22be3..2509f21242cd 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/models/player/SeekBarViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/models/player/SeekBarViewModel.kt @@ -187,6 +187,7 @@ constructor( /** * Handle request to change the current position in the media track. + * * @param position Place to seek to in the track. */ @AnyThread diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/models/recommendation/SmartspaceMediaData.kt b/packages/SystemUI/src/com/android/systemui/media/controls/models/recommendation/SmartspaceMediaData.kt index 0b57175defe7..ae03f27b32cd 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/models/recommendation/SmartspaceMediaData.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/models/recommendation/SmartspaceMediaData.kt @@ -52,6 +52,7 @@ data class SmartspaceMediaData( * Indicates if all the data is valid. * * TODO(b/230333302): Make MediaControlPanel more flexible so that we can display fewer than + * * ``` * [NUM_REQUIRED_RECOMMENDATIONS]. * ``` diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataFilter.kt b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataFilter.kt index 97717a64ce26..207df6bc4422 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataFilter.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataFilter.kt @@ -329,9 +329,8 @@ constructor( * Return the time since last active for the most-recent media. * * @param sortedEntries userEntries sorted from the earliest to the most-recent. - * * @return The duration in milliseconds from the most-recent media's last active timestamp to - * the present. MAX_VALUE will be returned if there is no media. + * the present. MAX_VALUE will be returned if there is no media. */ private fun timeSinceActiveForMostRecentMedia( sortedEntries: SortedMap<String, MediaData> diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt index e70a2f3ed446..6023bc250b1b 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt @@ -525,8 +525,8 @@ class MediaDataManager( * through the internal listener pipeline. * * @param immediately indicates should apply the UI changes immediately, otherwise wait until - * the next refresh-round before UI becomes visible. Should only be true if the update is - * initiated by user's interaction. + * the next refresh-round before UI becomes visible. Should only be true if the update is + * initiated by user's interaction. */ private fun notifySmartspaceMediaDataRemoved(key: String, immediately: Boolean) { internalListeners.forEach { it.onSmartspaceMediaDataRemoved(key, immediately) } @@ -535,6 +535,7 @@ class MediaDataManager( /** * Called whenever the player has been paused or stopped for a while, or swiped from QQS. This * will make the player not active anymore, hiding it from QQS and Keyguard. + * * @see MediaData.active */ internal fun setTimedOut(key: String, timedOut: Boolean, forceUpdate: Boolean = false) { @@ -1023,6 +1024,7 @@ class MediaDataManager( * @param packageName Package name for the media app * @param controller MediaController for the current session * @return a Pair consisting of a list of media actions, and a list of ints representing which + * * ``` * of those actions should be shown in the compact player * ``` @@ -1126,6 +1128,7 @@ class MediaDataManager( * [PlaybackState.ACTION_SKIP_TO_NEXT] * @return * ``` + * * A [MediaAction] with correct values set, or null if the state doesn't support it */ private fun getStandardAction( @@ -1226,6 +1229,7 @@ class MediaDataManager( } /** * Load a bitmap from a URI + * * @param uri the uri to load * @return bitmap, or null if couldn't be loaded */ @@ -1519,15 +1523,13 @@ class MediaDataManager( * notification key) or vice versa. * * @param immediately indicates should apply the UI changes immediately, otherwise wait - * until the next refresh-round before UI becomes visible. True by default to take in place - * immediately. - * + * until the next refresh-round before UI becomes visible. True by default to take in + * place immediately. * @param receivedSmartspaceCardLatency is the latency between headphone connects and sysUI - * displays Smartspace media targets. Will be 0 if the data is not activated by Smartspace - * signal. - * + * displays Smartspace media targets. Will be 0 if the data is not activated by Smartspace + * signal. * @param isSsReactivated indicates resume media card is reactivated by Smartspace - * recommendation signal + * recommendation signal */ fun onMediaDataLoaded( key: String, @@ -1542,8 +1544,8 @@ class MediaDataManager( * Called whenever there's new Smartspace media data loaded. * * @param shouldPrioritize indicates the sorting priority of the Smartspace card. If true, - * it will be prioritized as the first card. Otherwise, it will show up as the last card as - * default. + * it will be prioritized as the first card. Otherwise, it will show up as the last card + * as default. */ fun onSmartspaceMediaDataLoaded( key: String, @@ -1558,8 +1560,8 @@ class MediaDataManager( * Called whenever a previously existing Smartspace media data was removed. * * @param immediately indicates should apply the UI changes immediately, otherwise wait - * until the next refresh-round before UI becomes visible. True by default to take in place - * immediately. + * until the next refresh-round before UI becomes visible. True by default to take in + * place immediately. */ fun onSmartspaceMediaDataRemoved(key: String, immediately: Boolean = true) {} } @@ -1568,7 +1570,7 @@ class MediaDataManager( * Converts the pass-in SmartspaceTarget to SmartspaceMediaData * * @return An empty SmartspaceMediaData with the valid target Id is returned if the - * SmartspaceTarget's data is invalid. + * SmartspaceTarget's data is invalid. */ private fun toSmartspaceMediaData(target: SmartspaceTarget): SmartspaceMediaData { var dismissIntent: Intent? = null diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDeviceManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDeviceManager.kt index 6a512be091e1..120704c0582a 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDeviceManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDeviceManager.kt @@ -408,9 +408,9 @@ constructor( * [LocalMediaManager.DeviceCallback.onAboutToConnectDeviceAdded] for more information. * * @property fullMediaDevice a full-fledged [MediaDevice] object representing the device. If - * non-null, prefer using [fullMediaDevice] over [backupMediaDeviceData]. + * non-null, prefer using [fullMediaDevice] over [backupMediaDeviceData]. * @property backupMediaDeviceData a backup [MediaDeviceData] object containing the minimum - * information required to display the device. Only use if [fullMediaDevice] is null. + * information required to display the device. Only use if [fullMediaDevice] is null. */ private data class AboutToConnectDevice( val fullMediaDevice: MediaDevice? = null, diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaTimeoutListener.kt b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaTimeoutListener.kt index 878962dc60b4..a1d9214cb215 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaTimeoutListener.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaTimeoutListener.kt @@ -60,6 +60,7 @@ constructor( /** * Callback representing that a media object is now expired: + * * @param key Media control unique identifier * @param timedOut True when expired for {@code PAUSED_MEDIA_TIMEOUT} for active media, * ``` @@ -70,6 +71,7 @@ constructor( /** * Callback representing that a media object [PlaybackState] has changed. + * * @param key Media control unique identifier * @param state The new [PlaybackState] */ @@ -77,6 +79,7 @@ constructor( /** * Callback representing that the [MediaSession] for an active control has been destroyed + * * @param key Media control unique identifier */ lateinit var sessionCallback: (String) -> Unit diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/resume/MediaResumeListener.kt b/packages/SystemUI/src/com/android/systemui/media/controls/resume/MediaResumeListener.kt index 2af21c4dbd9f..92e0c851a462 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/resume/MediaResumeListener.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/resume/MediaResumeListener.kt @@ -297,6 +297,7 @@ constructor( /** * Add the component to the saved list of media browser services, checking for duplicates and * removing older components that exceed the maximum limit + * * @param componentName */ private fun updateResumptionList(componentName: ComponentName) { diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowserLogger.kt b/packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowserLogger.kt index 335ce1d3d694..095cf09a6c2c 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowserLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowserLogger.kt @@ -52,10 +52,12 @@ class ResumeMediaBrowserLogger @Inject constructor(@MediaBrowserLog private val * event. * * @param isBrowserConnected true if there's a currently connected + * * ``` * [android.media.browse.MediaBrowser] and false otherwise. * @param componentName * ``` + * * the component name for the [ResumeMediaBrowser] that triggered this log. */ fun logSessionDestroyed(isBrowserConnected: Boolean, componentName: ComponentName) = diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/AnimationBindHandler.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/AnimationBindHandler.kt index d2793bca867b..f5cc04331f94 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/AnimationBindHandler.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/AnimationBindHandler.kt @@ -24,10 +24,12 @@ import android.graphics.drawable.Drawable * and conflicts due to media notifications arriving at any time during an animation. It does this * in two parts. * - Exit animations fired as a result of user input are tracked. When these are running, any + * * ``` * bind actions are delayed until the animation completes (and then fired in sequence). * ``` * - Continuous animations are tracked using their rebind id. Later calls using the same + * * ``` * rebind id will be totally ignored to prevent the continuous animation from restarting. * ``` diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/ColorSchemeTransition.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/ColorSchemeTransition.kt index 4827a16d229d..2b42604e7160 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/ColorSchemeTransition.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/ColorSchemeTransition.kt @@ -201,7 +201,9 @@ internal constructor( animatingColorTransitionFactory( loadDefaultColor(R.attr.textColorSecondary), ::textSecondaryFromScheme - ) { textSecondary -> mediaViewHolder.artistText.setTextColor(textSecondary) } + ) { textSecondary -> + mediaViewHolder.artistText.setTextColor(textSecondary) + } val textTertiary = animatingColorTransitionFactory( diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/IlluminationDrawable.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/IlluminationDrawable.kt index 9f86cd88788b..3669493f4e41 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/IlluminationDrawable.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/IlluminationDrawable.kt @@ -159,6 +159,7 @@ class IlluminationDrawable : Drawable() { /** * Cross fade background. + * * @see setTintList * @see backgroundColor */ diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt index 6cf051ad7668..67d3be4a3ad2 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt @@ -197,7 +197,6 @@ constructor( private val configListener = object : ConfigurationController.ConfigurationListener { - var lastOrientation = -1 override fun onDensityOrFontScaleChanged() { // System font changes should only happen when UMO is offscreen or a flicker may @@ -214,13 +213,6 @@ constructor( override fun onConfigChanged(newConfig: Configuration?) { if (newConfig == null) return isRtl = newConfig.layoutDirection == View.LAYOUT_DIRECTION_RTL - val newOrientation = newConfig.orientation - if (lastOrientation != newOrientation) { - // The players actually depend on the orientation possibly, so we have to - // recreate them (at least on large screen devices) - lastOrientation = newOrientation - updatePlayers(recreateMedia = true) - } } override fun onUiModeChanged() { @@ -853,10 +845,12 @@ constructor( * @param startLocation the start location of our state or -1 if this is directly set * @param endLocation the ending location of our state. * @param progress the progress of the transition between startLocation and endlocation. If + * * ``` * this is not a guided transformation, this will be 1.0f * @param immediately * ``` + * * should this state be applied immediately, canceling all animations? */ fun setCurrentState( @@ -1100,17 +1094,17 @@ constructor( * * @param eventId UI event id (e.g. 800 for SMARTSPACE_CARD_SEEN) * @param instanceId id to uniquely identify a card, e.g. each headphone generates a new - * instanceId + * instanceId * @param uid uid for the application that media comes from * @param surfaces list of display surfaces the media card is on (e.g. lockscreen, shade) when - * the event happened + * the event happened * @param interactedSubcardRank the rank for interacted media item for recommendation card, -1 - * for tapping on card but not on any media item, 0 for first media item, 1 for second, etc. + * for tapping on card but not on any media item, 0 for first media item, 1 for second, etc. * @param interactedSubcardCardinality how many media items were shown to the user when there is - * user interaction + * user interaction * @param rank the rank for media card in the media carousel, starting from 0 * @param receivedLatencyMillis latency in milliseconds for card received events. E.g. latency - * between headphone connection to sysUI displays media recommendation card + * between headphone connection to sysUI displays media recommendation card * @param isSwipeToDismiss whether is to log swipe-to-dismiss event */ fun logSmartspaceCardReported( @@ -1371,6 +1365,7 @@ internal object MediaPlayerData { /** * Removes media player given the key. + * * @param isDismissed determines whether the media player is removed from the carousel. */ fun removeMediaPlayer(key: String, isDismissed: Boolean = false) = diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java index 4ab93daef70c..4ddff530e658 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java @@ -31,12 +31,15 @@ import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.res.ColorStateList; +import android.graphics.Bitmap; import android.graphics.BlendMode; import android.graphics.Color; import android.graphics.ColorMatrix; import android.graphics.ColorMatrixColorFilter; +import android.graphics.Matrix; import android.graphics.Rect; import android.graphics.drawable.Animatable; +import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; @@ -62,7 +65,6 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.UiThread; -import androidx.appcompat.content.res.AppCompatResources; import androidx.constraintlayout.widget.ConstraintSet; import com.android.internal.annotations.VisibleForTesting; @@ -145,6 +147,12 @@ public class MediaControlPanel { private static final int SMARTSPACE_CARD_CLICK_EVENT = 760; protected static final int SMARTSPACE_CARD_DISMISS_EVENT = 761; + private static final float REC_MEDIA_COVER_SCALE_FACTOR = 1.25f; + private static final float MEDIA_SCRIM_START_ALPHA = 0.25f; + private static final float MEDIA_REC_SCRIM_START_ALPHA = 0.15f; + private static final float MEDIA_PLAYER_SCRIM_END_ALPHA = 0.9f; + private static final float MEDIA_REC_SCRIM_END_ALPHA = 1.0f; + private static final Intent SETTINGS_INTENT = new Intent(ACTION_MEDIA_CONTROLS_SETTINGS); // Buttons to show in small player when using semantic actions @@ -776,7 +784,7 @@ public class MediaControlPanel { WallpaperColors wallpaperColors = getWallpaperColor(artworkIcon); if (wallpaperColors != null) { mutableColorScheme = new ColorScheme(wallpaperColors, true, Style.CONTENT); - artwork = addGradientToIcon(artworkIcon, mutableColorScheme, width, height); + artwork = addGradientToPlayerAlbum(artworkIcon, mutableColorScheme, width, height); isArtworkBound = true; } else { // If there's no artwork, use colors from the app icon @@ -866,8 +874,9 @@ public class MediaControlPanel { Trace.beginAsyncSection(traceName, traceCookie); // Capture width & height from views in foreground for artwork scaling in background - int width = mRecommendationViewHolder.getMediaCoverContainers().get(0).getMeasuredWidth(); - int height = mRecommendationViewHolder.getMediaCoverContainers().get(0).getMeasuredHeight(); + int width = mContext.getResources().getDimensionPixelSize(R.dimen.qs_media_rec_album_width); + int height = mContext.getResources().getDimensionPixelSize( + R.dimen.qs_media_rec_album_height_expanded); mBackgroundExecutor.execute(() -> { // Album art @@ -877,7 +886,8 @@ public class MediaControlPanel { WallpaperColors wallpaperColors = getWallpaperColor(artworkIcon); if (wallpaperColors != null) { mutableColorScheme = new ColorScheme(wallpaperColors, true, Style.CONTENT); - artwork = addGradientToIcon(artworkIcon, mutableColorScheme, width, height); + artwork = addGradientToRecommendationAlbum(artworkIcon, mutableColorScheme, width, + height); } else { artwork = new ColorDrawable(Color.TRANSPARENT); } @@ -886,6 +896,11 @@ public class MediaControlPanel { // Bind the artwork drawable to media cover. ImageView mediaCover = mRecommendationViewHolder.getMediaCoverItems().get(itemIndex); + // Rescale media cover + Matrix coverMatrix = new Matrix(mediaCover.getImageMatrix()); + coverMatrix.postScale(REC_MEDIA_COVER_SCALE_FACTOR, REC_MEDIA_COVER_SCALE_FACTOR, + 0.5f * width, 0.5f * height); + mediaCover.setImageMatrix(coverMatrix); mediaCover.setImageDrawable(artwork); // Set up the app icon. @@ -907,40 +922,62 @@ public class MediaControlPanel { // This method should be called from a background thread. WallpaperColors.fromBitmap takes a // good amount of time. We do that work on the background executor to avoid stalling animations // on the UI Thread. - private WallpaperColors getWallpaperColor(Icon artworkIcon) { + @VisibleForTesting + protected WallpaperColors getWallpaperColor(Icon artworkIcon) { if (artworkIcon != null) { if (artworkIcon.getType() == Icon.TYPE_BITMAP || artworkIcon.getType() == Icon.TYPE_ADAPTIVE_BITMAP) { // Avoids extra processing if this is already a valid bitmap - return WallpaperColors - .fromBitmap(artworkIcon.getBitmap()); + Bitmap artworkBitmap = artworkIcon.getBitmap(); + if (artworkBitmap.isRecycled()) { + Log.d(TAG, "Cannot load wallpaper color from a recycled bitmap"); + return null; + } + return WallpaperColors.fromBitmap(artworkBitmap); } else { Drawable artworkDrawable = artworkIcon.loadDrawable(mContext); if (artworkDrawable != null) { - return WallpaperColors - .fromDrawable(artworkIcon.loadDrawable(mContext)); + return WallpaperColors.fromDrawable(artworkDrawable); } } } return null; } - private LayerDrawable addGradientToIcon( - Icon artworkIcon, - ColorScheme mutableColorScheme, - int width, - int height - ) { + @VisibleForTesting + protected LayerDrawable addGradientToPlayerAlbum(Icon artworkIcon, + ColorScheme mutableColorScheme, int width, int height) { Drawable albumArt = getScaledBackground(artworkIcon, width, height); - GradientDrawable gradient = (GradientDrawable) AppCompatResources - .getDrawable(mContext, R.drawable.qs_media_scrim); + GradientDrawable gradient = (GradientDrawable) mContext.getDrawable( + R.drawable.qs_media_scrim).mutate(); + return setupGradientColorOnDrawable(albumArt, gradient, mutableColorScheme, + MEDIA_SCRIM_START_ALPHA, MEDIA_PLAYER_SCRIM_END_ALPHA); + } + + @VisibleForTesting + protected LayerDrawable addGradientToRecommendationAlbum(Icon artworkIcon, + ColorScheme mutableColorScheme, int width, int height) { + // First try scaling rec card using bitmap drawable. + // If returns null, set drawable bounds. + Drawable albumArt = getScaledRecommendationCover(artworkIcon, width, height); + if (albumArt == null) { + albumArt = getScaledBackground(artworkIcon, width, height); + } + GradientDrawable gradient = (GradientDrawable) mContext.getDrawable( + R.drawable.qs_media_rec_scrim).mutate(); + return setupGradientColorOnDrawable(albumArt, gradient, mutableColorScheme, + MEDIA_REC_SCRIM_START_ALPHA, MEDIA_REC_SCRIM_END_ALPHA); + } + + private LayerDrawable setupGradientColorOnDrawable(Drawable albumArt, GradientDrawable gradient, + ColorScheme mutableColorScheme, float startAlpha, float endAlpha) { gradient.setColors(new int[] { ColorUtilKt.getColorWithAlpha( MediaColorSchemesKt.backgroundStartFromScheme(mutableColorScheme), - 0.25f), + startAlpha), ColorUtilKt.getColorWithAlpha( MediaColorSchemesKt.backgroundEndFromScheme(mutableColorScheme), - 0.9f), + endAlpha), }); return new LayerDrawable(new Drawable[] { albumArt, gradient }); } @@ -1586,6 +1623,29 @@ public class MediaControlPanel { } /** + * Scale artwork to fill the background of media covers in recommendation card. + */ + @UiThread + private Drawable getScaledRecommendationCover(Icon artworkIcon, int width, int height) { + if (width == 0 || height == 0) { + return null; + } + if (artworkIcon != null) { + Bitmap bitmap; + if (artworkIcon.getType() == Icon.TYPE_BITMAP + || artworkIcon.getType() == Icon.TYPE_ADAPTIVE_BITMAP) { + Bitmap artworkBitmap = artworkIcon.getBitmap(); + if (artworkBitmap != null) { + bitmap = Bitmap.createScaledBitmap(artworkIcon.getBitmap(), width, + height, false); + return new BitmapDrawable(mContext.getResources(), bitmap); + } + } + } + return null; + } + + /** * Get the current media controller * * @return the controller diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt index 66f12d6242b0..7fc7bdb872c9 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt @@ -28,7 +28,6 @@ import android.net.Uri import android.os.Handler import android.os.UserHandle import android.provider.Settings -import android.util.Log import android.util.MathUtils import android.view.View import android.view.ViewGroup @@ -418,8 +417,8 @@ constructor( * Calculate the alpha of the view when given a cross-fade progress. * * @param crossFadeProgress The current cross fade progress. 0.5f means it's just switching - * between the start and the end location and the content is fully faded, while 0.75f means that - * we're halfway faded in again in the target state. + * between the start and the end location and the content is fully faded, while 0.75f means + * that we're halfway faded in again in the target state. */ private fun calculateAlphaFromCrossFade(crossFadeProgress: Float): Float { if (crossFadeProgress <= 0.5f) { @@ -629,6 +628,7 @@ constructor( * * @param forceNoAnimation optional parameter telling the system not to animate * @param forceStateUpdate optional parameter telling the system to update transition state + * * ``` * even if location did not change * ``` @@ -944,7 +944,7 @@ constructor( /** * @return the current transformation progress if we're in a guided transformation and -1 - * otherwise + * otherwise */ private fun getTransformationProgress(): Float { if (skipQqsOnExpansion) { @@ -1055,17 +1055,6 @@ constructor( // This will either do a full layout pass and remeasure, or it will bypass // that and directly set the mediaFrame's bounds within the premeasured host. targetHost.addView(mediaFrame) - - if (mediaFrame.childCount > 0) { - val child = mediaFrame.getChildAt(0) - if (mediaFrame.height < child.height) { - Log.wtf( - TAG, - "mediaFrame height is too small for child: " + - "${mediaFrame.height} vs ${child.height}" - ) - } - } } if (isCrossFadeAnimatorRunning) { // When cross-fading with an animation, we only notify the media carousel of the diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHost.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHost.kt index 455b7de3dc0c..be570b4a1119 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHost.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHost.kt @@ -126,6 +126,7 @@ constructor( * remeasurings later on. * * @param location the location this host name has. Used to identify the host during + * * ``` * transitions. * ``` diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewController.kt index b9b0459ad615..b4724ddebb9a 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewController.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewController.kt @@ -154,9 +154,11 @@ constructor( return transitionLayout?.translationY ?: 0.0f } - /** A callback for RTL config changes */ + /** A callback for config changes */ private val configurationListener = object : ConfigurationController.ConfigurationListener { + var lastOrientation = -1 + override fun onConfigChanged(newConfig: Configuration?) { // Because the TransitionLayout is not always attached (and calculates/caches layout // results regardless of attach state), we have to force the layoutDirection of the @@ -169,6 +171,13 @@ constructor( transitionLayout?.layoutDirection = layoutDirection refreshState() } + val newOrientation = newConfig.orientation + if (lastOrientation != newOrientation) { + // Layout dimensions are possibly changing, so we need to update them. (at + // least on large screen devices) + lastOrientation = newOrientation + loadLayoutForType(type) + } } } } @@ -195,13 +204,14 @@ constructor( * The expanded constraint set used to render a expanded player. If it is modified, make sure to * call [refreshState] */ - val collapsedLayout = ConstraintSet() - + var collapsedLayout = ConstraintSet() + @VisibleForTesting set /** * The expanded constraint set used to render a collapsed player. If it is modified, make sure * to call [refreshState] */ - val expandedLayout = ConstraintSet() + var expandedLayout = ConstraintSet() + @VisibleForTesting set /** Whether the guts are visible for the associated player. */ var isGutsVisible = false @@ -348,14 +358,17 @@ constructor( * bottom of UMO reach the bottom of this group It will change to alpha 1.0 when the visible * bottom of UMO reach the top of the group below e.g.Album title, artist title and play-pause * button will change alpha together. + * * ``` * And their alpha becomes 1.0 when the visible bottom of UMO reach the top of controls, * including progress bar, next button, previous button * ``` + * * widgetGroupIds: a group of widgets have same state during UMO is squished, * ``` * e.g. Album title, artist title and play-pause button * ``` + * * groupEndPosition: the height of UMO, when the height reaches this value, * ``` * widgets in this group should have 1.0 as alpha @@ -363,6 +376,7 @@ constructor( * visible when the height of UMO reaches the top of controls group * (progress bar, previous button and next button) * ``` + * * squishedViewState: hold the widgetState of each widget, which will be modified * squishFraction: the squishFraction of UMO */ @@ -479,7 +493,7 @@ constructor( */ fun attach(transitionLayout: TransitionLayout, type: TYPE) = traceSection("MediaViewController#attach") { - updateMediaViewControllerType(type) + loadLayoutForType(type) logger.logMediaLocation("attach $type", currentStartLocation, currentEndLocation) this.transitionLayout = transitionLayout layoutController.attach(transitionLayout) @@ -637,7 +651,7 @@ constructor( return result } - private fun updateMediaViewControllerType(type: TYPE) { + private fun loadLayoutForType(type: TYPE) { this.type = type // These XML resources contain ConstraintSets that will apply to this player type's layout @@ -665,7 +679,7 @@ constructor( * * @param location Target * @param locationWhenHidden Location that will be used when the target is not - * [MediaHost.visible] + * [MediaHost.visible] * @return State require for executing a transition, and also the respective [MediaHost]. */ private fun obtainViewStateForLocation(@MediaLocation location: Int): TransitionViewState? { diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputSwitcherDialogUI.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputSwitcherDialogUI.java index e35575bfc184..b5b1f0ffe23d 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputSwitcherDialogUI.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputSwitcherDialogUI.java @@ -23,8 +23,6 @@ import android.util.Log; import com.android.systemui.CoreStartable; import com.android.systemui.dagger.SysUISingleton; -import com.android.systemui.flags.FeatureFlags; -import com.android.systemui.flags.Flags; import com.android.systemui.statusbar.CommandQueue; import javax.inject.Inject; @@ -37,26 +35,19 @@ public class MediaOutputSwitcherDialogUI implements CoreStartable, CommandQueue. private final CommandQueue mCommandQueue; private final MediaOutputDialogFactory mMediaOutputDialogFactory; - private final FeatureFlags mFeatureFlags; @Inject public MediaOutputSwitcherDialogUI( Context context, CommandQueue commandQueue, - MediaOutputDialogFactory mediaOutputDialogFactory, - FeatureFlags featureFlags) { + MediaOutputDialogFactory mediaOutputDialogFactory) { mCommandQueue = commandQueue; mMediaOutputDialogFactory = mediaOutputDialogFactory; - mFeatureFlags = featureFlags; } @Override public void start() { - if (mFeatureFlags.isEnabled(Flags.OUTPUT_SWITCHER_SHOW_API_ENABLED)) { - mCommandQueue.addCallback(this); - } else { - Log.w(TAG, "Show media output switcher is not enabled."); - } + mCommandQueue.addCallback(this); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttUtils.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttUtils.kt index 720c44a0904b..ee93c3788243 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttUtils.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttUtils.kt @@ -43,7 +43,7 @@ class MediaTttUtils { * * @param appPackageName the package name of the app playing the media. * @param onPackageNotFoundException a function run if a - * [PackageManager.NameNotFoundException] occurs. + * [PackageManager.NameNotFoundException] occurs. * @param isReceiver indicates whether the icon is displayed in a receiver view. */ fun getIconInfoFromPackageName( diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskListProvider.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskListProvider.kt index 7a77c476aa11..01398cf81314 100644 --- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskListProvider.kt +++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskListProvider.kt @@ -70,6 +70,8 @@ constructor( RECENT_IGNORE_UNAVAILABLE, userTracker.userId, backgroundExecutor - ) { tasks -> continuation.resume(tasks) } + ) { tasks -> + continuation.resume(tasks) + } } } diff --git a/packages/SystemUI/src/com/android/systemui/notetask/shortcut/CreateNoteTaskShortcutActivity.kt b/packages/SystemUI/src/com/android/systemui/notetask/shortcut/CreateNoteTaskShortcutActivity.kt index 6ab0da6fe3b3..75a0c6836c45 100644 --- a/packages/SystemUI/src/com/android/systemui/notetask/shortcut/CreateNoteTaskShortcutActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/notetask/shortcut/CreateNoteTaskShortcutActivity.kt @@ -33,8 +33,8 @@ import javax.inject.Inject * launched, creating a new shortcut for [CreateNoteTaskShortcutActivity], and will finish. * * @see <a - * href="https://developer.android.com/develop/ui/views/launch/shortcuts/creating-shortcuts#custom-pinned">Creating - * a custom shortcut activity</a> + * href="https://developer.android.com/develop/ui/views/launch/shortcuts/creating-shortcuts#custom-pinned">Creating + * a custom shortcut activity</a> */ internal class CreateNoteTaskShortcutActivity @Inject constructor() : ComponentActivity() { diff --git a/packages/SystemUI/src/com/android/systemui/qrcodescanner/dagger/QRCodeScannerModule.kt b/packages/SystemUI/src/com/android/systemui/qrcodescanner/dagger/QRCodeScannerModule.kt index 62c99da5ed81..fb09c55dc544 100644 --- a/packages/SystemUI/src/com/android/systemui/qrcodescanner/dagger/QRCodeScannerModule.kt +++ b/packages/SystemUI/src/com/android/systemui/qrcodescanner/dagger/QRCodeScannerModule.kt @@ -26,8 +26,7 @@ import dagger.multibindings.StringKey @Module interface QRCodeScannerModule { - /** - */ + /** */ @Binds @IntoMap @StringKey(QRCodeScannerTile.TILE_SPEC) diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java index 7c2536dac56e..d4854e1a7daf 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java @@ -328,7 +328,7 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener if (listening) { updateDefaultTileAndIcon(); refreshState(); - if (!mServiceManager.isActiveTile()) { + if (!mServiceManager.isActiveTile() || !isTileReady()) { mServiceManager.setBindRequested(true); mService.onStartListening(); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java index e86bd7a30490..9f93e4926532 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java @@ -76,7 +76,8 @@ public class TileServiceManager { this(tileServices, handler, userTracker, new TileLifecycleManager(handler, tileServices.getContext(), tileServices, new PackageManagerAdapter(tileServices.getContext()), broadcastDispatcher, - new Intent().setComponent(component), userTracker.getUserHandle())); + new Intent(TileService.ACTION_QS_TILE).setComponent(component), + userTracker.getUserHandle())); } @VisibleForTesting diff --git a/packages/SystemUI/src/com/android/systemui/qs/footer/domain/interactor/FooterActionsInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/footer/domain/interactor/FooterActionsInteractor.kt index 03bb7a0f45da..8387c1dd60a5 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/footer/domain/interactor/FooterActionsInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/footer/domain/interactor/FooterActionsInteractor.kt @@ -71,8 +71,8 @@ interface FooterActionsInteractor { /** * Show the device monitoring dialog, expanded from [expandable] if it's not null. * - * Important: [quickSettingsContext] *must* be the [Context] associated to the [Quick Settings - * fragment][com.android.systemui.qs.QSFragment]. + * Important: [quickSettingsContext] *must* be the [Context] associated to the + * [Quick Settings fragment][com.android.systemui.qs.QSFragment]. */ fun showDeviceMonitoringDialog(quickSettingsContext: Context, expandable: Expandable?) diff --git a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt index fbf32b3b99ea..f170ac1d9d4e 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt @@ -196,9 +196,9 @@ class FooterActionsViewModel( * Observe the device monitoring dialog requests and show the dialog accordingly. This function * will suspend indefinitely and will need to be cancelled to stop observing. * - * Important: [quickSettingsContext] must be the [Context] associated to the [Quick Settings - * fragment][com.android.systemui.qs.QSFragment], and the call to this function must be - * cancelled when that fragment is destroyed. + * Important: [quickSettingsContext] must be the [Context] associated to the + * [Quick Settings fragment][com.android.systemui.qs.QSFragment], and the call to this function + * must be cancelled when that fragment is destroyed. */ suspend fun observeDeviceMonitoringDialogRequests(quickSettingsContext: Context) { footerActionsInteractor.deviceMonitoringDialogRequests.collect { diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java index 25ff308b46bb..019ca52107dd 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java @@ -631,7 +631,9 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis final NavigationBarView navBarView = mNavBarControllerLazy.get().getNavigationBarView(mContext.getDisplayId()); final NotificationPanelViewController panelController = - mCentralSurfacesOptionalLazy.get().get().getNotificationPanelViewController(); + mCentralSurfacesOptionalLazy.get() + .map(CentralSurfaces::getNotificationPanelViewController) + .orElse(null); if (SysUiState.DEBUG) { Log.d(TAG_OPS, "Updating sysui state flags: navBarFragment=" + navBarFragment + " navBarView=" + navBarView + " panelController=" + panelController); diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt index dd21be971b36..30509e23d186 100644 --- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt +++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt @@ -124,8 +124,9 @@ class ScreenRecordPermissionDialog( /** * Starts screen capture after some countdown + * * @param captureTarget target to capture (could be e.g. a task) or null to record the whole - * screen + * screen */ private fun requestScreenCapture(captureTarget: MediaProjectionCaptureTarget?) { val userContext = userContextProvider.userContext diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentCreator.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentCreator.kt index 310baafbae1a..a8f99bef2423 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentCreator.kt +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentCreator.kt @@ -70,7 +70,7 @@ object ActionIntentCreator { /** * @return an ACTION_EDIT intent for the given URI, directed to config_screenshotEditor if - * available. + * available. */ fun createEditIntent(uri: Uri, context: Context): Intent { val editIntent = Intent(Intent.ACTION_EDIT) diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/DraggableConstraintLayout.java b/packages/SystemUI/src/com/android/systemui/screenshot/DraggableConstraintLayout.java index ead3b7b1de53..0b4b7c691cfd 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/DraggableConstraintLayout.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/DraggableConstraintLayout.java @@ -45,6 +45,7 @@ public class DraggableConstraintLayout extends ConstraintLayout implements ViewTreeObserver.OnComputeInternalInsetsListener { private static final float VELOCITY_DP_PER_MS = 1; + private static final int MAXIMUM_DISMISS_DISTANCE_DP = 400; private final SwipeDismissHandler mSwipeDismissHandler; private final GestureDetector mSwipeDetector; @@ -347,14 +348,18 @@ public class DraggableConstraintLayout extends ConstraintLayout } else { finalX = -1 * getBackgroundRight(); } - float distance = Math.abs(finalX - startX); + float distance = Math.min(Math.abs(finalX - startX), + FloatingWindowUtil.dpToPx(mDisplayMetrics, MAXIMUM_DISMISS_DISTANCE_DP)); + // ensure that view dismisses in the right direction (right in LTR, left in RTL) + float distanceVector = Math.copySign(distance, finalX - startX); anim.addUpdateListener(animation -> { - float translation = MathUtils.lerp(startX, finalX, animation.getAnimatedFraction()); + float translation = MathUtils.lerp( + startX, startX + distanceVector, animation.getAnimatedFraction()); mView.setTranslationX(translation); mView.setAlpha(1 - animation.getAnimatedFraction()); }); - anim.setDuration((long) (distance / Math.abs(velocity))); + anim.setDuration((long) (Math.abs(distance / velocity))); return anim; } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java b/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java index c8c133774766..7cfe2327f992 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java @@ -57,7 +57,8 @@ import java.util.concurrent.Executor; import javax.inject.Inject; -class ImageExporter { +/** A class to help with exporting screenshot to storage. */ +public class ImageExporter { private static final String TAG = LogConfig.logTag(ImageExporter.class); static final Duration PENDING_ENTRY_TTL = Duration.ofHours(24); @@ -90,7 +91,7 @@ class ImageExporter { private final FeatureFlags mFlags; @Inject - ImageExporter(ContentResolver resolver, FeatureFlags flags) { + public ImageExporter(ContentResolver resolver, FeatureFlags flags) { mResolver = resolver; mFlags = flags; } @@ -148,7 +149,7 @@ class ImageExporter { * * @return a listenable future result */ - ListenableFuture<Result> export(Executor executor, UUID requestId, Bitmap bitmap, + public ListenableFuture<Result> export(Executor executor, UUID requestId, Bitmap bitmap, UserHandle owner) { return export(executor, requestId, bitmap, ZonedDateTime.now(), owner); } @@ -181,13 +182,14 @@ class ImageExporter { ); } - static class Result { - Uri uri; - UUID requestId; - String fileName; - long timestamp; - CompressFormat format; - boolean published; + /** The result returned by the task exporting screenshots to storage. */ + public static class Result { + public Uri uri; + public UUID requestId; + public String fileName; + public long timestamp; + public CompressFormat format; + public boolean published; @Override public String toString() { diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java index fc94aed5336a..7a62bae5b5ae 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java @@ -93,13 +93,7 @@ public enum ScreenshotEvent implements UiEventLogger.UiEventEnum { @UiEvent(doc = "User has discarded the result of a long screenshot") SCREENSHOT_LONG_SCREENSHOT_EXIT(911), @UiEvent(doc = "A screenshot has been taken and saved to work profile") - SCREENSHOT_SAVED_TO_WORK_PROFILE(1240), - @UiEvent(doc = "Notes application triggered the screenshot for notes") - SCREENSHOT_FOR_NOTE_TRIGGERED(1308), - @UiEvent(doc = "User accepted the screenshot to be sent to the notes app") - SCREENSHOT_FOR_NOTE_ACCEPTED(1309), - @UiEvent(doc = "User cancelled the screenshot for notes app flow") - SCREENSHOT_FOR_NOTE_CANCELLED(1310); + SCREENSHOT_SAVED_TO_WORK_PROFILE(1240); private final int mId; diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/WorkProfileMessageController.kt b/packages/SystemUI/src/com/android/systemui/screenshot/WorkProfileMessageController.kt index 1b728b8aa9cc..236213cb023f 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/WorkProfileMessageController.kt +++ b/packages/SystemUI/src/com/android/systemui/screenshot/WorkProfileMessageController.kt @@ -44,7 +44,7 @@ constructor( /** * @return a populated WorkProfileFirstRunData object if a work profile first run message should - * be shown + * be shown */ fun onScreenshotTaken(userHandle: UserHandle?): WorkProfileFirstRunData? { if (userHandle == null) return null diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java index e53eea90ad33..8323d1e6bae3 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java @@ -23,6 +23,7 @@ import static android.view.View.VISIBLE; import static androidx.constraintlayout.widget.ConstraintSet.END; import static androidx.constraintlayout.widget.ConstraintSet.PARENT_ID; +import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION; import static com.android.keyguard.KeyguardClockSwitch.LARGE; import static com.android.keyguard.KeyguardClockSwitch.SMALL; import static com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE; @@ -71,6 +72,7 @@ import android.os.VibrationEffect; import android.provider.Settings; import android.transition.ChangeBounds; import android.transition.Transition; +import android.transition.TransitionListenerAdapter; import android.transition.TransitionManager; import android.transition.TransitionSet; import android.transition.TransitionValues; @@ -98,6 +100,7 @@ import android.widget.FrameLayout; import androidx.constraintlayout.widget.ConstraintSet; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.jank.InteractionJankMonitor; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.policy.SystemBarUtils; @@ -353,6 +356,7 @@ public final class NotificationPanelViewController implements Dumpable { private final NotificationGutsManager mGutsManager; private final AlternateBouncerInteractor mAlternateBouncerInteractor; private final QuickSettingsController mQsController; + private final InteractionJankMonitor mInteractionJankMonitor; private long mDownTime; private boolean mTouchSlopExceededBeforeDown; @@ -642,6 +646,19 @@ public final class NotificationPanelViewController implements Dumpable { step.getTransitionState() == TransitionState.RUNNING; }; + private final TransitionListenerAdapter mKeyguardStatusAlignmentTransitionListener = + new TransitionListenerAdapter() { + @Override + public void onTransitionCancel(Transition transition) { + mInteractionJankMonitor.cancel(CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION); + } + + @Override + public void onTransitionEnd(Transition transition) { + mInteractionJankMonitor.end(CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION); + } + }; + @Inject public NotificationPanelViewController(NotificationPanelView view, @Main Handler handler, @@ -706,6 +723,7 @@ public final class NotificationPanelViewController implements Dumpable { NotificationStackSizeCalculator notificationStackSizeCalculator, UnlockedScreenOffAnimationController unlockedScreenOffAnimationController, ShadeTransitionController shadeTransitionController, + InteractionJankMonitor interactionJankMonitor, SystemClock systemClock, KeyguardBottomAreaViewModel keyguardBottomAreaViewModel, KeyguardBottomAreaInteractor keyguardBottomAreaInteractor, @@ -720,6 +738,7 @@ public final class NotificationPanelViewController implements Dumpable { DumpManager dumpManager, KeyguardLongPressViewModel keyguardLongPressViewModel, KeyguardInteractor keyguardInteractor) { + mInteractionJankMonitor = interactionJankMonitor; keyguardStateController.addCallback(new KeyguardStateController.Callback() { @Override public void onKeyguardFadingAwayChanged() { @@ -1540,6 +1559,7 @@ public final class NotificationPanelViewController implements Dumpable { int statusConstraint = shouldBeCentered ? PARENT_ID : R.id.qs_edge_guideline; constraintSet.connect(R.id.keyguard_status_view, END, statusConstraint, END); if (animate) { + mInteractionJankMonitor.begin(mView, CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION); ChangeBounds transition = new ChangeBounds(); if (mSplitShadeEnabled) { // Excluding media from the transition on split-shade, as it doesn't transition @@ -1563,6 +1583,7 @@ public final class NotificationPanelViewController implements Dumpable { // The clock container can sometimes be null. If it is, just fall back to the // old animation rather than setting up the custom animations. if (clockContainerView == null || clockContainerView.getChildCount() == 0) { + transition.addListener(mKeyguardStatusAlignmentTransitionListener); TransitionManager.beginDelayedTransition( mNotificationContainerParent, transition); } else { @@ -1581,10 +1602,11 @@ public final class NotificationPanelViewController implements Dumpable { adapter.setDuration(KEYGUARD_STATUS_VIEW_CUSTOM_CLOCK_MOVE_DURATION); adapter.addTarget(clockView); set.addTransition(adapter); - + set.addListener(mKeyguardStatusAlignmentTransitionListener); TransitionManager.beginDelayedTransition(mNotificationContainerParent, set); } } else { + transition.addListener(mKeyguardStatusAlignmentTransitionListener); TransitionManager.beginDelayedTransition( mNotificationContainerParent, transition); } @@ -4628,8 +4650,13 @@ public final class NotificationPanelViewController implements Dumpable { gesture possible. */ int pointerIndex = event.findPointerIndex(mTrackingPointer); if (pointerIndex < 0) { - pointerIndex = 0; - mTrackingPointer = event.getPointerId(pointerIndex); + if (mTrackingPointer < 0) { + pointerIndex = 0; + mTrackingPointer = event.getPointerId(pointerIndex); + } else { + mShadeLog.logMotionEvent(event, "Skipping intercept of multitouch pointer"); + return false; + } } final float x = event.getX(pointerIndex); final float y = event.getY(pointerIndex); diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java index 87350b465895..c130b3913b64 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java @@ -45,6 +45,7 @@ import com.android.systemui.keyguard.shared.model.TransitionState; import com.android.systemui.keyguard.shared.model.TransitionStep; import com.android.systemui.keyguard.ui.binder.KeyguardBouncerViewBinder; import com.android.systemui.keyguard.ui.viewmodel.KeyguardBouncerViewModel; +import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel; import com.android.systemui.statusbar.DragDownHelper; import com.android.systemui.statusbar.LockscreenShadeTransitionController; import com.android.systemui.statusbar.NotificationInsetsController; @@ -133,7 +134,8 @@ public class NotificationShadeWindowViewController { KeyguardBouncerViewModel keyguardBouncerViewModel, KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory, AlternateBouncerInteractor alternateBouncerInteractor, - KeyguardTransitionInteractor keyguardTransitionInteractor + KeyguardTransitionInteractor keyguardTransitionInteractor, + PrimaryBouncerToGoneTransitionViewModel primaryBouncerToGoneTransitionViewModel ) { mLockscreenShadeTransitionController = transitionController; mFalsingCollector = falsingCollector; @@ -160,6 +162,7 @@ public class NotificationShadeWindowViewController { KeyguardBouncerViewBinder.bind( mView.findViewById(R.id.keyguard_bouncer_container), keyguardBouncerViewModel, + primaryBouncerToGoneTransitionViewModel, keyguardBouncerComponentFactory); collectFlow(mView, keyguardTransitionInteractor.getLockscreenToDreamingTransition(), diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt index a1767cc5888d..f4b1cc5f71be 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt @@ -107,7 +107,7 @@ class ShadeExpansionStateManager @Inject constructor() : ShadeStateEvents { * * @param fraction the fraction from the expansion in [0, 1] * @param expanded whether the panel is currently expanded; this is independent from the - * fraction as the panel also might be expanded if the fraction is 0. + * fraction as the panel also might be expanded if the fraction is 0. * @param tracking whether we're currently tracking the user's gesture. */ fun onPanelExpansionChanged( diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt index 37773e952875..b79f32a6eae1 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt @@ -70,9 +70,9 @@ import javax.inject.Named * * [header] is a [MotionLayout] that has two transitions: * * [HEADER_TRANSITION_ID]: [QQS_HEADER_CONSTRAINT] <-> [QS_HEADER_CONSTRAINT] for portrait - * handheld device configuration. + * handheld device configuration. * * [LARGE_SCREEN_HEADER_TRANSITION_ID]: [LARGE_SCREEN_HEADER_CONSTRAINT] for all other - * configurations + * configurations */ @CentralSurfacesScope class ShadeHeaderController diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionController.kt index 62c225ba0b4e..df8c6abfff97 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionController.kt @@ -148,7 +148,8 @@ constructor( qsDragFraction: $qsTransitionFraction qsSquishFraction: $qsSquishTransitionFraction isTransitioningToFullShade: $isTransitioningToFullShade - """.trimIndent() + """ + .trimIndent() ) } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt index f0d064b42d9c..9a9503c8cd9c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt @@ -572,8 +572,7 @@ class LockscreenShadeTransitionController @Inject constructor( entry.setGroupExpansionChanging(true) userId = entry.sbn.userId } - var fullShadeNeedsBouncer = (!lockScreenUserManager.userAllowsPrivateNotificationsInPublic( - lockScreenUserManager.getCurrentUserId()) || + var fullShadeNeedsBouncer = ( !lockScreenUserManager.shouldShowLockscreenNotifications() || falsingCollector.shouldEnforceBouncer()) if (keyguardBypassController.bypassEnabled) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java index c35c5c522798..77550038c94a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java @@ -93,6 +93,16 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi @IntDef({STATE_ICON, STATE_DOT, STATE_HIDDEN}) public @interface VisibleState { } + /** Returns a human-readable string of {@link VisibleState}. */ + public static String getVisibleStateString(@VisibleState int state) { + switch(state) { + case STATE_ICON: return "ICON"; + case STATE_DOT: return "DOT"; + case STATE_HIDDEN: return "HIDDEN"; + default: return "UNKNOWN"; + } + } + private static final String TAG = "StatusBarIconView"; private static final Property<StatusBarIconView, Float> ICON_APPEAR_AMOUNT = new FloatProperty<StatusBarIconView>("iconAppearAmount") { @@ -561,7 +571,8 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi @Override public String toString() { return "StatusBarIconView(" - + "slot='" + mSlot + " alpha=" + getAlpha() + " icon=" + mIcon + + "slot='" + mSlot + "' alpha=" + getAlpha() + " icon=" + mIcon + + " visibleState=" + getVisibleStateString(getVisibleState()) + " iconColor=#" + Integer.toHexString(mIconColor) + " notification=" + mNotification + ')'; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/ui/MobileContextProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/ui/MobileContextProvider.kt index 42b874fd7156..7297ae689224 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/ui/MobileContextProvider.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/ui/MobileContextProvider.kt @@ -74,7 +74,7 @@ constructor( /** * @return a context with the MCC/MNC [Configuration] values corresponding to this - * subscriptionId + * subscriptionId */ fun getMobileContextForSub(subId: Int, context: Context): Context { if (demoModeController.isInDemoMode) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerLegacyImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerLegacyImpl.kt index 64b7ac9ee0a1..5fa83ef5d454 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerLegacyImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerLegacyImpl.kt @@ -39,6 +39,7 @@ import javax.inject.Inject * - Simple prioritization: Privacy > Battery > connectivity (encoded in [StatusEvent]) * - Only schedules a single event, and throws away lowest priority events * ``` + * * There are 4 basic stages of animation at play here: * ``` * 1. System chrome animation OUT @@ -46,6 +47,7 @@ import javax.inject.Inject * 3. Chip animation OUT; potentially into a dot * 4. System chrome animation IN * ``` + * * Thus we can keep all animations synchronized with two separate ValueAnimators, one for system * chrome and the other for the chip. These can animate from 0,1 and listeners can parameterize * their respective views based on the progress of the animator. Interpolation differences TBD @@ -168,7 +170,7 @@ constructor( * 3. Update the scheduler state so that clients know where we are * 4. Maybe: provide scaffolding such as: dot location, margins, etc * 5. Maybe: define a maximum animation length and enforce it. Probably only doable if we - * collect all of the animators and run them together. + * collect all of the animators and run them together. */ private fun runChipAnimation() { statusBarWindowController.setForceStatusBarVisible(true) 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 29510d00a8d4..b0ad6a1ffbd8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt @@ -333,9 +333,9 @@ constructor( } val ssView = plugin.getView(parent) + configPlugin?.let { ssView.registerConfigProvider(it) } ssView.setUiSurface(BcSmartspaceDataPlugin.UI_SURFACE_LOCK_SCREEN_AOD) ssView.registerDataProvider(plugin) - configPlugin?.let { ssView.registerConfigProvider(it) } ssView.setIntentStarter(object : BcSmartspaceDataPlugin.IntentStarter { override fun startIntent(view: View, intent: Intent, showOnLockscreen: Boolean) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt index 7e53d5431353..8874f59d6c17 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt @@ -18,6 +18,7 @@ package com.android.systemui.statusbar.notification import android.animation.ObjectAnimator import android.util.FloatProperty +import androidx.annotation.VisibleForTesting import com.android.systemui.Dumpable import com.android.systemui.animation.Interpolators import com.android.systemui.dagger.SysUISingleton @@ -302,29 +303,29 @@ class NotificationWakeUpCoordinator @Inject constructor( // the doze amount to 0f (not dozing) so that the notifications are no longer hidden. // See: UnlockedScreenOffAnimationController.onFinishedWakingUp() setDozeAmount(0f, 0f, source = "Override: Shade->Shade (lock cancelled by unlock)") + this.state = newState + return } if (overrideDozeAmountIfAnimatingScreenOff(mLinearDozeAmount)) { + this.state = newState return } if (overrideDozeAmountIfBypass()) { + this.state = newState return } maybeClearDozeAmountOverrideHidingNotifs() - if (bypassController.bypassEnabled && - newState == StatusBarState.KEYGUARD && state == StatusBarState.SHADE_LOCKED && - (!statusBarStateController.isDozing || shouldAnimateVisibility())) { - // We're leaving shade locked. Let's animate the notifications away - setNotificationsVisible(visible = true, increaseSpeed = false, animate = false) - setNotificationsVisible(visible = false, increaseSpeed = false, animate = true) - } - this.state = newState } + @VisibleForTesting + val statusBarState: Int + get() = state + override fun onPanelExpansionChanged(event: ShadeExpansionChangeEvent) { val collapsedEnough = event.fraction <= 0.9f if (collapsedEnough != this.collapsedEnoughToHide) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/Roundable.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/Roundable.kt index a35617c88caf..6deef2e11828 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/Roundable.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/Roundable.kt @@ -315,6 +315,7 @@ interface Roundable { /** * State object for a `Roundable` class. + * * @param targetView Will handle the [AnimatableProperty] * @param roundable Target of the radius animation * @param maxRadius Max corner radius in pixels @@ -436,7 +437,6 @@ interface SourceType { * This is the most convenient way to define a new [SourceType]. * * For example: - * * ```kotlin * private val SECTION = SourceType.from("Section") * ``` 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 64c1a595483e..bbabde3f444e 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 @@ -191,7 +191,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView private int mMaxSmallHeightBeforeS; private int mMaxSmallHeight; private int mMaxSmallHeightLarge; - private int mMaxSmallHeightMedia; private int mMaxExpandedHeight; private int mIncreasedPaddingBetweenElements; private int mNotificationLaunchHeight; @@ -1771,8 +1770,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView R.dimen.notification_min_height); mMaxSmallHeightLarge = NotificationUtils.getFontScaledHeight(mContext, R.dimen.notification_min_height_increased); - mMaxSmallHeightMedia = NotificationUtils.getFontScaledHeight(mContext, - R.dimen.notification_min_height_media); mMaxExpandedHeight = NotificationUtils.getFontScaledHeight(mContext, R.dimen.notification_max_height); mMaxHeadsUpHeightBeforeN = NotificationUtils.getFontScaledHeight(mContext, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java index 39e4000c5d05..4522e41daf91 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java @@ -443,6 +443,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder CancellationSignal cancellationSignal = new CancellationSignal(); cancellationSignal.setOnCancelListener( () -> runningInflations.values().forEach(CancellationSignal::cancel)); + return cancellationSignal; } @@ -783,6 +784,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder public static class AsyncInflationTask extends AsyncTask<Void, Void, InflationProgress> implements InflationCallback, InflationTask { + private static final long IMG_PRELOAD_TIMEOUT_MS = 1000L; private final NotificationEntry mEntry; private final Context mContext; private final boolean mInflateSynchronously; @@ -876,7 +878,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder recoveredBuilder, mIsLowPriority, mUsesIncreasedHeight, mUsesIncreasedHeadsUpHeight, packageContext); InflatedSmartReplyState previousSmartReplyState = mRow.getExistingSmartReplyState(); - return inflateSmartReplyViews( + InflationProgress result = inflateSmartReplyViews( inflationProgress, mReInflateFlags, mEntry, @@ -884,6 +886,11 @@ public class NotificationContentInflater implements NotificationRowContentBinder packageContext, previousSmartReplyState, mSmartRepliesInflater); + + // wait for image resolver to finish preloading + mRow.getImageResolver().waitForPreloadedImages(IMG_PRELOAD_TIMEOUT_MS); + + return result; } catch (Exception e) { mError = e; return null; @@ -918,6 +925,9 @@ public class NotificationContentInflater implements NotificationRowContentBinder mCallback.handleInflationException(mRow.getEntry(), new InflationException("Couldn't inflate contentViews" + e)); } + + // Cancel any image loading tasks, not useful any more + mRow.getImageResolver().cancelRunningTasks(); } @Override @@ -944,6 +954,9 @@ public class NotificationContentInflater implements NotificationRowContentBinder // Notify the resolver that the inflation task has finished, // try to purge unnecessary cached entries. mRow.getImageResolver().purgeCache(); + + // Cancel any image loading tasks that have not completed at this point + mRow.getImageResolver().cancelRunningTasks(); } private static class RtlEnabledContext extends ContextWrapper { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageCache.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageCache.java index 41eeada0fcda..fe0b3123eb25 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageCache.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageCache.java @@ -22,8 +22,11 @@ import android.os.AsyncTask; import android.util.Log; import java.util.Set; +import java.util.concurrent.CancellationException; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; /** * A cache for inline images of image messages. @@ -56,12 +59,13 @@ public class NotificationInlineImageCache implements NotificationInlineImageReso } @Override - public Drawable get(Uri uri) { + public Drawable get(Uri uri, long timeoutMs) { Drawable result = null; try { - result = mCache.get(uri).get(); - } catch (InterruptedException | ExecutionException ex) { - Log.d(TAG, "get: Failed get image from " + uri); + result = mCache.get(uri).get(timeoutMs, TimeUnit.MILLISECONDS); + } catch (InterruptedException | ExecutionException + | TimeoutException | CancellationException ex) { + Log.d(TAG, "get: Failed get image from " + uri + " " + ex); } return result; } @@ -72,6 +76,15 @@ public class NotificationInlineImageCache implements NotificationInlineImageReso mCache.entrySet().removeIf(entry -> !wantedSet.contains(entry.getKey())); } + @Override + public void cancelRunningTasks() { + mCache.forEach((key, value) -> { + if (value.getStatus() != AsyncTask.Status.FINISHED) { + value.cancel(true); + } + }); + } + private static class PreloadImageTask extends AsyncTask<Uri, Void, Drawable> { private final NotificationInlineImageResolver mResolver; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java index b05e64ab1991..c620f448b3b7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java @@ -23,6 +23,7 @@ import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Bundle; import android.os.Parcelable; +import android.os.SystemClock; import android.util.Log; import com.android.internal.R; @@ -45,6 +46,9 @@ import java.util.Set; public class NotificationInlineImageResolver implements ImageResolver { private static final String TAG = NotificationInlineImageResolver.class.getSimpleName(); + // Timeout for loading images from ImageCache when calling from UI thread + private static final long MAX_UI_THREAD_TIMEOUT_MS = 100L; + private final Context mContext; private final ImageCache mImageCache; private Set<Uri> mWantedUriSet; @@ -123,17 +127,25 @@ public class NotificationInlineImageResolver implements ImageResolver { return null; } + /** + * Loads an image from the Uri. + * This method is synchronous and is usually called from the Main thread. + * It will time-out after MAX_UI_THREAD_TIMEOUT_MS. + * + * @param uri Uri of the target image. + * @return drawable of the image, null if loading failed/timeout + */ @Override public Drawable loadImage(Uri uri) { - return hasCache() ? loadImageFromCache(uri) : resolveImage(uri); + return hasCache() ? loadImageFromCache(uri, MAX_UI_THREAD_TIMEOUT_MS) : resolveImage(uri); } - private Drawable loadImageFromCache(Uri uri) { + private Drawable loadImageFromCache(Uri uri, long timeoutMs) { // if the uri isn't currently cached, try caching it first if (!mImageCache.hasEntry(uri)) { mImageCache.preload((uri)); } - return mImageCache.get(uri); + return mImageCache.get(uri, timeoutMs); } /** @@ -208,6 +220,30 @@ public class NotificationInlineImageResolver implements ImageResolver { } /** + * Wait for a maximum timeout for images to finish preloading + * @param timeoutMs total timeout time + */ + void waitForPreloadedImages(long timeoutMs) { + if (!hasCache()) { + return; + } + Set<Uri> preloadedUris = getWantedUriSet(); + if (preloadedUris != null) { + // Decrement remaining timeout after each image check + long endTimeMs = SystemClock.elapsedRealtime() + timeoutMs; + preloadedUris.forEach( + uri -> loadImageFromCache(uri, endTimeMs - SystemClock.elapsedRealtime())); + } + } + + void cancelRunningTasks() { + if (!hasCache()) { + return; + } + mImageCache.cancelRunningTasks(); + } + + /** * A interface for internal cache implementation of this resolver. */ interface ImageCache { @@ -216,7 +252,7 @@ public class NotificationInlineImageResolver implements ImageResolver { * @param uri The uri of the image. * @return Drawable of the image. */ - Drawable get(Uri uri); + Drawable get(Uri uri, long timeoutMs); /** * Set the image resolver that actually resolves image from specified uri. @@ -241,6 +277,11 @@ public class NotificationInlineImageResolver implements ImageResolver { * Purge unnecessary entries in the cache. */ void purge(); + + /** + * Cancel all unfinished image loading tasks + */ + void cancelRunningTasks(); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index d2087ba6ca1c..977e1bb31049 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -67,6 +67,7 @@ import android.view.ViewGroup; import android.view.ViewOutlineProvider; import android.view.ViewTreeObserver; import android.view.WindowInsets; +import android.view.WindowInsetsAnimation; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; import android.view.animation.AnimationUtils; @@ -199,6 +200,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable private final boolean mDebugRemoveAnimation; private final boolean mSimplifiedAppearFraction; private final boolean mUseRoundnessSourceTypes; + private boolean mAnimatedInsets; private int mContentHeight; private float mIntrinsicContentHeight; @@ -207,7 +209,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable private int mTopPadding; private boolean mAnimateNextTopPaddingChange; private int mBottomPadding; - private int mBottomInset = 0; + @VisibleForTesting + int mBottomInset = 0; private float mQsExpansionFraction; private final int mSplitShadeMinContentHeight; @@ -388,9 +391,33 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable } } }; + private boolean mPulsing; private boolean mScrollable; private View mForcedScroll; + private boolean mIsInsetAnimationRunning; + + private final WindowInsetsAnimation.Callback mInsetsCallback = + new WindowInsetsAnimation.Callback( + WindowInsetsAnimation.Callback.DISPATCH_MODE_CONTINUE_ON_SUBTREE) { + + @Override + public void onPrepare(WindowInsetsAnimation animation) { + mIsInsetAnimationRunning = true; + } + + @Override + public WindowInsets onProgress(WindowInsets windowInsets, + List<WindowInsetsAnimation> list) { + updateBottomInset(windowInsets); + return windowInsets; + } + + @Override + public void onEnd(WindowInsetsAnimation animation) { + mIsInsetAnimationRunning = false; + } + }; /** * @see #setHideAmount(float, float) @@ -584,6 +611,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable mDebugRemoveAnimation = featureFlags.isEnabled(Flags.NSSL_DEBUG_REMOVE_ANIMATION); mSimplifiedAppearFraction = featureFlags.isEnabled(Flags.SIMPLIFIED_APPEAR_FRACTION); mUseRoundnessSourceTypes = featureFlags.isEnabled(Flags.USE_ROUNDNESS_SOURCETYPES); + setAnimatedInsetsEnabled(featureFlags.isEnabled(Flags.ANIMATED_NOTIFICATION_SHADE_INSETS)); mSectionsManager = Dependency.get(NotificationSectionsManager.class); mScreenOffAnimationController = Dependency.get(ScreenOffAnimationController.class); @@ -622,6 +650,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable mGroupMembershipManager = Dependency.get(GroupMembershipManager.class); mGroupExpansionManager = Dependency.get(GroupExpansionManager.class); setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); + if (mAnimatedInsets) { + setWindowInsetsAnimationCallback(mInsetsCallback); + } } /** @@ -690,6 +721,11 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable } @VisibleForTesting + void setAnimatedInsetsEnabled(boolean enabled) { + mAnimatedInsets = enabled; + } + + @VisibleForTesting @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) public void updateFooter() { if (mFooterView == null) { @@ -1781,7 +1817,11 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable return; } mForcedScroll = v; - scrollTo(v); + if (mAnimatedInsets) { + updateForcedScroll(); + } else { + scrollTo(v); + } } @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) @@ -1813,26 +1853,46 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable + ((!isExpanded() && isPinnedHeadsUp(v)) ? mHeadsUpInset : getTopPadding()); } + private void updateBottomInset(WindowInsets windowInsets) { + mBottomInset = windowInsets.getInsets(WindowInsets.Type.ime()).bottom; + + if (mForcedScroll != null) { + updateForcedScroll(); + } + + int range = getScrollRange(); + if (mOwnScrollY > range) { + setOwnScrollY(range); + } + } + @Override @ShadeViewRefactor(RefactorComponent.COORDINATOR) public WindowInsets onApplyWindowInsets(WindowInsets insets) { - mBottomInset = insets.getInsets(WindowInsets.Type.ime()).bottom; + if (!mAnimatedInsets) { + mBottomInset = insets.getInsets(WindowInsets.Type.ime()).bottom; + } mWaterfallTopInset = 0; final DisplayCutout cutout = insets.getDisplayCutout(); if (cutout != null) { mWaterfallTopInset = cutout.getWaterfallInsets().top; } - - int range = getScrollRange(); - if (mOwnScrollY > range) { - // HACK: We're repeatedly getting staggered insets here while the IME is - // animating away. To work around that we'll wait until things have settled. - removeCallbacks(mReclamp); - postDelayed(mReclamp, 50); - } else if (mForcedScroll != null) { - // The scroll was requested before we got the actual inset - in case we need - // to scroll up some more do so now. - scrollTo(mForcedScroll); + if (mAnimatedInsets && !mIsInsetAnimationRunning) { + // update bottom inset e.g. after rotation + updateBottomInset(insets); + } + if (!mAnimatedInsets) { + int range = getScrollRange(); + if (mOwnScrollY > range) { + // HACK: We're repeatedly getting staggered insets here while the IME is + // animating away. To work around that we'll wait until things have settled. + removeCallbacks(mReclamp); + postDelayed(mReclamp, 50); + } else if (mForcedScroll != null) { + // The scroll was requested before we got the actual inset - in case we need + // to scroll up some more do so now. + scrollTo(mForcedScroll); + } } return insets; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java index 42d122d6f9ac..14b0763580e9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java @@ -209,7 +209,11 @@ public class NotificationStackScrollLayoutController { public void onViewAttachedToWindow(View v) { mConfigurationController.addCallback(mConfigurationListener); mZenModeController.addCallback(mZenModeControllerCallback); - mBarState = mStatusBarStateController.getState(); + final int newBarState = mStatusBarStateController.getState(); + if (newBarState != mBarState) { + mStateListener.onStateChanged(newBarState); + mStateListener.onStatePostChange(); + } mStatusBarStateController.addCallback( mStateListener, SysuiStatusBarStateController.RANK_STACK_SCROLLER); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelper.kt index 548d1a135948..8b6d6a4f3170 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelper.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelper.kt @@ -25,9 +25,10 @@ constructor( /** * This method looks for views that can be rounded (and implement [Roundable]) during a * notification swipe. + * * @return The [Roundable] targets above/below the [viewSwiped] (if available). The - * [RoundableTargets.before] and [RoundableTargets.after] parameters can be `null` if there is - * no above/below notification or the notification is not part of the same section. + * [RoundableTargets.before] and [RoundableTargets.after] parameters can be `null` if there is + * no above/below notification or the notification is not part of the same section. */ fun findRoundableTargets( viewSwiped: ExpandableNotificationRow, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java index 993c4e2a4073..573347cb1aff 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java @@ -398,6 +398,9 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp boolean isStrongBiometric) { Trace.beginSection("BiometricUnlockController#onBiometricAuthenticated"); if (mUpdateMonitor.isGoingToSleep()) { + mLogger.deferringAuthenticationDueToSleep(userId, + biometricSourceType, + mPendingAuthenticated != null); mPendingAuthenticated = new PendingAuthenticated(userId, biometricSourceType, isStrongBiometric); Trace.endSection(); @@ -813,6 +816,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp public void onFinishedGoingToSleep() { Trace.beginSection("BiometricUnlockController#onFinishedGoingToSleep"); if (mPendingAuthenticated != null) { + mLogger.finishedGoingToSleepWithPendingAuth(); PendingAuthenticated pendingAuthenticated = mPendingAuthenticated; // Post this to make sure it's executed after the device is fully locked. mHandler.post(() -> onBiometricAuthenticated(pendingAuthenticated.userId, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java index 6b4a4d1389ff..b5d51ce2b9ee 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java @@ -2211,10 +2211,10 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { pw.println("Current Status Bar state:"); pw.println(" mExpandedVisible=" + mShadeController.isExpandedVisible()); pw.println(" mDisplayMetrics=" + mDisplayMetrics); - pw.println(" mStackScroller: " + CentralSurfaces.viewInfo(mStackScroller)); - pw.println(" mStackScroller: " + CentralSurfaces.viewInfo(mStackScroller) - + " scroll " + mStackScroller.getScrollX() + pw.print(" mStackScroller: " + CentralSurfaces.viewInfo(mStackScroller)); + pw.print(" scroll " + mStackScroller.getScrollX() + "," + mStackScroller.getScrollY()); + pw.println(" translationX " + mStackScroller.getTranslationX()); } pw.print(" mInteractingWindows="); pw.println(mInteractingWindows); @@ -3695,6 +3695,12 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { @Override public void notifyBiometricAuthModeChanged() { mDozeServiceHost.updateDozing(); + if (mBiometricUnlockController.getMode() + == BiometricUnlockController.MODE_DISMISS_BOUNCER) { + // Don't update the scrim controller at this time, in favor of the transition repository + // updating the scrim + return; + } updateScrimController(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java index c72eb054c62c..39b5b5a4cef8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java @@ -40,6 +40,7 @@ import com.android.systemui.statusbar.StatusIconDisplayable; import com.android.systemui.statusbar.connectivity.ui.MobileContextProvider; import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState; import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState; +import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger; import com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernStatusBarMobileView; import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel; import com.android.systemui.statusbar.pipeline.wifi.ui.view.ModernStatusBarWifiView; @@ -288,10 +289,14 @@ public class DemoStatusIcons extends StatusIconContainer implements DemoMode, Da * @param mobileContext possibly mcc/mnc overridden mobile context * @param subId the subscriptionId for this mobile view */ - public void addModernMobileView(Context mobileContext, int subId) { + public void addModernMobileView( + Context mobileContext, + MobileViewLogger mobileViewLogger, + int subId) { Log.d(TAG, "addModernMobileView (subId=" + subId + ")"); ModernStatusBarMobileView view = ModernStatusBarMobileView.constructAndBind( mobileContext, + mobileViewLogger, "mobile", mMobileIconsViewModel.viewModelForSub(subId, mLocation) ); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java index b88531e59568..ae715b3f20c8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java @@ -429,7 +429,6 @@ public class DozeParameters implements } dispatchAlwaysOnEvent(); - mScreenOffAnimationController.onAlwaysOnChanged(getAlwaysOn()); } @Override @@ -469,6 +468,7 @@ public class DozeParameters implements for (Callback callback : mCallbacks) { callback.onAlwaysOnChange(); } + mScreenOffAnimationController.onAlwaysOnChanged(getAlwaysOn()); } private boolean getPostureSpecificBool( diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java index 753032c2ee01..3268032becf8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java @@ -59,7 +59,7 @@ import com.android.systemui.statusbar.notification.PropertyAnimator; import com.android.systemui.statusbar.notification.stack.AnimationProperties; import com.android.systemui.statusbar.notification.stack.StackStateAnimator; import com.android.systemui.statusbar.phone.fragment.StatusBarIconBlocklistKt; -import com.android.systemui.statusbar.phone.fragment.StatusBarSystemEventAnimator; +import com.android.systemui.statusbar.phone.fragment.StatusBarSystemEventDefaultAnimator; import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -75,6 +75,8 @@ import java.util.concurrent.Executor; import javax.inject.Inject; +import kotlin.Unit; + /** View Controller for {@link com.android.systemui.statusbar.phone.KeyguardStatusBarView}. */ public class KeyguardStatusBarViewController extends ViewController<KeyguardStatusBarView> { private static final String TAG = "KeyguardStatusBarViewController"; @@ -123,7 +125,8 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat public void onDensityOrFontScaleChanged() { mView.loadDimens(); // The animator is dependent on resources for offsets - mSystemEventAnimator = new StatusBarSystemEventAnimator(mView, getResources()); + mSystemEventAnimator = + getSystemEventAnimator(mSystemEventAnimator.isAnimationRunning()); } @Override @@ -248,7 +251,8 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat private int mStatusBarState; private boolean mDozing; private boolean mShowingKeyguardHeadsUp; - private StatusBarSystemEventAnimator mSystemEventAnimator; + private StatusBarSystemEventDefaultAnimator mSystemEventAnimator; + private float mSystemEventAnimatorAlpha = 1; /** * The alpha value to be set on the View. If -1, this value is to be ignored. @@ -324,7 +328,7 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat mView.setKeyguardUserAvatarEnabled( !mStatusBarUserChipViewModel.getChipEnabled()); - mSystemEventAnimator = new StatusBarSystemEventAnimator(mView, r); + mSystemEventAnimator = getSystemEventAnimator(/* isAnimationRunning */ false); mDisableStateTracker = new DisableStateTracker( /* mask1= */ DISABLE_SYSTEM_INFO, @@ -480,6 +484,10 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat * (1.0f - mKeyguardHeadsUpShowingAmount); } + if (mSystemEventAnimator.isAnimationRunning()) { + newAlpha = Math.min(newAlpha, mSystemEventAnimatorAlpha); + } + boolean hideForBypass = mFirstBypassAttempt && mKeyguardUpdateMonitor.shouldListenForFace() || mDelayShowingKeyguardStatusBar; @@ -488,7 +496,7 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat && !mDozing && !hideForBypass && !mDisableStateTracker.isDisabled() - ? View.VISIBLE : View.INVISIBLE; + ? View.VISIBLE : View.INVISIBLE; updateViewState(newAlpha, newVisibility); } @@ -614,4 +622,15 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat updateBlockedIcons(); } }; + + private StatusBarSystemEventDefaultAnimator getSystemEventAnimator(boolean isAnimationRunning) { + return new StatusBarSystemEventDefaultAnimator(getResources(), (alpha) -> { + mSystemEventAnimatorAlpha = alpha; + updateViewState(); + return Unit.INSTANCE; + }, (translationX) -> { + mView.setTranslationX(translationX); + return Unit.INSTANCE; + }, isAnimationRunning); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java index 8e0ec284c840..8fd967594198 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -16,6 +16,8 @@ package com.android.systemui.statusbar.phone; +import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow; + import static java.lang.Float.isNaN; import android.animation.Animator; @@ -53,9 +55,14 @@ import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dock.DockManager; import com.android.systemui.keyguard.KeyguardUnlockAnimationController; +import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor; import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants; +import com.android.systemui.keyguard.shared.model.TransitionState; +import com.android.systemui.keyguard.shared.model.TransitionStep; +import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel; import com.android.systemui.scrim.ScrimView; import com.android.systemui.shade.NotificationPanelViewController; +import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.stack.ViewState; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -71,6 +78,8 @@ import java.util.function.Consumer; import javax.inject.Inject; +import kotlinx.coroutines.CoroutineDispatcher; + /** * Controls both the scrim behind the notifications and in front of the notifications (when a * security method gets shown). @@ -197,6 +206,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump private final ScreenOffAnimationController mScreenOffAnimationController; private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController; private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; + private final SysuiStatusBarStateController mStatusBarStateController; private GradientColors mColors; private boolean mNeedsDrawableColorUpdate; @@ -251,6 +261,20 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump private boolean mWakeLockHeld; private boolean mKeyguardOccluded; + private KeyguardTransitionInteractor mKeyguardTransitionInteractor; + private CoroutineDispatcher mMainDispatcher; + private boolean mIsBouncerToGoneTransitionRunning = false; + private PrimaryBouncerToGoneTransitionViewModel mPrimaryBouncerToGoneTransitionViewModel; + private final Consumer<Float> mScrimAlphaConsumer = + (Float alpha) -> { + mScrimInFront.setViewAlpha(mInFrontAlpha); + mNotificationsScrim.setViewAlpha(mNotificationsAlpha); + mBehindAlpha = alpha; + mScrimBehind.setViewAlpha(alpha); + }; + + Consumer<TransitionStep> mPrimaryBouncerToGoneTransition; + @Inject public ScrimController( LightBarController lightBarController, @@ -265,13 +289,18 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump @Main Executor mainExecutor, ScreenOffAnimationController screenOffAnimationController, KeyguardUnlockAnimationController keyguardUnlockAnimationController, - StatusBarKeyguardViewManager statusBarKeyguardViewManager) { + StatusBarKeyguardViewManager statusBarKeyguardViewManager, + PrimaryBouncerToGoneTransitionViewModel primaryBouncerToGoneTransitionViewModel, + KeyguardTransitionInteractor keyguardTransitionInteractor, + SysuiStatusBarStateController sysuiStatusBarStateController, + @Main CoroutineDispatcher mainDispatcher) { mScrimStateListener = lightBarController::setScrimState; mDefaultScrimAlpha = BUSY_SCRIM_ALPHA; mKeyguardStateController = keyguardStateController; mDarkenWhileDragging = !mKeyguardStateController.canDismissLockScreen(); mKeyguardUpdateMonitor = keyguardUpdateMonitor; + mStatusBarStateController = sysuiStatusBarStateController; mKeyguardVisibilityCallback = new KeyguardVisibilityCallback(); mHandler = handler; mMainExecutor = mainExecutor; @@ -304,6 +333,9 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump } }); mColors = new GradientColors(); + mPrimaryBouncerToGoneTransitionViewModel = primaryBouncerToGoneTransitionViewModel; + mKeyguardTransitionInteractor = keyguardTransitionInteractor; + mMainDispatcher = mainDispatcher; } /** @@ -343,6 +375,33 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump for (ScrimState state : ScrimState.values()) { state.prepare(state); } + + // Directly control transition to UNLOCKED scrim state from PRIMARY_BOUNCER, and make sure + // to report back that keyguard has faded away. This fixes cases where the scrim state was + // rapidly switching on unlock, due to shifts in state in CentralSurfacesImpl + mPrimaryBouncerToGoneTransition = + (TransitionStep step) -> { + TransitionState state = step.getTransitionState(); + + mIsBouncerToGoneTransitionRunning = state == TransitionState.RUNNING; + + if (state == TransitionState.STARTED) { + setExpansionAffectsAlpha(false); + transitionTo(ScrimState.UNLOCKED); + } + + if (state == TransitionState.FINISHED || state == TransitionState.CANCELED) { + setExpansionAffectsAlpha(true); + if (mKeyguardStateController.isKeyguardFadingAway()) { + mStatusBarKeyguardViewManager.onKeyguardFadedAway(); + } + } + }; + + collectFlow(behindScrim, mKeyguardTransitionInteractor.getPrimaryBouncerToGoneTransition(), + mPrimaryBouncerToGoneTransition, mMainDispatcher); + collectFlow(behindScrim, mPrimaryBouncerToGoneTransitionViewModel.getScrimBehindAlpha(), + mScrimAlphaConsumer, mMainDispatcher); } /** @@ -365,6 +424,11 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump } public void transitionTo(ScrimState state, Callback callback) { + if (mIsBouncerToGoneTransitionRunning) { + Log.i(TAG, "Skipping transition to: " + state + + " while mIsBouncerToGoneTransitionRunning"); + return; + } if (state == mState) { // Call the callback anyway, unless it's already enqueued if (callback != null && mCallback != callback) { @@ -1036,7 +1100,8 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump mBehindAlpha = 1; } // Prevent notification scrim flicker when transitioning away from keyguard. - if (mKeyguardStateController.isKeyguardGoingAway()) { + if (mKeyguardStateController.isKeyguardGoingAway() + && !mStatusBarStateController.leaveOpenOnKeyguardHide()) { mNotificationsAlpha = 0; } @@ -1125,7 +1190,9 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump Trace.traceCounter(Trace.TRACE_TAG_APP, getScrimName(scrimView) + "_tint", Color.alpha(tint)); scrimView.setTint(tint); - scrimView.setViewAlpha(alpha); + if (!mIsBouncerToGoneTransitionRunning) { + scrimView.setViewAlpha(alpha); + } } else { scrim.setAlpha(alpha); } @@ -1473,6 +1540,9 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump } public void setKeyguardOccluded(boolean keyguardOccluded) { + if (mKeyguardOccluded == keyguardOccluded) { + return; + } mKeyguardOccluded = keyguardOccluded; updateScrims(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java index 11863627218e..04cc8ce792d1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java @@ -569,7 +569,10 @@ public interface StatusBarIconController { mGroup.addView(view, index, onCreateLayoutParams()); if (mIsInDemoMode) { - mDemoStatusIcons.addModernMobileView(mContext, subId); + mDemoStatusIcons.addModernMobileView( + mContext, + mMobileIconsViewModel.getLogger(), + subId); } return view; @@ -601,6 +604,7 @@ public interface StatusBarIconController { return ModernStatusBarMobileView .constructAndBind( mobileContext, + mMobileIconsViewModel.getLogger(), slot, mMobileIconsViewModel.viewModelForSub(subId, mLocation) ); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconHolder.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconHolder.java index f6c0da8da8c0..833cb93f62e9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconHolder.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconHolder.java @@ -79,6 +79,18 @@ public class StatusBarIconHolder { private @IconType int mType = TYPE_ICON; private int mTag = 0; + /** Returns a human-readable string representing the given type. */ + public static String getTypeString(@IconType int type) { + switch(type) { + case TYPE_ICON: return "ICON"; + case TYPE_WIFI: return "WIFI_OLD"; + case TYPE_MOBILE: return "MOBILE_OLD"; + case TYPE_MOBILE_NEW: return "MOBILE_NEW"; + case TYPE_WIFI_NEW: return "WIFI_NEW"; + default: return "UNKNOWN"; + } + } + private StatusBarIconHolder() { } @@ -230,4 +242,11 @@ public class StatusBarIconHolder { public int getTag() { return mTag; } + + @Override + public String toString() { + return "StatusBarIconHolder(type=" + getTypeString(mType) + + " tag=" + getTag() + + " visible=" + isVisible() + ")"; + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconList.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconList.java index 8800b05fadb7..565481a20d95 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconList.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconList.java @@ -27,6 +27,7 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; /** A class holding the list of all the system icons that could be shown in the status bar. */ public class StatusBarIconList { @@ -302,7 +303,7 @@ public class StatusBarIconList { @Override public String toString() { - return String.format("(%s) %s", mName, subSlotsString()); + return String.format("(%s) holder=%s %s", mName, mHolder, subSlotsString()); } private String subSlotsString() { @@ -310,7 +311,10 @@ public class StatusBarIconList { return ""; } - return "" + mSubSlots.size() + " subSlots"; + return "| " + mSubSlots.size() + " subSlots: " + + mSubSlots.stream() + .map(StatusBarIconHolder::toString) + .collect(Collectors.joining("|")); } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationController.kt index 79c0984d9bf7..d30d0e25bd8c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationController.kt @@ -22,6 +22,7 @@ import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator.AlphaP import com.android.systemui.statusbar.phone.PhoneStatusBarViewController.StatusBarViewsCenterProvider import com.android.systemui.unfold.SysUIUnfoldScope import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener +import com.android.systemui.unfold.util.CurrentActivityTypeProvider import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider import javax.inject.Inject import kotlin.math.max @@ -29,9 +30,13 @@ import kotlin.math.max @SysUIUnfoldScope class StatusBarMoveFromCenterAnimationController @Inject constructor( private val progressProvider: ScopedUnfoldTransitionProgressProvider, + private val currentActivityTypeProvider: CurrentActivityTypeProvider, windowManager: WindowManager ) { + // Whether we're on home activity. Updated only when the animation starts. + private var isOnHomeActivity: Boolean? = null + private val transitionListener = TransitionListener() private val moveFromCenterAnimator = UnfoldMoveFromCenterAnimator( windowManager, @@ -60,6 +65,10 @@ class StatusBarMoveFromCenterAnimationController @Inject constructor( } private inner class TransitionListener : TransitionProgressListener { + override fun onTransitionStarted() { + isOnHomeActivity = currentActivityTypeProvider.isHomeActivity + } + override fun onTransitionProgress(progress: Float) { moveFromCenterAnimator.onTransitionProgress(progress) } @@ -68,11 +77,23 @@ class StatusBarMoveFromCenterAnimationController @Inject constructor( // Reset translations when transition is stopped/cancelled // (e.g. the transition could be cancelled mid-way when rotating the screen) moveFromCenterAnimator.onTransitionProgress(1f) + isOnHomeActivity = null } } - private class StatusBarIconsAlphaProvider : AlphaProvider { + + /** + * In certain cases, an alpha is applied based on the progress. + * + * This mainly happens to hide the statusbar during the unfold animation while on apps, as the + * bounds of the app "collapse" to the center, but the statusbar doesn't. + * While on launcher, this alpha is not applied. + */ + private inner class StatusBarIconsAlphaProvider : AlphaProvider { override fun getAlpha(progress: Float): Float { + if (isOnHomeActivity == true) { + return 1.0f + } return max( 0f, (progress - ICONS_START_APPEARING_PROGRESS) / (1 - ICONS_START_APPEARING_PROGRESS) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarSystemEventAnimator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarSystemEventAnimator.kt index c04ea36b3d8d..5903fa3d5bd1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarSystemEventAnimator.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarSystemEventAnimator.kt @@ -26,19 +26,39 @@ import com.android.systemui.statusbar.events.STATUS_BAR_X_MOVE_IN import com.android.systemui.statusbar.events.STATUS_BAR_X_MOVE_OUT import com.android.systemui.statusbar.events.SystemStatusAnimationCallback import com.android.systemui.util.animation.AnimationUtil.Companion.frames +import com.android.systemui.util.doOnCancel +import com.android.systemui.util.doOnEnd + +/** + * An implementation of [StatusBarSystemEventDefaultAnimator], applying the onAlphaChanged and + * onTranslationXChanged callbacks directly to the provided animatedView. + */ +class StatusBarSystemEventAnimator @JvmOverloads constructor( + val animatedView: View, + resources: Resources, + isAnimationRunning: Boolean = false +) : StatusBarSystemEventDefaultAnimator( + resources = resources, + onAlphaChanged = animatedView::setAlpha, + onTranslationXChanged = animatedView::setTranslationX, + isAnimationRunning = isAnimationRunning +) /** * Tied directly to [SystemStatusAnimationScheduler]. Any StatusBar-like thing (keyguard, collapsed - * status bar fragment), can just feed this an animatable view to get the default system status - * animation. + * status bar fragment), can use this Animator to get the default system status animation. It simply + * needs to implement the onAlphaChanged and onTranslationXChanged callbacks. * * This animator relies on resources, and should be recreated whenever resources are updated. While * this class could be used directly as the animation callback, it's probably best to forward calls * to it so that it can be recreated at any moment without needing to remove/add callback. */ -class StatusBarSystemEventAnimator( - val animatedView: View, - resources: Resources + +open class StatusBarSystemEventDefaultAnimator @JvmOverloads constructor( + resources: Resources, + private val onAlphaChanged: (Float) -> Unit, + private val onTranslationXChanged: (Float) -> Unit, + var isAnimationRunning: Boolean = false ) : SystemStatusAnimationCallback { private val translationXIn: Int = resources.getDimensionPixelSize( R.dimen.ongoing_appops_chip_animation_in_status_bar_translation_x) @@ -46,18 +66,19 @@ class StatusBarSystemEventAnimator( R.dimen.ongoing_appops_chip_animation_out_status_bar_translation_x) override fun onSystemEventAnimationBegin(): Animator { + isAnimationRunning = true val moveOut = ValueAnimator.ofFloat(0f, 1f).apply { duration = 23.frames interpolator = STATUS_BAR_X_MOVE_OUT addUpdateListener { - animatedView.translationX = -(translationXIn * animatedValue as Float) + onTranslationXChanged(-(translationXIn * animatedValue as Float)) } } val alphaOut = ValueAnimator.ofFloat(1f, 0f).apply { duration = 8.frames interpolator = null addUpdateListener { - animatedView.alpha = animatedValue as Float + onAlphaChanged(animatedValue as Float) } } @@ -67,13 +88,13 @@ class StatusBarSystemEventAnimator( } override fun onSystemEventAnimationFinish(hasPersistentDot: Boolean): Animator { - animatedView.translationX = translationXOut.toFloat() + onTranslationXChanged(translationXOut.toFloat()) val moveIn = ValueAnimator.ofFloat(1f, 0f).apply { duration = 23.frames startDelay = 7.frames interpolator = STATUS_BAR_X_MOVE_IN addUpdateListener { - animatedView.translationX = translationXOut * animatedValue as Float + onTranslationXChanged(translationXOut * animatedValue as Float) } } val alphaIn = ValueAnimator.ofFloat(0f, 1f).apply { @@ -81,13 +102,14 @@ class StatusBarSystemEventAnimator( startDelay = 11.frames interpolator = null addUpdateListener { - animatedView.alpha = animatedValue as Float + onAlphaChanged(animatedValue as Float) } } val animatorSet = AnimatorSet() animatorSet.playTogether(moveIn, alphaIn) - + animatorSet.doOnEnd { isAnimationRunning = false } + animatorSet.doOnCancel { isAnimationRunning = false } return animatorSet } }
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/MobileViewLog.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/MobileViewLog.kt new file mode 100644 index 000000000000..e594a8a5efd9 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/MobileViewLog.kt @@ -0,0 +1,25 @@ +/* + * 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.systemui.statusbar.pipeline.dagger + +import javax.inject.Qualifier + +/** Logs for changes with the new mobile views. */ +@Qualifier +@MustBeDocumented +@kotlin.annotation.Retention(AnnotationRetention.RUNTIME) +annotation class MobileViewLog diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt index 44647515a6e5..adfea80715a2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt @@ -148,5 +148,19 @@ abstract class StatusBarPipelineModule { fun provideMobileInputLogBuffer(factory: LogBufferFactory): LogBuffer { return factory.create("MobileInputLog", 100) } + + @Provides + @SysUISingleton + @MobileViewLog + fun provideMobileViewLogBuffer(factory: LogBufferFactory): LogBuffer { + return factory.create("MobileViewLog", 100) + } + + @Provides + @SysUISingleton + @VerboseMobileViewLog + fun provideVerboseMobileViewLogBuffer(factory: LogBufferFactory): LogBuffer { + return factory.create("VerboseMobileViewLog", 100) + } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/VerboseMobileViewLog.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/VerboseMobileViewLog.kt new file mode 100644 index 000000000000..b98789807dd3 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/VerboseMobileViewLog.kt @@ -0,0 +1,25 @@ +/* + * 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.systemui.statusbar.pipeline.dagger + +import javax.inject.Qualifier + +/** Logs for **verbose** changes with the new mobile views. */ +@Qualifier +@MustBeDocumented +@kotlin.annotation.Retention(AnnotationRetention.RUNTIME) +annotation class VerboseMobileViewLog diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/shared/MobileInputLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/MobileInputLogger.kt index 3cbd2b76c248..4156fc152602 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/shared/MobileInputLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/MobileInputLogger.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.statusbar.pipeline.mobile.shared +package com.android.systemui.statusbar.pipeline.mobile.data import android.net.Network import android.net.NetworkCapabilities @@ -51,8 +51,8 @@ constructor( ) } - fun logOnLost(network: Network) { - LoggerHelper.logOnLost(buffer, TAG, network) + fun logOnLost(network: Network, isDefaultNetworkCallback: Boolean) { + LoggerHelper.logOnLost(buffer, TAG, network, isDefaultNetworkCallback) } fun logOnServiceStateChanged(serviceState: ServiceState, subId: Int) { @@ -133,24 +133,6 @@ constructor( ) } - fun logUiAdapterSubIdsUpdated(subs: List<Int>) { - buffer.log( - TAG, - LogLevel.INFO, - { str1 = subs.toString() }, - { "Sub IDs in MobileUiAdapter updated internally: $str1" }, - ) - } - - fun logUiAdapterSubIdsSentToIconController(subs: List<Int>) { - buffer.log( - TAG, - LogLevel.INFO, - { str1 = subs.toString() }, - { "Sub IDs in MobileUiAdapter being sent to icon controller: $str1" }, - ) - } - fun logCarrierConfigChanged(subId: Int) { buffer.log( TAG, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SystemUiCarrierConfig.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SystemUiCarrierConfig.kt index 8c82fbac90b8..f4e3eab8593d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SystemUiCarrierConfig.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SystemUiCarrierConfig.kt @@ -45,7 +45,7 @@ import kotlinx.coroutines.flow.asStateFlow * 1. Define a new `private val` wrapping the key using [BooleanCarrierConfig] * 2. Define a public `val` exposing the wrapped flow using [BooleanCarrierConfig.config] * 3. Add the new [BooleanCarrierConfig] to the list of tracked configs, so they are properly - * updated when a new carrier config comes down + * updated when a new carrier config comes down */ class SystemUiCarrierConfig internal constructor( diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepository.kt index bb3b9b2166c3..efdce062bb37 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepository.kt @@ -30,8 +30,8 @@ import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dump.DumpManager +import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig -import com.android.systemui.statusbar.pipeline.mobile.shared.MobileInputLogger import java.io.PrintWriter import javax.inject.Inject import kotlinx.coroutines.CoroutineScope diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt index 96b96f14d6aa..e182bc66081a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt @@ -36,6 +36,7 @@ import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCall import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.log.table.TableLogBuffer +import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType @@ -47,7 +48,6 @@ import com.android.systemui.statusbar.pipeline.mobile.data.model.toNetworkNameMo import com.android.systemui.statusbar.pipeline.mobile.data.repository.CarrierConfigRepository import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS -import com.android.systemui.statusbar.pipeline.mobile.shared.MobileInputLogger import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel import javax.inject.Inject diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt index b3d5b1e7e450..b7da3f27c70a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt @@ -45,11 +45,11 @@ import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.log.table.TableLogBuffer import com.android.systemui.log.table.logDiffsForTable import com.android.systemui.statusbar.pipeline.dagger.MobileSummaryLog +import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository -import com.android.systemui.statusbar.pipeline.mobile.shared.MobileInputLogger import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel @@ -266,6 +266,7 @@ constructor( val callback = object : NetworkCallback(FLAG_INCLUDE_LOCATION_INFO) { override fun onLost(network: Network) { + logger.logOnLost(network, isDefaultNetworkCallback = true) // Send a disconnected model when lost. Maybe should create a sealed // type or null here? trySend(MobileConnectivityModel()) @@ -275,6 +276,11 @@ constructor( network: Network, caps: NetworkCapabilities ) { + logger.logOnCapabilitiesChanged( + network, + caps, + isDefaultNetworkCallback = true, + ) trySend( MobileConnectivityModel( isConnected = caps.hasTransport(TRANSPORT_CELLULAR), @@ -353,8 +359,8 @@ constructor( * True if the checked subId is in the list of current subs or the active mobile data subId * * @param checkedSubs the list to validate [subId] against. To invalidate the cache, pass in the - * new subscription list. Otherwise use [subscriptions.value] to validate a subId against the - * current known subscriptions + * new subscription list. Otherwise use [subscriptions.value] to validate a subId against the + * current known subscriptions */ private fun checkSub(subId: Int, checkedSubs: List<SubscriptionModel>): Boolean { if (activeMobileDataSubscriptionId.value == subId) return true 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 7b0f95271d63..4caf2b09a3f2 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 @@ -92,7 +92,8 @@ interface MobileIconInteractor { * 1. The default network name, if one is configured * 2. A derived name based off of the intent [ACTION_SERVICE_PROVIDERS_UPDATED] * 3. Or, in the case where the repository sends us the default network name, we check for an - * override in [connectionInfo.operatorAlphaShort], a value that is derived from [ServiceState] + * override in [connectionInfo.operatorAlphaShort], a value that is derived from + * [ServiceState] */ val networkName: StateFlow<NetworkNameModel> diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt index da63ab10f733..075e6ec11ae7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt @@ -22,7 +22,6 @@ import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.statusbar.phone.StatusBarIconController import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor -import com.android.systemui.statusbar.pipeline.mobile.shared.MobileInputLogger import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel import java.io.PrintWriter import javax.inject.Inject @@ -55,17 +54,14 @@ constructor( interactor: MobileIconsInteractor, private val iconController: StatusBarIconController, private val iconsViewModelFactory: MobileIconsViewModel.Factory, - private val logger: MobileInputLogger, + private val logger: MobileViewLogger, @Application private val scope: CoroutineScope, private val statusBarPipelineFlags: StatusBarPipelineFlags, ) : CoreStartable { private val mobileSubIds: Flow<List<Int>> = - interactor.filteredSubscriptions - .mapLatest { subscriptions -> - subscriptions.map { subscriptionModel -> subscriptionModel.subscriptionId } - } - .distinctUntilChanged() - .onEach { logger.logUiAdapterSubIdsUpdated(it) } + interactor.filteredSubscriptions.mapLatest { subscriptions -> + subscriptions.map { subscriptionModel -> subscriptionModel.subscriptionId } + } /** * We expose the list of tracked subscriptions as a flow of a list of ints, where each int is @@ -75,7 +71,10 @@ constructor( * NOTE: this should go away as the view presenter learns more about this data pipeline */ private val mobileSubIdsState: StateFlow<List<Int>> = - mobileSubIds.stateIn(scope, SharingStarted.WhileSubscribed(), listOf()) + mobileSubIds + .distinctUntilChanged() + .onEach { logger.logUiAdapterSubIdsUpdated(it) } + .stateIn(scope, SharingStarted.WhileSubscribed(), listOf()) /** In order to keep the logs tame, we will reuse the same top-level mobile icons view model */ val mobileIconsViewModel = iconsViewModelFactory.create(mobileSubIdsState) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLogger.kt new file mode 100644 index 000000000000..90dff23c637c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLogger.kt @@ -0,0 +1,118 @@ +/* + * 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.systemui.statusbar.pipeline.mobile.ui + +import android.view.View +import com.android.systemui.Dumpable +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dump.DumpManager +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel +import com.android.systemui.statusbar.pipeline.dagger.MobileViewLog +import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.LocationBasedMobileViewModel +import java.io.PrintWriter +import javax.inject.Inject + +/** Logs for changes with the new mobile views. */ +@SysUISingleton +class MobileViewLogger +@Inject +constructor( + @MobileViewLog private val buffer: LogBuffer, + dumpManager: DumpManager, +) : Dumpable { + init { + dumpManager.registerNormalDumpable(this) + } + + private val collectionStatuses = mutableMapOf<String, Boolean>() + + fun logUiAdapterSubIdsUpdated(subs: List<Int>) { + buffer.log( + TAG, + LogLevel.INFO, + { str1 = subs.toString() }, + { "Sub IDs in MobileUiAdapter updated internally: $str1" }, + ) + } + + fun logUiAdapterSubIdsSentToIconController(subs: List<Int>) { + buffer.log( + TAG, + LogLevel.INFO, + { str1 = subs.toString() }, + { "Sub IDs in MobileUiAdapter being sent to icon controller: $str1" }, + ) + } + + fun logNewViewBinding(view: View, viewModel: LocationBasedMobileViewModel) { + buffer.log( + TAG, + LogLevel.INFO, + { + str1 = view.getIdForLogging() + str2 = viewModel.getIdForLogging() + str3 = viewModel.locationName + }, + { "New view binding. viewId=$str1, viewModelId=$str2, viewModelLocation=$str3" }, + ) + } + + fun logCollectionStarted(view: View, viewModel: LocationBasedMobileViewModel) { + collectionStatuses[view.getIdForLogging()] = true + buffer.log( + TAG, + LogLevel.INFO, + { + str1 = view.getIdForLogging() + str2 = viewModel.getIdForLogging() + str3 = viewModel.locationName + }, + { "Collection started. viewId=$str1, viewModelId=$str2, viewModelLocation=$str3" }, + ) + } + + fun logCollectionStopped(view: View, viewModel: LocationBasedMobileViewModel) { + collectionStatuses[view.getIdForLogging()] = false + buffer.log( + TAG, + LogLevel.INFO, + { + str1 = view.getIdForLogging() + str2 = viewModel.getIdForLogging() + str3 = viewModel.locationName + }, + { "Collection stopped. viewId=$str1, viewModelId=$str2, viewModelLocation=$str3" }, + ) + } + + override fun dump(pw: PrintWriter, args: Array<out String>) { + pw.println("Collection statuses per view:---") + collectionStatuses.forEach { viewId, isCollecting -> + pw.println("viewId=$viewId, isCollecting=$isCollecting") + } + } + + companion object { + fun Any.getIdForLogging(): String { + // The identityHashCode is guaranteed to be constant for the lifetime of the object. + return Integer.toHexString(System.identityHashCode(this)) + } + } +} + +private const val TAG = "MobileViewLogger" diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/VerboseMobileViewLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/VerboseMobileViewLogger.kt new file mode 100644 index 000000000000..f67bc8f14447 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/VerboseMobileViewLogger.kt @@ -0,0 +1,76 @@ +/* + * 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.systemui.statusbar.pipeline.mobile.ui + +import android.view.View +import com.android.systemui.common.shared.model.Icon +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel +import com.android.systemui.statusbar.pipeline.dagger.VerboseMobileViewLog +import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger.Companion.getIdForLogging +import com.android.systemui.statusbar.pipeline.mobile.ui.model.SignalIconModel +import javax.inject.Inject + +/** + * Logs for **verbose** changes with the new mobile views. + * + * This is a hopefully temporary log until we resolve some open bugs (b/267236367, b/269565345, + * b/270300839). + */ +@SysUISingleton +class VerboseMobileViewLogger +@Inject +constructor( + @VerboseMobileViewLog private val buffer: LogBuffer, +) { + fun logBinderReceivedSignalIcon(parentView: View, subId: Int, icon: SignalIconModel) { + buffer.log( + TAG, + LogLevel.VERBOSE, + { + str1 = parentView.getIdForLogging() + int1 = subId + int2 = icon.level + bool1 = icon.showExclamationMark + }, + { + "Binder[subId=$int1, viewId=$str1] received new signal icon: " + + "level=$int2 showExclamation=$bool1" + }, + ) + } + + fun logBinderReceivedNetworkTypeIcon(parentView: View, subId: Int, icon: Icon.Resource?) { + buffer.log( + TAG, + LogLevel.VERBOSE, + { + str1 = parentView.getIdForLogging() + int1 = subId + bool1 = icon != null + int2 = icon?.res ?: -1 + }, + { + "Binder[subId=$int1, viewId=$str1] received new network type icon: " + + if (bool1) "resId=$int2" else "null" + }, + ) + } +} + +private const val TAG = "VerboseMobileViewLogger" diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt index db585e68d185..5b7d45b55c5c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt @@ -36,8 +36,10 @@ import com.android.systemui.statusbar.StatusBarIconView import com.android.systemui.statusbar.StatusBarIconView.STATE_DOT import com.android.systemui.statusbar.StatusBarIconView.STATE_HIDDEN import com.android.systemui.statusbar.StatusBarIconView.STATE_ICON +import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.LocationBasedMobileViewModel import com.android.systemui.statusbar.pipeline.shared.ui.binder.ModernStatusBarViewBinding +import kotlinx.coroutines.awaitCancellation import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.launch @@ -48,6 +50,7 @@ object MobileIconBinder { fun bind( view: ViewGroup, viewModel: LocationBasedMobileViewModel, + logger: MobileViewLogger, ): ModernStatusBarViewBinding { val mobileGroupView = view.requireViewById<ViewGroup>(R.id.mobile_group) val activityContainer = view.requireViewById<View>(R.id.inout_container) @@ -70,8 +73,13 @@ object MobileIconBinder { val iconTint: MutableStateFlow<Int> = MutableStateFlow(viewModel.defaultColor) val decorTint: MutableStateFlow<Int> = MutableStateFlow(viewModel.defaultColor) + var isCollecting: Boolean = false + view.repeatWhenAttached { repeatOnLifecycle(Lifecycle.State.STARTED) { + logger.logCollectionStarted(view, viewModel) + isCollecting = true + launch { visibilityState.collect { state -> when (state) { @@ -96,6 +104,11 @@ object MobileIconBinder { // Set the icon for the triangle launch { viewModel.icon.distinctUntilChanged().collect { icon -> + viewModel.verboseLogger?.logBinderReceivedSignalIcon( + view, + viewModel.subscriptionId, + icon, + ) mobileDrawable.level = SignalDrawable.getState( icon.level, @@ -114,6 +127,11 @@ object MobileIconBinder { // Set the network type icon launch { viewModel.networkTypeIcon.distinctUntilChanged().collect { dataTypeId -> + viewModel.verboseLogger?.logBinderReceivedNetworkTypeIcon( + view, + viewModel.subscriptionId, + dataTypeId, + ) dataTypeId?.let { IconViewBinder.bind(dataTypeId, networkTypeView) } networkTypeView.visibility = if (dataTypeId != null) VISIBLE else GONE } @@ -150,6 +168,13 @@ object MobileIconBinder { } launch { decorTint.collect { tint -> dotView.setDecorColor(tint) } } + + try { + awaitCancellation() + } finally { + isCollecting = false + logger.logCollectionStopped(view, viewModel) + } } } @@ -175,6 +200,10 @@ object MobileIconBinder { } decorTint.value = newTint } + + override fun isCollecting(): Boolean { + return isCollecting + } } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt index ed9a1884a7b4..4144293d5ccd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt @@ -20,6 +20,8 @@ import android.content.Context import android.util.AttributeSet import android.view.LayoutInflater import com.android.systemui.R +import com.android.systemui.statusbar.StatusBarIconView.getVisibleStateString +import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger import com.android.systemui.statusbar.pipeline.mobile.ui.binder.MobileIconBinder import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.LocationBasedMobileViewModel import com.android.systemui.statusbar.pipeline.shared.ui.view.ModernStatusBarView @@ -31,6 +33,15 @@ class ModernStatusBarMobileView( var subId: Int = -1 + override fun toString(): String { + return "ModernStatusBarMobileView(" + + "slot='$slot', " + + "subId=$subId, " + + "isCollecting=${binding.isCollecting()}, " + + "visibleState=${getVisibleStateString(visibleState)}); " + + "viewString=${super.toString()}" + } + companion object { /** @@ -40,6 +51,7 @@ class ModernStatusBarMobileView( @JvmStatic fun constructAndBind( context: Context, + logger: MobileViewLogger, slot: String, viewModel: LocationBasedMobileViewModel, ): ModernStatusBarMobileView { @@ -48,7 +60,8 @@ class ModernStatusBarMobileView( as ModernStatusBarMobileView) .also { it.subId = viewModel.subscriptionId - it.initView(slot) { MobileIconBinder.bind(it, viewModel) } + it.initView(slot) { MobileIconBinder.bind(it, viewModel, logger) } + logger.logNewViewBinding(it, viewModel) } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileViewModel.kt index 24cd9304f8dd..f775940140cc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileViewModel.kt @@ -19,18 +19,23 @@ package com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel import android.graphics.Color import com.android.systemui.statusbar.phone.StatusBarLocation import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags +import com.android.systemui.statusbar.pipeline.mobile.ui.VerboseMobileViewLogger /** * A view model for an individual mobile icon that embeds the notion of a [StatusBarLocation]. This * allows the mobile icon to change some view parameters at different locations * * @param commonImpl for convenience, this class wraps a base interface that can provides all of the - * common implementations between locations. See [MobileIconViewModel] + * common implementations between locations. See [MobileIconViewModel] + * @property locationName the name of the location of this VM, used for logging. + * @property verboseLogger an optional logger to log extremely verbose view updates. */ abstract class LocationBasedMobileViewModel( val commonImpl: MobileIconViewModelCommon, statusBarPipelineFlags: StatusBarPipelineFlags, debugTint: Int, + val locationName: String, + val verboseLogger: VerboseMobileViewLogger?, ) : MobileIconViewModelCommon by commonImpl { val useDebugColoring: Boolean = statusBarPipelineFlags.useDebugColoring() @@ -45,11 +50,16 @@ abstract class LocationBasedMobileViewModel( fun viewModelForLocation( commonImpl: MobileIconViewModelCommon, statusBarPipelineFlags: StatusBarPipelineFlags, + verboseMobileViewLogger: VerboseMobileViewLogger, loc: StatusBarLocation, ): LocationBasedMobileViewModel = when (loc) { StatusBarLocation.HOME -> - HomeMobileIconViewModel(commonImpl, statusBarPipelineFlags) + HomeMobileIconViewModel( + commonImpl, + statusBarPipelineFlags, + verboseMobileViewLogger, + ) StatusBarLocation.KEYGUARD -> KeyguardMobileIconViewModel(commonImpl, statusBarPipelineFlags) StatusBarLocation.QS -> QsMobileIconViewModel(commonImpl, statusBarPipelineFlags) @@ -60,20 +70,41 @@ abstract class LocationBasedMobileViewModel( class HomeMobileIconViewModel( commonImpl: MobileIconViewModelCommon, statusBarPipelineFlags: StatusBarPipelineFlags, + verboseMobileViewLogger: VerboseMobileViewLogger, ) : MobileIconViewModelCommon, - LocationBasedMobileViewModel(commonImpl, statusBarPipelineFlags, debugTint = Color.CYAN) + LocationBasedMobileViewModel( + commonImpl, + statusBarPipelineFlags, + debugTint = Color.CYAN, + locationName = "Home", + verboseMobileViewLogger, + ) class QsMobileIconViewModel( commonImpl: MobileIconViewModelCommon, statusBarPipelineFlags: StatusBarPipelineFlags, ) : MobileIconViewModelCommon, - LocationBasedMobileViewModel(commonImpl, statusBarPipelineFlags, debugTint = Color.GREEN) + LocationBasedMobileViewModel( + commonImpl, + statusBarPipelineFlags, + debugTint = Color.GREEN, + locationName = "QS", + // Only do verbose logging for the Home location. + verboseLogger = null, + ) class KeyguardMobileIconViewModel( commonImpl: MobileIconViewModelCommon, statusBarPipelineFlags: StatusBarPipelineFlags, ) : MobileIconViewModelCommon, - LocationBasedMobileViewModel(commonImpl, statusBarPipelineFlags, debugTint = Color.MAGENTA) + LocationBasedMobileViewModel( + commonImpl, + statusBarPipelineFlags, + debugTint = Color.MAGENTA, + locationName = "Keyguard", + // Only do verbose logging for the Home location. + verboseLogger = null, + ) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt index 049627899eff..dbb534b24471 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt @@ -49,7 +49,7 @@ interface MobileIconViewModelCommon { val contentDescription: Flow<ContentDescription> val roaming: Flow<Boolean> /** The RAT icon (LTE, 3G, 5G, etc) to be displayed. Null if we shouldn't show anything */ - val networkTypeIcon: Flow<Icon?> + val networkTypeIcon: Flow<Icon.Resource?> val activityInVisible: Flow<Boolean> val activityOutVisible: Flow<Boolean> val activityContainerVisible: Flow<Boolean> @@ -161,7 +161,7 @@ constructor( ) .stateIn(scope, SharingStarted.WhileSubscribed(), false) - override val networkTypeIcon: Flow<Icon?> = + override val networkTypeIcon: Flow<Icon.Resource?> = combine( iconInteractor.networkTypeIconGroup, showNetworkTypeIcon, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt index 8cb52af336da..2b90065284d0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt @@ -23,6 +23,8 @@ import com.android.systemui.statusbar.phone.StatusBarLocation import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor +import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger +import com.android.systemui.statusbar.pipeline.mobile.ui.VerboseMobileViewLogger import com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernStatusBarMobileView import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants import javax.inject.Inject @@ -39,6 +41,8 @@ class MobileIconsViewModel @Inject constructor( val subscriptionIdsFlow: StateFlow<List<Int>>, + val logger: MobileViewLogger, + private val verboseLogger: VerboseMobileViewLogger, private val interactor: MobileIconsInteractor, private val airplaneModeInteractor: AirplaneModeInteractor, private val constants: ConnectivityConstants, @@ -66,6 +70,7 @@ constructor( return LocationBasedMobileViewModel.viewModelForLocation( common, statusBarPipelineFlags, + verboseLogger, location, ) } @@ -79,6 +84,8 @@ constructor( class Factory @Inject constructor( + private val logger: MobileViewLogger, + private val verboseLogger: VerboseMobileViewLogger, private val interactor: MobileIconsInteractor, private val airplaneModeInteractor: AirplaneModeInteractor, private val constants: ConnectivityConstants, @@ -88,6 +95,8 @@ constructor( fun create(subscriptionIdsFlow: StateFlow<List<Int>>): MobileIconsViewModel { return MobileIconsViewModel( subscriptionIdsFlow, + logger, + verboseLogger, interactor, airplaneModeInteractor, constants, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/LoggerHelper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/LoggerHelper.kt index 6f29e33b5a17..a96e8ff20dd4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/LoggerHelper.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/LoggerHelper.kt @@ -38,11 +38,24 @@ object LoggerHelper { int1 = network.getNetId() str1 = networkCapabilities.toString() }, - { "onCapabilitiesChanged[default=$bool1]: net=$int1 capabilities=$str1" } + { "on${if (bool1) "Default" else ""}CapabilitiesChanged: net=$int1 capabilities=$str1" } ) } - fun logOnLost(buffer: LogBuffer, tag: String, network: Network) { - buffer.log(tag, LogLevel.INFO, { int1 = network.getNetId() }, { "onLost: net=$int1" }) + fun logOnLost( + buffer: LogBuffer, + tag: String, + network: Network, + isDefaultNetworkCallback: Boolean, + ) { + buffer.log( + tag, + LogLevel.INFO, + { + int1 = network.getNetId() + bool1 = isDefaultNetworkCallback + }, + { "on${if (bool1) "Default" else ""}Lost: net=$int1" } + ) } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/ModernStatusBarViewBinding.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/ModernStatusBarViewBinding.kt index f67876b50233..81f8683411ca 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/ModernStatusBarViewBinding.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/ModernStatusBarViewBinding.kt @@ -37,4 +37,7 @@ interface ModernStatusBarViewBinding { /** Notifies that the decor tint has been updated (used only for the dot). */ fun onDecorTintChanged(newTint: Int) + + /** Returns true if the binding between the view and view-model is currently collecting. */ + fun isCollecting(): Boolean } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarView.kt index b1e28129a690..1a1340484bfc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarView.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarView.kt @@ -36,7 +36,7 @@ open class ModernStatusBarView(context: Context, attrs: AttributeSet?) : BaseStatusBarFrameLayout(context, attrs) { private lateinit var slot: String - private lateinit var binding: ModernStatusBarViewBinding + internal lateinit var binding: ModernStatusBarViewBinding @StatusBarIconView.VisibleState private var iconVisibleState: Int = STATE_HIDDEN diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcher.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcher.kt index e0e0ed795e4a..b1296179d7f7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcher.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcher.kt @@ -41,7 +41,6 @@ import kotlinx.coroutines.flow.stateIn * or the [WifiRepositoryImpl]'s prod implementation, based on the current demo mode value. In this * way, downstream clients can all consist of real implementations and not care about which * repository is responsible for the data. Graphically: - * * ``` * RealRepository * │ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt index ee58160a7d3b..b5e7b7a13505 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt @@ -128,6 +128,7 @@ constructor( } override fun onLost(network: Network) { + logger.logOnLost(network, isDefaultNetworkCallback = true) // The system no longer has a default network, so wifi is definitely not // default. trySend(false) @@ -179,7 +180,7 @@ constructor( } override fun onLost(network: Network) { - logger.logOnLost(network) + logger.logOnLost(network, isDefaultNetworkCallback = false) wifiNetworkChangeEvents.tryEmit(Unit) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiInputLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiInputLogger.kt index a32e47592355..bb0b166f7aba 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiInputLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiInputLogger.kt @@ -48,8 +48,8 @@ constructor( ) } - fun logOnLost(network: Network) { - LoggerHelper.logOnLost(buffer, TAG, network) + fun logOnLost(network: Network, isDefaultNetworkCallback: Boolean) { + LoggerHelper.logOnLost(buffer, TAG, network, isDefaultNetworkCallback) } fun logIntent(intentName: String) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/binder/WifiViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/binder/WifiViewBinder.kt index 2aff12c8721d..9e8c814ca2a9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/binder/WifiViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/binder/WifiViewBinder.kt @@ -34,6 +34,7 @@ import com.android.systemui.statusbar.pipeline.shared.ui.binder.ModernStatusBarV import com.android.systemui.statusbar.pipeline.wifi.ui.model.WifiIcon import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.LocationBasedWifiViewModel import kotlinx.coroutines.InternalCoroutinesApi +import kotlinx.coroutines.awaitCancellation import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.distinctUntilChanged @@ -74,8 +75,12 @@ object WifiViewBinder { val iconTint: MutableStateFlow<Int> = MutableStateFlow(viewModel.defaultColor) val decorTint: MutableStateFlow<Int> = MutableStateFlow(viewModel.defaultColor) + var isCollecting: Boolean = false + view.repeatWhenAttached { repeatOnLifecycle(Lifecycle.State.STARTED) { + isCollecting = true + launch { visibilityState.collect { visibilityState -> groupView.isVisible = visibilityState == STATE_ICON @@ -127,6 +132,12 @@ object WifiViewBinder { airplaneSpacer.isVisible = visible } } + + try { + awaitCancellation() + } finally { + isCollecting = false + } } } @@ -152,6 +163,10 @@ object WifiViewBinder { } decorTint.value = newTint } + + override fun isCollecting(): Boolean { + return isCollecting + } } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiView.kt index 7a734862fe1b..f23e10287164 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiView.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiView.kt @@ -21,6 +21,7 @@ import android.content.Context import android.util.AttributeSet import android.view.LayoutInflater import com.android.systemui.R +import com.android.systemui.statusbar.StatusBarIconView import com.android.systemui.statusbar.pipeline.shared.ui.view.ModernStatusBarView import com.android.systemui.statusbar.pipeline.wifi.ui.binder.WifiViewBinder import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.LocationBasedWifiViewModel @@ -33,6 +34,15 @@ class ModernStatusBarWifiView( context: Context, attrs: AttributeSet?, ) : ModernStatusBarView(context, attrs) { + + override fun toString(): String { + return "ModernStatusBarWifiView(" + + "slot='$slot', " + + "isCollecting=${binding.isCollecting()}, " + + "visibleState=${StatusBarIconView.getVisibleStateString(visibleState)}); " + + "viewString=${super.toString()}" + } + companion object { /** * Inflates a new instance of [ModernStatusBarWifiView], binds it to a view model, and @@ -45,12 +55,9 @@ class ModernStatusBarWifiView( slot: String, wifiViewModel: LocationBasedWifiViewModel, ): ModernStatusBarWifiView { - return ( - LayoutInflater.from(context).inflate(R.layout.new_status_bar_wifi_group, null) - as ModernStatusBarWifiView - ).also { - it.initView(slot) { WifiViewBinder.bind(it, wifiViewModel) } - } + return (LayoutInflater.from(context).inflate(R.layout.new_status_bar_wifi_group, null) + as ModernStatusBarWifiView) + .also { it.initView(slot) { WifiViewBinder.bind(it, wifiViewModel) } } } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java index 7acdaffb48c4..01fabcc8bc1e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java @@ -22,13 +22,18 @@ import static android.provider.Settings.Secure.DEVICE_STATE_ROTATION_LOCK_LOCKED import android.annotation.Nullable; import android.hardware.devicestate.DeviceStateManager; import android.os.Trace; -import android.util.Log; +import android.util.IndentingPrintWriter; + +import androidx.annotation.NonNull; import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager; +import com.android.systemui.Dumpable; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.dump.DumpManager; import com.android.systemui.util.wrapper.RotationPolicyWrapper; +import java.io.PrintWriter; import java.util.concurrent.Executor; import javax.inject.Inject; @@ -39,19 +44,19 @@ import javax.inject.Inject; */ @SysUISingleton public final class DeviceStateRotationLockSettingController - implements Listenable, RotationLockController.RotationLockControllerCallback { - - private static final String TAG = "DSRotateLockSettingCon"; + implements Listenable, RotationLockController.RotationLockControllerCallback, Dumpable { private final RotationPolicyWrapper mRotationPolicyWrapper; private final DeviceStateManager mDeviceStateManager; private final Executor mMainExecutor; private final DeviceStateRotationLockSettingsManager mDeviceStateRotationLockSettingsManager; + private final DeviceStateRotationLockSettingControllerLogger mLogger; // On registration for DeviceStateCallback, we will receive a callback with the current state // and this will be initialized. private int mDeviceState = -1; - @Nullable private DeviceStateManager.DeviceStateCallback mDeviceStateCallback; + @Nullable + private DeviceStateManager.DeviceStateCallback mDeviceStateCallback; private DeviceStateRotationLockSettingsManager.DeviceStateRotationLockSettingsListener mDeviceStateRotationLockSettingsListener; @@ -60,21 +65,27 @@ public final class DeviceStateRotationLockSettingController RotationPolicyWrapper rotationPolicyWrapper, DeviceStateManager deviceStateManager, @Main Executor executor, - DeviceStateRotationLockSettingsManager deviceStateRotationLockSettingsManager) { + DeviceStateRotationLockSettingsManager deviceStateRotationLockSettingsManager, + DeviceStateRotationLockSettingControllerLogger logger, + DumpManager dumpManager) { mRotationPolicyWrapper = rotationPolicyWrapper; mDeviceStateManager = deviceStateManager; mMainExecutor = executor; mDeviceStateRotationLockSettingsManager = deviceStateRotationLockSettingsManager; + mLogger = logger; + dumpManager.registerDumpable(this); } @Override public void setListening(boolean listening) { + mLogger.logListeningChange(listening); if (listening) { // Note that this is called once with the initial state of the device, even if there // is no user action. mDeviceStateCallback = this::updateDeviceState; mDeviceStateManager.registerCallback(mMainExecutor, mDeviceStateCallback); - mDeviceStateRotationLockSettingsListener = () -> readPersistedSetting(mDeviceState); + mDeviceStateRotationLockSettingsListener = () -> + readPersistedSetting("deviceStateRotationLockChange", mDeviceState); mDeviceStateRotationLockSettingsManager.registerListener( mDeviceStateRotationLockSettingsListener); } else { @@ -89,35 +100,28 @@ public final class DeviceStateRotationLockSettingController } @Override - public void onRotationLockStateChanged(boolean rotationLocked, boolean affordanceVisible) { - if (mDeviceState == -1) { - Log.wtf(TAG, "Device state was not initialized."); + public void onRotationLockStateChanged(boolean newRotationLocked, boolean affordanceVisible) { + int deviceState = mDeviceState; + boolean currentRotationLocked = mDeviceStateRotationLockSettingsManager + .isRotationLocked(deviceState); + mLogger.logRotationLockStateChanged(deviceState, newRotationLocked, currentRotationLocked); + if (deviceState == -1) { return; } - - if (rotationLocked - == mDeviceStateRotationLockSettingsManager.isRotationLocked(mDeviceState)) { - Log.v(TAG, "Rotation lock same as the current setting, no need to update."); + if (newRotationLocked == currentRotationLocked) { return; } - - saveNewRotationLockSetting(rotationLocked); + saveNewRotationLockSetting(newRotationLocked); } private void saveNewRotationLockSetting(boolean isRotationLocked) { - Log.v( - TAG, - "saveNewRotationLockSetting [state=" - + mDeviceState - + "] [isRotationLocked=" - + isRotationLocked - + "]"); - - mDeviceStateRotationLockSettingsManager.updateSetting(mDeviceState, isRotationLocked); + int deviceState = mDeviceState; + mLogger.logSaveNewRotationLockSetting(isRotationLocked, deviceState); + mDeviceStateRotationLockSettingsManager.updateSetting(deviceState, isRotationLocked); } private void updateDeviceState(int state) { - Log.v(TAG, "updateDeviceState [state=" + state + "]"); + mLogger.logUpdateDeviceState(mDeviceState, state); if (Trace.isEnabled()) { Trace.traceBegin( Trace.TRACE_TAG_APP, "updateDeviceState [state=" + state + "]"); @@ -127,22 +131,26 @@ public final class DeviceStateRotationLockSettingController return; } - readPersistedSetting(state); + readPersistedSetting("updateDeviceState", state); } finally { Trace.endSection(); } } - private void readPersistedSetting(int state) { + private void readPersistedSetting(String caller, int state) { int rotationLockSetting = mDeviceStateRotationLockSettingsManager.getRotationLockSetting(state); + boolean shouldBeLocked = rotationLockSetting == DEVICE_STATE_ROTATION_LOCK_LOCKED; + boolean isLocked = mRotationPolicyWrapper.isRotationLocked(); + + mLogger.readPersistedSetting(caller, state, rotationLockSetting, shouldBeLocked, isLocked); + if (rotationLockSetting == DEVICE_STATE_ROTATION_LOCK_IGNORED) { // This should not happen. Device states that have an ignored setting, should also // specify a fallback device state which is not ignored. // We won't handle this device state. The same rotation lock setting as before should // apply and any changes to the rotation lock setting will be written for the previous // valid device state. - Log.w(TAG, "Missing fallback. Ignoring new device state: " + state); return; } @@ -150,9 +158,18 @@ public final class DeviceStateRotationLockSettingController mDeviceState = state; // Update the rotation policy, if needed, for this new device state - boolean newRotationLockSetting = rotationLockSetting == DEVICE_STATE_ROTATION_LOCK_LOCKED; - if (newRotationLockSetting != mRotationPolicyWrapper.isRotationLocked()) { - mRotationPolicyWrapper.setRotationLock(newRotationLockSetting); + if (shouldBeLocked != isLocked) { + mRotationPolicyWrapper.setRotationLock(shouldBeLocked); } } + + @Override + public void dump(@NonNull PrintWriter printWriter, @NonNull String[] args) { + IndentingPrintWriter pw = new IndentingPrintWriter(printWriter); + mDeviceStateRotationLockSettingsManager.dump(pw); + pw.println("DeviceStateRotationLockSettingController"); + pw.increaseIndent(); + pw.println("mDeviceState: " + mDeviceState); + pw.decreaseIndent(); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerLogger.kt new file mode 100644 index 000000000000..aa502bc48149 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerLogger.kt @@ -0,0 +1,140 @@ +/* + * 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.systemui.statusbar.policy + +import android.content.Context +import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_LOCK_IGNORED +import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_LOCK_LOCKED +import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_LOCK_UNLOCKED +import com.android.internal.R +import com.android.systemui.log.dagger.DeviceStateAutoRotationLog +import com.android.systemui.plugins.log.LogBuffer +import com.android.systemui.plugins.log.LogLevel.VERBOSE +import javax.inject.Inject + +class DeviceStateRotationLockSettingControllerLogger +@Inject +constructor(@DeviceStateAutoRotationLog private val logBuffer: LogBuffer, context: Context) { + + private val foldedStates = context.resources.getIntArray(R.array.config_foldedDeviceStates) + private val halfFoldedStates = + context.resources.getIntArray(R.array.config_halfFoldedDeviceStates) + private val unfoldedStates = context.resources.getIntArray(R.array.config_openDeviceStates) + + fun logListeningChange(listening: Boolean) { + logBuffer.log(TAG, VERBOSE, { bool1 = listening }, { "setListening: $bool1" }) + } + + fun logRotationLockStateChanged( + state: Int, + newRotationLocked: Boolean, + currentRotationLocked: Boolean + ) { + logBuffer.log( + TAG, + VERBOSE, + { + int1 = state + bool1 = newRotationLocked + bool2 = currentRotationLocked + }, + { + "onRotationLockStateChanged: " + + "state=$int1 [${int1.toDevicePostureString()}], " + + "newRotationLocked=$bool1, " + + "currentRotationLocked=$bool2" + } + ) + } + + fun logSaveNewRotationLockSetting(isRotationLocked: Boolean, state: Int) { + logBuffer.log( + TAG, + VERBOSE, + { + bool1 = isRotationLocked + int1 = state + }, + { "saveNewRotationLockSetting: isRotationLocked=$bool1, state=$int1" } + ) + } + + fun logUpdateDeviceState(currentState: Int, newState: Int) { + logBuffer.log( + TAG, + VERBOSE, + { + int1 = currentState + int2 = newState + }, + { + "updateDeviceState: " + + "current=$int1 [${int1.toDevicePostureString()}], " + + "new=$int2 [${int2.toDevicePostureString()}]" + } + ) + } + + fun readPersistedSetting( + caller: String, + state: Int, + rotationLockSetting: Int, + shouldBeLocked: Boolean, + isLocked: Boolean + ) { + logBuffer.log( + TAG, + VERBOSE, + { + str1 = caller + int1 = state + int2 = rotationLockSetting + bool1 = shouldBeLocked + bool2 = isLocked + }, + { + "readPersistedSetting: " + + "caller=$str1, " + + "state=$int1 [${int1.toDevicePostureString()}], " + + "rotationLockSettingForState: ${int2.toRotationLockSettingString()}, " + + "shouldBeLocked=$bool1, " + + "isLocked=$bool2" + } + ) + } + + private fun Int.toDevicePostureString(): String { + return when (this) { + in foldedStates -> "Folded" + in unfoldedStates -> "Unfolded" + in halfFoldedStates -> "Half-Folded" + -1 -> "Uninitialized" + else -> "Unknown" + } + } +} + +private fun Int.toRotationLockSettingString(): String { + return when (this) { + DEVICE_STATE_ROTATION_LOCK_IGNORED -> "IGNORED" + DEVICE_STATE_ROTATION_LOCK_LOCKED -> "LOCKED" + DEVICE_STATE_ROTATION_LOCK_UNLOCKED -> "UNLOCKED" + else -> "Unknown" + } +} + +private const val TAG = "DSRotateLockSettingCon" diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.kt index bdb656b9d2d5..1e223b1920ed 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.kt @@ -146,7 +146,7 @@ constructor( * * @param guestUserId id of the guest user to remove * @param targetUserId id of the user to switch to after guest is removed. If - * `UserHandle.USER_NULL`, then switch immediately to the newly created guest user. + * `UserHandle.USER_NULL`, then switch immediately to the newly created guest user. */ fun removeGuestUser(guestUserId: Int, targetUserId: Int) { userInteractor.removeGuestUser( @@ -160,9 +160,9 @@ constructor( * * @param guestUserId user id of the guest user to exit * @param targetUserId user id of the guest user to exit, set to UserHandle#USER_NULL when - * target user id is not known + * target user id is not known * @param forceRemoveGuestOnExit true: remove guest before switching user, false: remove guest - * only if its ephemeral, else keep guest + * only if its ephemeral, else keep guest */ fun exitGuestUser(guestUserId: Int, targetUserId: Int, forceRemoveGuestOnExit: Boolean) { userInteractor.exitGuestUser(guestUserId, targetUserId, forceRemoveGuestOnExit) diff --git a/packages/SystemUI/src/com/android/systemui/telephony/ui/activity/SwitchToManagedProfileForCallActivity.kt b/packages/SystemUI/src/com/android/systemui/telephony/ui/activity/SwitchToManagedProfileForCallActivity.kt index e092f01d19f6..8e2b05cd9526 100644 --- a/packages/SystemUI/src/com/android/systemui/telephony/ui/activity/SwitchToManagedProfileForCallActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/telephony/ui/activity/SwitchToManagedProfileForCallActivity.kt @@ -66,7 +66,7 @@ class SwitchToManagedProfileForCallActivity : AlertActivity(), DialogInterface.O private fun switchToManagedProfile() { try { applicationContext.startActivityAsUser( - Intent(Intent.ACTION_DIAL, phoneNumber), + Intent(Intent.ACTION_CALL, phoneNumber), ActivityOptions.makeOpenCrossProfileAppsAnimation().toBundle(), UserHandle.of(managedProfileUserId) ) diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TouchableRegionViewController.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TouchableRegionViewController.kt index 60241a9684d9..cf0184f9e1ae 100644 --- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TouchableRegionViewController.kt +++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TouchableRegionViewController.kt @@ -27,7 +27,7 @@ import com.android.systemui.util.ViewController * pass through to the window below. * * @param touchableRegionSetter a function that, given the view and an out rect, fills the rect with - * the touchable region of this view. + * the touchable region of this view. */ class TouchableRegionViewController( view: View, diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarAnimator.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarAnimator.kt index 01a81deabc95..16123882046c 100644 --- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarAnimator.kt +++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarAnimator.kt @@ -35,7 +35,7 @@ open class ChipbarAnimator @Inject constructor() { * Animates [innerView] and its children into view. * * @return true if the animation was successfully started and false if the animation can't be - * run for any reason. + * run for any reason. * * See [ViewHierarchyAnimator.animateAddition]. */ @@ -55,7 +55,7 @@ open class ChipbarAnimator @Inject constructor() { * Animates [innerView] and its children out of view. * * @return true if the animation was successfully started and false if the animation can't be - * run for any reason. + * run for any reason. * * See [ViewHierarchyAnimator.animateRemoval]. */ diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarInfo.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarInfo.kt index fe46318daa30..125cc761d400 100644 --- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarInfo.kt +++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarInfo.kt @@ -28,10 +28,10 @@ import com.android.systemui.temporarydisplay.ViewPriority * A container for all the state needed to display a chipbar via [ChipbarCoordinator]. * * @property startIcon the icon to display at the start of the chipbar (on the left in LTR locales; - * on the right in RTL locales). + * on the right in RTL locales). * @property text the text to display. * @property endItem an optional end item to display at the end of the chipbar (on the right in LTR - * locales; on the left in RTL locales). + * locales; on the left in RTL locales). * @property vibrationEffect an optional vibration effect when the chipbar is displayed * @property allowSwipeToDismiss true if users are allowed to swipe up to dismiss this chipbar. */ diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java index d5d3efd78d13..3a7ac9c8a8bd 100644 --- a/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java +++ b/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java @@ -31,6 +31,9 @@ import android.view.WindowManager; import com.android.internal.app.AlertActivity; import com.android.internal.app.AlertController; import com.android.systemui.R; +import com.android.systemui.statusbar.policy.DeviceProvisionedController; + +import javax.inject.Inject; /** * If the attached USB accessory has a URL associated with it, and that URL is valid, @@ -46,13 +49,27 @@ public class UsbAccessoryUriActivity extends AlertActivity private UsbAccessory mAccessory; private Uri mUri; + private final DeviceProvisionedController mDeviceProvisionedController; + + @Inject + UsbAccessoryUriActivity(DeviceProvisionedController deviceProvisionedController) { + mDeviceProvisionedController = deviceProvisionedController; + } + @Override public void onCreate(Bundle icicle) { - getWindow().addSystemFlags( + getWindow().addSystemFlags( WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS); - super.onCreate(icicle); + super.onCreate(icicle); + + // Don't show this dialog during Setup Wizard + if (!mDeviceProvisionedController.isDeviceProvisioned()) { + Log.e(TAG, "device not provisioned"); + finish(); + return; + } - Intent intent = getIntent(); + Intent intent = getIntent(); mAccessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY); String uriString = intent.getStringExtra("uri"); mUri = (uriString == null ? null : Uri.parse(uriString)); diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/GuestUserInteractor.kt b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/GuestUserInteractor.kt index 208061433325..42cd5bca376d 100644 --- a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/GuestUserInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/GuestUserInteractor.kt @@ -297,7 +297,7 @@ constructor( * to create a new one. * * @return The multi-user user ID of the newly created guest user, or [UserHandle.USER_NULL] if - * the guest couldn't be created. + * the guest couldn't be created. */ @UserIdInt private suspend fun createInBackground(): Int { diff --git a/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java b/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java index 81ae6e851fb9..c72853ef37be 100644 --- a/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java +++ b/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java @@ -115,6 +115,17 @@ public abstract class SysUIConcurrencyModule { } /** + * Provide a Long running Executor. + */ + @Provides + @SysUISingleton + @LongRunning + public static DelayableExecutor provideLongRunningDelayableExecutor( + @LongRunning Looper looper) { + return new ExecutorImpl(looper); + } + + /** * Provide a Background-Thread Executor. */ @Provides diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java index 8b925b7ad312..b962148b79dc 100644 --- a/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java +++ b/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java @@ -35,7 +35,7 @@ import android.view.WindowManager; import androidx.annotation.NonNull; import com.android.internal.annotations.VisibleForTesting; -import com.android.systemui.dagger.qualifiers.Background; +import com.android.systemui.dagger.qualifiers.LongRunning; import com.android.systemui.settings.UserTracker; import com.android.systemui.util.concurrency.DelayableExecutor; @@ -61,17 +61,16 @@ public class ImageWallpaper extends WallpaperService { private final UserTracker mUserTracker; // used for most tasks (call canvas.drawBitmap, load/unload the bitmap) - @Background - private final DelayableExecutor mBackgroundExecutor; + @LongRunning + private final DelayableExecutor mLongExecutor; // wait at least this duration before unloading the bitmap private static final int DELAY_UNLOAD_BITMAP = 2000; @Inject - public ImageWallpaper(@Background DelayableExecutor backgroundExecutor, - UserTracker userTracker) { + public ImageWallpaper(@LongRunning DelayableExecutor longExecutor, UserTracker userTracker) { super(); - mBackgroundExecutor = backgroundExecutor; + mLongExecutor = longExecutor; mUserTracker = userTracker; } @@ -105,7 +104,7 @@ public class ImageWallpaper extends WallpaperService { setFixedSizeAllowed(true); setShowForAllUsers(true); mWallpaperLocalColorExtractor = new WallpaperLocalColorExtractor( - mBackgroundExecutor, + mLongExecutor, new WallpaperLocalColorExtractor.WallpaperLocalColorExtractorCallback() { @Override public void onColorsProcessed(List<RectF> regions, @@ -202,7 +201,7 @@ public class ImageWallpaper extends WallpaperService { } private void drawFrame() { - mBackgroundExecutor.execute(this::drawFrameSynchronized); + mLongExecutor.execute(this::drawFrameSynchronized); } private void drawFrameSynchronized() { @@ -257,7 +256,7 @@ public class ImageWallpaper extends WallpaperService { } private void unloadBitmapIfNotUsed() { - mBackgroundExecutor.execute(this::unloadBitmapIfNotUsedSynchronized); + mLongExecutor.execute(this::unloadBitmapIfNotUsedSynchronized); } private void unloadBitmapIfNotUsedSynchronized() { @@ -341,7 +340,7 @@ public class ImageWallpaper extends WallpaperService { * - the mini bitmap from color extractor is recomputed * - the DELAY_UNLOAD_BITMAP has passed */ - mBackgroundExecutor.executeDelayed( + mLongExecutor.executeDelayed( this::unloadBitmapIfNotUsedSynchronized, DELAY_UNLOAD_BITMAP); } // even if the bitmap cannot be loaded, call reportEngineShown diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/WallpaperLocalColorExtractor.java b/packages/SystemUI/src/com/android/systemui/wallpapers/WallpaperLocalColorExtractor.java index 988fd710d2dc..1e8446f8df1d 100644 --- a/packages/SystemUI/src/com/android/systemui/wallpapers/WallpaperLocalColorExtractor.java +++ b/packages/SystemUI/src/com/android/systemui/wallpapers/WallpaperLocalColorExtractor.java @@ -29,7 +29,7 @@ import android.util.MathUtils; import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; -import com.android.systemui.dagger.qualifiers.Background; +import com.android.systemui.dagger.qualifiers.LongRunning; import com.android.systemui.util.Assert; import java.io.FileDescriptor; @@ -66,8 +66,8 @@ public class WallpaperLocalColorExtractor { private final List<RectF> mPendingRegions = new ArrayList<>(); private final Set<RectF> mProcessedRegions = new ArraySet<>(); - @Background - private final Executor mBackgroundExecutor; + @LongRunning + private final Executor mLongExecutor; private final WallpaperLocalColorExtractorCallback mWallpaperLocalColorExtractorCallback; @@ -101,13 +101,13 @@ public class WallpaperLocalColorExtractor { /** * Creates a new color extractor. - * @param backgroundExecutor the executor on which the color extraction will be performed + * @param longExecutor the executor on which the color extraction will be performed * @param wallpaperLocalColorExtractorCallback an interface to handle the callbacks from * the color extractor. */ - public WallpaperLocalColorExtractor(@Background Executor backgroundExecutor, + public WallpaperLocalColorExtractor(@LongRunning Executor longExecutor, WallpaperLocalColorExtractorCallback wallpaperLocalColorExtractorCallback) { - mBackgroundExecutor = backgroundExecutor; + mLongExecutor = longExecutor; mWallpaperLocalColorExtractorCallback = wallpaperLocalColorExtractorCallback; } @@ -117,7 +117,7 @@ public class WallpaperLocalColorExtractor { * not recomputed. */ public void setDisplayDimensions(int displayWidth, int displayHeight) { - mBackgroundExecutor.execute(() -> + mLongExecutor.execute(() -> setDisplayDimensionsSynchronized(displayWidth, displayHeight)); } @@ -144,7 +144,7 @@ public class WallpaperLocalColorExtractor { * @param bitmap the new wallpaper */ public void onBitmapChanged(@NonNull Bitmap bitmap) { - mBackgroundExecutor.execute(() -> onBitmapChangedSynchronized(bitmap)); + mLongExecutor.execute(() -> onBitmapChangedSynchronized(bitmap)); } private void onBitmapChangedSynchronized(@NonNull Bitmap bitmap) { @@ -167,7 +167,7 @@ public class WallpaperLocalColorExtractor { * @param pages the total number of pages of the launcher */ public void onPageChanged(int pages) { - mBackgroundExecutor.execute(() -> onPageChangedSynchronized(pages)); + mLongExecutor.execute(() -> onPageChangedSynchronized(pages)); } private void onPageChangedSynchronized(int pages) { @@ -194,7 +194,7 @@ public class WallpaperLocalColorExtractor { */ public void addLocalColorsAreas(@NonNull List<RectF> regions) { if (regions.size() > 0) { - mBackgroundExecutor.execute(() -> addLocalColorsAreasSynchronized(regions)); + mLongExecutor.execute(() -> addLocalColorsAreasSynchronized(regions)); } else { Log.w(TAG, "Attempt to add colors with an empty list"); } @@ -218,7 +218,7 @@ public class WallpaperLocalColorExtractor { * @param regions The areas of interest in our wallpaper (in screen pixel coordinates) */ public void removeLocalColorAreas(@NonNull List<RectF> regions) { - mBackgroundExecutor.execute(() -> removeLocalColorAreasSynchronized(regions)); + mLongExecutor.execute(() -> removeLocalColorAreasSynchronized(regions)); } private void removeLocalColorAreasSynchronized(@NonNull List<RectF> regions) { @@ -236,7 +236,7 @@ public class WallpaperLocalColorExtractor { * Clean up the memory (in particular, the mini bitmap) used by this class. */ public void cleanUp() { - mBackgroundExecutor.execute(this::cleanUpSynchronized); + mLongExecutor.execute(this::cleanUpSynchronized); } private void cleanUpSynchronized() { diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java index 5d896cbbdab4..56df3e114c0b 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java @@ -25,7 +25,6 @@ import static android.service.notification.NotificationListenerService.REASON_GR import static android.service.notification.NotificationStats.DISMISSAL_BUBBLE; import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL; -import static com.android.systemui.flags.Flags.WM_BUBBLE_BAR; import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES; import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME; @@ -358,7 +357,6 @@ public class BubblesManager { }); } }; - mBubbles.setBubbleBarEnabled(featureFlags.isEnabled(WM_BUBBLE_BAR)); mBubbles.setSysuiProxy(mSysuiProxy); } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java index 1bbc19931c21..531006da8210 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java @@ -37,6 +37,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -160,6 +161,29 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase { } @Test + public void testOnApplyWindowInsets_disappearAnimation_paddingNotSet() { + int paddingBottom = getContext().getResources() + .getDimensionPixelSize(R.dimen.keyguard_security_view_bottom_margin); + int imeInsetAmount = paddingBottom + 1; + int systemBarInsetAmount = 0; + initMode(MODE_DEFAULT); + + Insets imeInset = Insets.of(0, 0, 0, imeInsetAmount); + Insets systemBarInset = Insets.of(0, 0, 0, systemBarInsetAmount); + + WindowInsets insets = new WindowInsets.Builder() + .setInsets(ime(), imeInset) + .setInsetsIgnoringVisibility(systemBars(), systemBarInset) + .build(); + + ensureViewFlipperIsMocked(); + mKeyguardSecurityContainer.startDisappearAnimation( + KeyguardSecurityModel.SecurityMode.Password); + mKeyguardSecurityContainer.onApplyWindowInsets(insets); + assertThat(mKeyguardSecurityContainer.getPaddingBottom()).isNotEqualTo(imeInsetAmount); + } + + @Test public void testDefaultViewMode() { initMode(MODE_ONE_HANDED); initMode(MODE_DEFAULT); @@ -376,6 +400,17 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase { assertThat(mKeyguardSecurityContainer.getScaleY()).isEqualTo(1); } + @Test + public void testDisappearAnimationPassword() { + ensureViewFlipperIsMocked(); + KeyguardPasswordView keyguardPasswordView = mock(KeyguardPasswordView.class); + when(mSecurityViewFlipper.getSecurityView()).thenReturn(keyguardPasswordView); + + mKeyguardSecurityContainer + .startDisappearAnimation(KeyguardSecurityModel.SecurityMode.Password); + verify(keyguardPasswordView).setDisappearAnimationListener(any()); + } + private BackEvent createBackEvent(float touchX, float progress) { return new BackEvent(0, 0, progress, BackEvent.EDGE_LEFT); } @@ -446,4 +481,12 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase { mUserSwitcherController, () -> { }, mFalsingA11yDelegate); } + + private void ensureViewFlipperIsMocked() { + mSecurityViewFlipper = mock(KeyguardSecurityViewFlipper.class); + KeyguardPasswordView keyguardPasswordView = mock(KeyguardPasswordView.class); + when(mSecurityViewFlipper.getSecurityView()).thenReturn(keyguardPasswordView); + mKeyguardSecurityContainer.mSecurityViewFlipper = mSecurityViewFlipper; + } + } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java index 3c80dad2bd82..4c92eddd66fb 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java @@ -17,7 +17,6 @@ package com.android.keyguard; import static android.app.StatusBarManager.SESSION_KEYGUARD; -import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_LOCKOUT_TIMED; import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_LOCKOUT; import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_LOCKOUT_PERMANENT; import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_POWER_BUTTON; @@ -2200,6 +2199,32 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } @Test + public void testPostureChangeToUnsupported_stopsFaceListeningState() { + // GIVEN device is listening for face + mKeyguardUpdateMonitor.mConfigFaceAuthSupportedPosture = DEVICE_POSTURE_CLOSED; + deviceInPostureStateClosed(); + mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON); + mTestableLooper.processAllMessages(); + keyguardIsVisible(); + + verifyFaceAuthenticateCall(); + + final CancellationSignal faceCancel = spy(mKeyguardUpdateMonitor.mFaceCancelSignal); + mKeyguardUpdateMonitor.mFaceCancelSignal = faceCancel; + KeyguardUpdateMonitorCallback callback = mock(KeyguardUpdateMonitorCallback.class); + mKeyguardUpdateMonitor.registerCallback(callback); + + // WHEN device is opened + deviceInPostureStateOpened(); + mTestableLooper.processAllMessages(); + + // THEN face listening is stopped. + verify(faceCancel).cancel(); + verify(callback).onBiometricRunningStateChanged( + eq(false), eq(BiometricSourceType.FACE)); + } + + @Test public void testShouldListenForFace_withLockedDown_returnsFalse() throws RemoteException { keyguardNotGoingAway(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt index b765ab3c5eac..a245c01d74de 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt @@ -25,7 +25,9 @@ import androidx.test.filters.SmallTest import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession import com.android.keyguard.KeyguardUpdateMonitor import com.android.keyguard.KeyguardUpdateMonitorCallback +import com.android.keyguard.logging.KeyguardLogger import com.android.systemui.SysuiTestCase +import com.android.systemui.dump.logcatLogBuffer import com.android.systemui.flags.FeatureFlags import com.android.systemui.keyguard.WakefulnessLifecycle import com.android.systemui.plugins.statusbar.StatusBarStateController @@ -109,6 +111,7 @@ class AuthRippleControllerTest : SysuiTestCase() { udfpsControllerProvider, statusBarStateController, featureFlags, + KeyguardLogger(logcatLogBuffer(AuthRippleController.TAG)), rippleView ) controller.init() diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt index 6333a68bb5e0..3ec49b263c54 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt @@ -354,7 +354,9 @@ class SideFpsControllerTest : SysuiTestCase() { deviceConfig = DeviceConfig.X_ALIGNED, isReverseDefaultRotation = false, { rotation = Surface.ROTATION_0 } - ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) } + ) { + verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) + } @Test fun showsSfpsIndicatorWithTaskbarForXAlignedSensor_90() = @@ -362,7 +364,9 @@ class SideFpsControllerTest : SysuiTestCase() { deviceConfig = DeviceConfig.X_ALIGNED, isReverseDefaultRotation = false, { rotation = Surface.ROTATION_90 } - ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) } + ) { + verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) + } @Test fun showsSfpsIndicatorWithTaskbarForXAlignedSensor_180() = @@ -370,7 +374,9 @@ class SideFpsControllerTest : SysuiTestCase() { deviceConfig = DeviceConfig.X_ALIGNED, isReverseDefaultRotation = false, { rotation = Surface.ROTATION_180 } - ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) } + ) { + verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) + } @Test fun showsSfpsIndicatorWithTaskbarCollapsedDownForXAlignedSensor_180() = @@ -379,7 +385,9 @@ class SideFpsControllerTest : SysuiTestCase() { isReverseDefaultRotation = false, { rotation = Surface.ROTATION_180 }, windowInsets = insetsForSmallNavbar() - ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) } + ) { + verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) + } @Test fun hidesSfpsIndicatorWhenOccludingTaskbarForXAlignedSensor_180() = @@ -388,7 +396,9 @@ class SideFpsControllerTest : SysuiTestCase() { isReverseDefaultRotation = false, { rotation = Surface.ROTATION_180 }, windowInsets = insetsForLargeNavbar() - ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = false) } + ) { + verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = false) + } @Test fun showsSfpsIndicatorWithTaskbarForXAlignedSensor_270() = @@ -396,7 +406,9 @@ class SideFpsControllerTest : SysuiTestCase() { deviceConfig = DeviceConfig.X_ALIGNED, isReverseDefaultRotation = false, { rotation = Surface.ROTATION_270 } - ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) } + ) { + verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) + } @Test fun showsSfpsIndicatorWithTaskbarForXAlignedSensor_InReverseDefaultRotation_0() = @@ -404,7 +416,9 @@ class SideFpsControllerTest : SysuiTestCase() { deviceConfig = DeviceConfig.X_ALIGNED, isReverseDefaultRotation = true, { rotation = Surface.ROTATION_0 } - ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) } + ) { + verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) + } @Test fun showsSfpsIndicatorWithTaskbarForXAlignedSensor_InReverseDefaultRotation_90() = @@ -412,7 +426,9 @@ class SideFpsControllerTest : SysuiTestCase() { deviceConfig = DeviceConfig.X_ALIGNED, isReverseDefaultRotation = true, { rotation = Surface.ROTATION_90 } - ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) } + ) { + verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) + } @Test fun showsSfpsIndicatorWithTaskbarCollapsedDownForXAlignedSensor_InReverseDefaultRotation_90() = @@ -421,7 +437,9 @@ class SideFpsControllerTest : SysuiTestCase() { isReverseDefaultRotation = true, { rotation = Surface.ROTATION_90 }, windowInsets = insetsForSmallNavbar() - ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) } + ) { + verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) + } @Test fun hidesSfpsIndicatorWhenOccludingTaskbarForXAlignedSensor_InReverseDefaultRotation_90() = @@ -430,7 +448,9 @@ class SideFpsControllerTest : SysuiTestCase() { isReverseDefaultRotation = true, { rotation = Surface.ROTATION_90 }, windowInsets = insetsForLargeNavbar() - ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = false) } + ) { + verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = false) + } @Test fun showsSfpsIndicatorWithTaskbarForXAlignedSensor_InReverseDefaultRotation_180() = @@ -438,7 +458,9 @@ class SideFpsControllerTest : SysuiTestCase() { deviceConfig = DeviceConfig.X_ALIGNED, isReverseDefaultRotation = true, { rotation = Surface.ROTATION_180 } - ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) } + ) { + verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) + } @Test fun showsSfpsIndicatorWithTaskbarForXAlignedSensor_InReverseDefaultRotation_270() = @@ -446,7 +468,9 @@ class SideFpsControllerTest : SysuiTestCase() { deviceConfig = DeviceConfig.X_ALIGNED, isReverseDefaultRotation = true, { rotation = Surface.ROTATION_270 } - ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) } + ) { + verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) + } @Test fun showsSfpsIndicatorWithTaskbarForYAlignedSensor_0() = @@ -454,7 +478,9 @@ class SideFpsControllerTest : SysuiTestCase() { deviceConfig = DeviceConfig.Y_ALIGNED, isReverseDefaultRotation = false, { rotation = Surface.ROTATION_0 } - ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) } + ) { + verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) + } @Test fun showsSfpsIndicatorWithTaskbarForYAlignedSensor_90() = @@ -462,7 +488,9 @@ class SideFpsControllerTest : SysuiTestCase() { deviceConfig = DeviceConfig.Y_ALIGNED, isReverseDefaultRotation = false, { rotation = Surface.ROTATION_90 } - ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) } + ) { + verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) + } @Test fun showsSfpsIndicatorWithTaskbarForYAlignedSensor_180() = @@ -480,7 +508,9 @@ class SideFpsControllerTest : SysuiTestCase() { deviceConfig = DeviceConfig.Y_ALIGNED, isReverseDefaultRotation = false, { rotation = Surface.ROTATION_270 } - ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) } + ) { + verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) + } @Test fun showsSfpsIndicatorWithTaskbarCollapsedDownForYAlignedSensor_270() = @@ -489,7 +519,9 @@ class SideFpsControllerTest : SysuiTestCase() { isReverseDefaultRotation = false, { rotation = Surface.ROTATION_270 }, windowInsets = insetsForSmallNavbar() - ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) } + ) { + verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) + } @Test fun hidesSfpsIndicatorWhenOccludingTaskbarForYAlignedSensor_270() = @@ -498,7 +530,9 @@ class SideFpsControllerTest : SysuiTestCase() { isReverseDefaultRotation = false, { rotation = Surface.ROTATION_270 }, windowInsets = insetsForLargeNavbar() - ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = false) } + ) { + verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = false) + } @Test fun showsSfpsIndicatorWithTaskbarForYAlignedSensor_InReverseDefaultRotation_0() = @@ -506,7 +540,9 @@ class SideFpsControllerTest : SysuiTestCase() { deviceConfig = DeviceConfig.Y_ALIGNED, isReverseDefaultRotation = true, { rotation = Surface.ROTATION_0 } - ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) } + ) { + verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) + } @Test fun showsSfpsIndicatorWithTaskbarForYAlignedSensor_InReverseDefaultRotation_90() = @@ -524,7 +560,9 @@ class SideFpsControllerTest : SysuiTestCase() { deviceConfig = DeviceConfig.Y_ALIGNED, isReverseDefaultRotation = true, { rotation = Surface.ROTATION_180 } - ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) } + ) { + verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) + } @Test fun showsSfpsIndicatorWithTaskbarCollapsedDownForYAlignedSensor_InReverseDefaultRotation_180() = @@ -533,7 +571,9 @@ class SideFpsControllerTest : SysuiTestCase() { isReverseDefaultRotation = true, { rotation = Surface.ROTATION_180 }, windowInsets = insetsForSmallNavbar() - ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) } + ) { + verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) + } @Test fun hidesSfpsIndicatorWhenOccludingTaskbarForYAlignedSensor_InReverseDefaultRotation_180() = @@ -542,7 +582,9 @@ class SideFpsControllerTest : SysuiTestCase() { isReverseDefaultRotation = true, { rotation = Surface.ROTATION_180 }, windowInsets = insetsForLargeNavbar() - ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = false) } + ) { + verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = false) + } @Test fun showsSfpsIndicatorWithTaskbarForYAlignedSensor_InReverseDefaultRotation_270() = @@ -550,7 +592,9 @@ class SideFpsControllerTest : SysuiTestCase() { deviceConfig = DeviceConfig.Y_ALIGNED, isReverseDefaultRotation = true, { rotation = Surface.ROTATION_270 } - ) { verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) } + ) { + verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible = true) + } @Test fun verifiesSfpsIndicatorNotAddedInRearDisplayMode_0() = diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/BroadcastDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/BroadcastDialogTest.java index 35039026fe9e..9d16185e75c5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/BroadcastDialogTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/BroadcastDialogTest.java @@ -45,8 +45,8 @@ import org.mockito.MockitoAnnotations; public class BroadcastDialogTest extends SysuiTestCase { private static final String CURRENT_BROADCAST_APP = "Music"; - private static final String SWITCH_APP = "Files by Google"; - private static final String TEST_PACKAGE = "com.google.android.apps.nbu.files"; + private static final String SWITCH_APP = "System UI"; + private static final String TEST_PACKAGE = "com.android.systemui"; private BroadcastDialog mBroadcastDialog; private View mDialogView; private TextView mTitle; @@ -59,6 +59,7 @@ public class BroadcastDialogTest extends SysuiTestCase { MockitoAnnotations.initMocks(this); mBroadcastDialog = new BroadcastDialog(mContext, mock(MediaOutputDialogFactory.class), CURRENT_BROADCAST_APP, TEST_PACKAGE, mock(UiEventLogger.class)); + mBroadcastDialog.show(); mDialogView = mBroadcastDialog.mDialogView; } diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/DistanceClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/DistanceClassifierTest.java index faa5db4327a6..ab6d5b771d5a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/DistanceClassifierTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/DistanceClassifierTest.java @@ -94,7 +94,9 @@ public class DistanceClassifierTest extends ClassifierTest { mClassifier.onTouchEvent(appendMoveEvent(1, 16, 3)); mClassifier.onTouchEvent(appendMoveEvent(1, 17, 300)); mClassifier.onTouchEvent(appendMoveEvent(1, 18, 301)); - mClassifier.onTouchEvent(appendUpEvent(1, 19, 501)); + mClassifier.onTouchEvent(appendMoveEvent(1, 19, 501)); + mClassifier.onTouchEvent(appendUpEvent(1, 19, 501)); //event will be dropped + assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isTrue(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java index 2edc3d361316..8eadadff1ca5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java @@ -75,16 +75,17 @@ public class FalsingDataProviderTest extends ClassifierTest { } @Test - public void test_trackMotionEvents() { + public void test_trackMotionEvents_dropUpEvent() { mDataProvider.onMotionEvent(appendDownEvent(2, 9)); mDataProvider.onMotionEvent(appendMoveEvent(4, 7)); - mDataProvider.onMotionEvent(appendUpEvent(6, 5)); + mDataProvider.onMotionEvent(appendMoveEvent(6, 5)); + mDataProvider.onMotionEvent(appendUpEvent(0, 0)); // event will be dropped List<MotionEvent> motionEventList = mDataProvider.getRecentMotionEvents(); assertThat(motionEventList.size()).isEqualTo(3); assertThat(motionEventList.get(0).getActionMasked()).isEqualTo(MotionEvent.ACTION_DOWN); assertThat(motionEventList.get(1).getActionMasked()).isEqualTo(MotionEvent.ACTION_MOVE); - assertThat(motionEventList.get(2).getActionMasked()).isEqualTo(MotionEvent.ACTION_UP); + assertThat(motionEventList.get(2).getActionMasked()).isEqualTo(MotionEvent.ACTION_MOVE); assertThat(motionEventList.get(0).getEventTime()).isEqualTo(1L); assertThat(motionEventList.get(1).getEventTime()).isEqualTo(2L); assertThat(motionEventList.get(2).getEventTime()).isEqualTo(3L); @@ -97,6 +98,28 @@ public class FalsingDataProviderTest extends ClassifierTest { } @Test + public void test_trackMotionEvents_keepUpEvent() { + mDataProvider.onMotionEvent(appendDownEvent(2, 9)); + mDataProvider.onMotionEvent(appendMoveEvent(4, 7)); + mDataProvider.onMotionEvent(appendUpEvent(0, 0, 100)); + List<MotionEvent> motionEventList = mDataProvider.getRecentMotionEvents(); + + assertThat(motionEventList.size()).isEqualTo(3); + assertThat(motionEventList.get(0).getActionMasked()).isEqualTo(MotionEvent.ACTION_DOWN); + assertThat(motionEventList.get(1).getActionMasked()).isEqualTo(MotionEvent.ACTION_MOVE); + assertThat(motionEventList.get(2).getActionMasked()).isEqualTo(MotionEvent.ACTION_UP); + assertThat(motionEventList.get(0).getEventTime()).isEqualTo(1L); + assertThat(motionEventList.get(1).getEventTime()).isEqualTo(2L); + assertThat(motionEventList.get(2).getEventTime()).isEqualTo(100); + assertThat(motionEventList.get(0).getX()).isEqualTo(2f); + assertThat(motionEventList.get(1).getX()).isEqualTo(4f); + assertThat(motionEventList.get(2).getX()).isEqualTo(0f); + assertThat(motionEventList.get(0).getY()).isEqualTo(9f); + assertThat(motionEventList.get(1).getY()).isEqualTo(7f); + assertThat(motionEventList.get(2).getY()).isEqualTo(0f); + } + + @Test public void test_trackRecentMotionEvents() { mDataProvider.onMotionEvent(appendDownEvent(2, 9, 1)); mDataProvider.onMotionEvent(appendMoveEvent(4, 7, 800)); diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/ZigZagClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/ZigZagClassifierTest.java index c343c20398e9..ae2b8bbb4ce6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/ZigZagClassifierTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/ZigZagClassifierTest.java @@ -68,6 +68,15 @@ public class ZigZagClassifierTest extends ClassifierTest { } @Test + public void testPass_dropClosingUpEvent() { + appendMoveEvent(0, 0); + appendMoveEvent(0, 100); + appendMoveEvent(0, 200); + appendUpEvent(0, 180); // this event would push us over the maxDevianceY + assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse(); + } + + @Test public void testPass_fewTouchesHorizontal() { assertThat(mClassifier.classifyGesture(0, 0.5, 1).isFalse()).isFalse(); appendMoveEvent(0, 0); diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java index 2099281d694a..ffd75fb9bbc6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java @@ -35,6 +35,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; import android.app.RemoteAction; import android.content.ClipData; import android.content.ClipDescription; @@ -101,6 +102,9 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase { private ArgumentCaptor<ClipboardOverlayView.ClipboardOverlayCallbacks> mOverlayCallbacksCaptor; private ClipboardOverlayView.ClipboardOverlayCallbacks mCallbacks; + @Captor + private ArgumentCaptor<AnimatorListenerAdapter> mAnimatorArgumentCaptor; + private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock()); @Before @@ -446,7 +450,7 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase { mFeatureFlags.set(CLIPBOARD_REMOTE_BEHAVIOR, true); when(mClipboardUtils.isRemoteCopy(any(Context.class), any(ClipData.class), anyString())) .thenReturn(true); - when(mClipboardUtils.getAction(any(CharSequence.class), any(TextLinks.class), anyString())) + when(mClipboardUtils.getAction(any(TextLinks.class), anyString())) .thenReturn(Optional.of(Mockito.mock(RemoteAction.class))); when(mClipboardOverlayView.post(any(Runnable.class))).thenAnswer(new Answer<Object>() { @Override @@ -478,12 +482,16 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase { when(mClipboardOverlayWindow.getWindowInsets()).thenReturn( getImeInsets(new Rect(0, 0, 0, 1))); mOverlayController.setClipData(mSampleClipData, ""); + Animator mockFadeoutAnimator = Mockito.mock(Animator.class); + when(mClipboardOverlayView.getMinimizedFadeoutAnimation()).thenReturn(mockFadeoutAnimator); verify(mClipboardOverlayView).setMinimized(true); verify(mClipboardOverlayView, never()).setMinimized(false); verify(mClipboardOverlayView, never()).showTextPreview(any(), anyBoolean()); mCallbacks.onMinimizedViewTapped(); + verify(mockFadeoutAnimator).addListener(mAnimatorArgumentCaptor.capture()); + mAnimatorArgumentCaptor.getValue().onAnimationEnd(mockFadeoutAnimator); verify(mClipboardOverlayView).setMinimized(false); verify(mClipboardOverlayView).showTextPreview("Test Item", false); diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtilsTest.java b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtilsTest.java index aea6be3d468b..3d8f04e08825 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtilsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtilsTest.java @@ -21,6 +21,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; 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.when; @@ -77,6 +78,74 @@ public class ClipboardOverlayUtilsTest extends SysuiTestCase { @Test public void test_getAction_noLinks_returnsEmptyOptional() { + Optional<RemoteAction> action = + mClipboardUtils.getAction(Mockito.mock(TextLinks.class), "abc"); + + assertTrue(action.isEmpty()); + } + + @Test + public void test_getAction_returnsFirstLink() { + TextLinks links = getFakeTextLinksBuilder().build(); + RemoteAction actionA = constructRemoteAction("abc"); + RemoteAction actionB = constructRemoteAction("def"); + TextClassification classificationA = Mockito.mock(TextClassification.class); + when(classificationA.getActions()).thenReturn(Lists.newArrayList(actionA)); + TextClassification classificationB = Mockito.mock(TextClassification.class); + when(classificationB.getActions()).thenReturn(Lists.newArrayList(actionB)); + when(mTextClassifier.classifyText(anyString(), anyInt(), anyInt(), isNull())).thenReturn( + classificationA, classificationB); + + RemoteAction result = mClipboardUtils.getAction(links, "test").orElse(null); + + assertEquals(actionA, result); + } + + @Test + public void test_getAction_skipsMatchingComponent() { + TextLinks links = getFakeTextLinksBuilder().build(); + RemoteAction actionA = constructRemoteAction("abc"); + RemoteAction actionB = constructRemoteAction("def"); + TextClassification classificationA = Mockito.mock(TextClassification.class); + when(classificationA.getActions()).thenReturn(Lists.newArrayList(actionA)); + TextClassification classificationB = Mockito.mock(TextClassification.class); + when(classificationB.getActions()).thenReturn(Lists.newArrayList(actionB)); + when(mTextClassifier.classifyText(anyString(), anyInt(), anyInt(), isNull())).thenReturn( + classificationA, classificationB); + + RemoteAction result = mClipboardUtils.getAction(links, "abc").orElse(null); + + assertEquals(actionB, result); + } + + @Test + public void test_getAction_skipsShortEntity() { + TextLinks.Builder textLinks = new TextLinks.Builder("test text of length 22"); + final Map<String, Float> scores = new ArrayMap<>(); + scores.put(TextClassifier.TYPE_EMAIL, 1f); + textLinks.addLink(20, 22, scores); + textLinks.addLink(0, 22, scores); + + RemoteAction actionA = constructRemoteAction("abc"); + RemoteAction actionB = constructRemoteAction("def"); + TextClassification classificationA = Mockito.mock(TextClassification.class); + when(classificationA.getActions()).thenReturn(Lists.newArrayList(actionA)); + TextClassification classificationB = Mockito.mock(TextClassification.class); + when(classificationB.getActions()).thenReturn(Lists.newArrayList(actionB)); + when(mTextClassifier.classifyText(anyString(), eq(20), eq(22), isNull())).thenReturn( + classificationA); + when(mTextClassifier.classifyText(anyString(), eq(0), eq(22), isNull())).thenReturn( + classificationB); + + RemoteAction result = mClipboardUtils.getAction(textLinks.build(), "test").orElse(null); + + assertEquals(actionB, result); + } + + // TODO(b/267162944): Next four tests (marked "legacy") are obsolete once + // CLIPBOARD_MINIMIZED_LAYOUT flag is released and removed + @Test + public void test_getAction_noLinks_returnsEmptyOptional_legacy() { ClipData.Item item = new ClipData.Item("no text links"); item.setTextLinks(Mockito.mock(TextLinks.class)); @@ -86,8 +155,8 @@ public class ClipboardOverlayUtilsTest extends SysuiTestCase { } @Test - public void test_getAction_returnsFirstLink() { - when(mClipDataItem.getTextLinks()).thenReturn(getFakeTextLinks()); + public void test_getAction_returnsFirstLink_legacy() { + when(mClipDataItem.getTextLinks()).thenReturn(getFakeTextLinksBuilder().build()); when(mClipDataItem.getText()).thenReturn(""); RemoteAction actionA = constructRemoteAction("abc"); RemoteAction actionB = constructRemoteAction("def"); @@ -98,14 +167,14 @@ public class ClipboardOverlayUtilsTest extends SysuiTestCase { when(mTextClassifier.classifyText(anyString(), anyInt(), anyInt(), isNull())).thenReturn( classificationA, classificationB); - RemoteAction result = mClipboardUtils.getAction(mClipDataItem, "def").orElse(null); + RemoteAction result = mClipboardUtils.getAction(mClipDataItem, "test").orElse(null); assertEquals(actionA, result); } @Test - public void test_getAction_skipsMatchingComponent() { - when(mClipDataItem.getTextLinks()).thenReturn(getFakeTextLinks()); + public void test_getAction_skipsMatchingComponent_legacy() { + when(mClipDataItem.getTextLinks()).thenReturn(getFakeTextLinksBuilder().build()); when(mClipDataItem.getText()).thenReturn(""); RemoteAction actionA = constructRemoteAction("abc"); RemoteAction actionB = constructRemoteAction("def"); @@ -122,6 +191,33 @@ public class ClipboardOverlayUtilsTest extends SysuiTestCase { } @Test + public void test_getAction_skipsShortEntity_legacy() { + TextLinks.Builder textLinks = new TextLinks.Builder("test text of length 22"); + final Map<String, Float> scores = new ArrayMap<>(); + scores.put(TextClassifier.TYPE_EMAIL, 1f); + textLinks.addLink(20, 22, scores); + textLinks.addLink(0, 22, scores); + + when(mClipDataItem.getTextLinks()).thenReturn(textLinks.build()); + when(mClipDataItem.getText()).thenReturn(textLinks.build().getText()); + + RemoteAction actionA = constructRemoteAction("abc"); + RemoteAction actionB = constructRemoteAction("def"); + TextClassification classificationA = Mockito.mock(TextClassification.class); + when(classificationA.getActions()).thenReturn(Lists.newArrayList(actionA)); + TextClassification classificationB = Mockito.mock(TextClassification.class); + when(classificationB.getActions()).thenReturn(Lists.newArrayList(actionB)); + when(mTextClassifier.classifyText(anyString(), eq(20), eq(22), isNull())).thenReturn( + classificationA); + when(mTextClassifier.classifyText(anyString(), eq(0), eq(22), isNull())).thenReturn( + classificationB); + + RemoteAction result = mClipboardUtils.getAction(mClipDataItem, "test").orElse(null); + + assertEquals(actionB, result); + } + + @Test public void test_extra_withPackage_returnsTrue() { PersistableBundle b = new PersistableBundle(); b.putBoolean(ClipDescription.EXTRA_IS_REMOTE_DEVICE, true); @@ -184,12 +280,12 @@ public class ClipboardOverlayUtilsTest extends SysuiTestCase { return action; } - private static TextLinks getFakeTextLinks() { - TextLinks.Builder textLinks = new TextLinks.Builder("test"); + private static TextLinks.Builder getFakeTextLinksBuilder() { + TextLinks.Builder textLinks = new TextLinks.Builder("test text of length 22"); final Map<String, Float> scores = new ArrayMap<>(); scores.put(TextClassifier.TYPE_EMAIL, 1f); - textLinks.addLink(0, 0, scores); - textLinks.addLink(0, 0, scores); - return textLinks.build(); + textLinks.addLink(0, 22, scores); + textLinks.addLink(0, 22, scores); + return textLinks; } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt index 28e80057a672..c98d5374311d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt @@ -34,6 +34,7 @@ import com.android.systemui.controls.ControlStatus import com.android.systemui.controls.ControlsServiceInfo import com.android.systemui.controls.management.ControlsListingController import com.android.systemui.controls.panels.AuthorizedPanelsRepository +import com.android.systemui.controls.panels.FakeSelectedComponentRepository import com.android.systemui.controls.ui.ControlsUiController import com.android.systemui.dump.DumpManager import com.android.systemui.settings.UserFileManager @@ -56,7 +57,6 @@ import org.mockito.ArgumentMatchers.anyString import org.mockito.Captor import org.mockito.Mock import org.mockito.Mockito -import org.mockito.Mockito.`when` import org.mockito.Mockito.anyInt import org.mockito.Mockito.clearInvocations import org.mockito.Mockito.inOrder @@ -66,6 +66,7 @@ import org.mockito.Mockito.reset import org.mockito.Mockito.times import org.mockito.Mockito.verify import org.mockito.Mockito.verifyNoMoreInteractions +import org.mockito.Mockito.`when` import org.mockito.MockitoAnnotations import java.io.File import java.util.* @@ -108,6 +109,8 @@ class ControlsControllerImplTest : SysuiTestCase() { private lateinit var listingCallbackCaptor: ArgumentCaptor<ControlsListingController.ControlsListingCallback> + private val preferredPanelRepository = FakeSelectedComponentRepository() + private lateinit var delayableExecutor: FakeExecutor private lateinit var controller: ControlsControllerImpl private lateinit var canceller: DidRunRunnable @@ -168,6 +171,7 @@ class ControlsControllerImplTest : SysuiTestCase() { wrapper, delayableExecutor, uiController, + preferredPanelRepository, bindingController, listingController, userFileManager, @@ -221,6 +225,7 @@ class ControlsControllerImplTest : SysuiTestCase() { mContext, delayableExecutor, uiController, + preferredPanelRepository, bindingController, listingController, userFileManager, @@ -240,6 +245,7 @@ class ControlsControllerImplTest : SysuiTestCase() { mContext, delayableExecutor, uiController, + preferredPanelRepository, bindingController, listingController, userFileManager, diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImplTest.kt index 7ac1953ee495..272f5895390c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImplTest.kt @@ -22,6 +22,8 @@ import android.testing.AndroidTestingRunner import androidx.test.filters.SmallTest import com.android.systemui.R import com.android.systemui.SysuiTestCase +import com.android.systemui.flags.FakeFeatureFlags +import com.android.systemui.flags.Flags import com.android.systemui.settings.UserFileManager import com.android.systemui.settings.UserTracker import com.android.systemui.util.FakeSharedPreferences @@ -40,6 +42,8 @@ class AuthorizedPanelsRepositoryImplTest : SysuiTestCase() { @Mock private lateinit var userTracker: UserTracker + private val featureFlags = FakeFeatureFlags() + @Before fun setUp() { MockitoAnnotations.initMocks(this) @@ -48,6 +52,7 @@ class AuthorizedPanelsRepositoryImplTest : SysuiTestCase() { arrayOf<String>() ) whenever(userTracker.userId).thenReturn(0) + featureFlags.set(Flags.APP_PANELS_REMOVE_APPS_ALLOWED, true) } @Test @@ -127,8 +132,25 @@ class AuthorizedPanelsRepositoryImplTest : SysuiTestCase() { assertThat(sharedPrefs.getStringSet(KEY, null)).isEmpty() } + @Test + fun testSetAuthorizedPackageAfterFeatureDisabled() { + mContext.orCreateTestableResources.addOverride( + R.array.config_controlsPreferredPackages, + arrayOf(TEST_PACKAGE) + ) + val sharedPrefs = FakeSharedPreferences() + val fileManager = FakeUserFileManager(mapOf(0 to sharedPrefs)) + val repository = createRepository(fileManager) + + repository.removeAuthorizedPanels(setOf(TEST_PACKAGE)) + + featureFlags.set(Flags.APP_PANELS_REMOVE_APPS_ALLOWED, false) + + assertThat(repository.getAuthorizedPanels()).isEqualTo(setOf(TEST_PACKAGE)) + } + private fun createRepository(userFileManager: UserFileManager): AuthorizedPanelsRepositoryImpl { - return AuthorizedPanelsRepositoryImpl(mContext, userFileManager, userTracker) + return AuthorizedPanelsRepositoryImpl(mContext, userFileManager, userTracker, featureFlags) } private class FakeUserFileManager(private val sharedPrefs: Map<Int, SharedPreferences>) : diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/panels/FakeSelectedComponentRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/panels/FakeSelectedComponentRepository.kt new file mode 100644 index 000000000000..a7677cca9f29 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/panels/FakeSelectedComponentRepository.kt @@ -0,0 +1,42 @@ +/* + * 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.systemui.controls.panels + +class FakeSelectedComponentRepository : SelectedComponentRepository { + + private var selectedComponent: SelectedComponentRepository.SelectedComponent? = null + private var shouldAddDefaultPanel: Boolean = true + + override fun getSelectedComponent(): SelectedComponentRepository.SelectedComponent? = + selectedComponent + + override fun setSelectedComponent( + selectedComponent: SelectedComponentRepository.SelectedComponent + ) { + this.selectedComponent = selectedComponent + } + + override fun removeSelectedComponent() { + selectedComponent = null + } + + override fun shouldAddDefaultComponent(): Boolean = shouldAddDefaultPanel + + override fun setShouldAddDefaultComponent(shouldAdd: Boolean) { + shouldAddDefaultPanel = shouldAdd + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/panels/SelectedComponentRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/panels/SelectedComponentRepositoryTest.kt new file mode 100644 index 000000000000..0c7b9cb82b94 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/panels/SelectedComponentRepositoryTest.kt @@ -0,0 +1,163 @@ +/* + * 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.systemui.controls.panels + +import android.content.ComponentName +import android.content.SharedPreferences +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.flags.FakeFeatureFlags +import com.android.systemui.flags.Flags +import com.android.systemui.settings.UserFileManager +import com.android.systemui.settings.UserTracker +import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl +import com.android.systemui.util.FakeSharedPreferences +import com.android.systemui.util.mockito.any +import com.android.systemui.util.mockito.whenever +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.MockitoAnnotations + +@RunWith(AndroidTestingRunner::class) +@SmallTest +class SelectedComponentRepositoryTest : SysuiTestCase() { + + private companion object { + val COMPONENT_A = + SelectedComponentRepository.SelectedComponent( + name = "a", + componentName = ComponentName.unflattenFromString("pkg/.cls_a"), + isPanel = false, + ) + val COMPONENT_B = + SelectedComponentRepository.SelectedComponent( + name = "b", + componentName = ComponentName.unflattenFromString("pkg/.cls_b"), + isPanel = false, + ) + } + + @Mock private lateinit var userTracker: UserTracker + @Mock private lateinit var userFileManager: UserFileManager + + private val featureFlags = FakeFeatureFlags() + private val sharedPreferences: SharedPreferences = FakeSharedPreferences() + + // under test + private lateinit var repository: SelectedComponentRepository + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + whenever(userFileManager.getSharedPreferences(any(), any(), any())) + .thenReturn(sharedPreferences) + + repository = SelectedComponentRepositoryImpl(userFileManager, userTracker, featureFlags) + } + + @Test + fun testUnsetIsNull() { + assertThat(repository.getSelectedComponent()).isNull() + } + + @Test + fun testGetReturnsSet() { + repository.setSelectedComponent(COMPONENT_A) + + assertThat(repository.getSelectedComponent()).isEqualTo(COMPONENT_A) + } + + @Test + fun testSetOverrides() { + repository.setSelectedComponent(COMPONENT_A) + repository.setSelectedComponent(COMPONENT_B) + + assertThat(repository.getSelectedComponent()).isEqualTo(COMPONENT_B) + } + + @Test + fun testRemove() { + repository.setSelectedComponent(COMPONENT_A) + + repository.removeSelectedComponent() + + assertThat(repository.getSelectedComponent()).isNull() + } + + @Test + fun testFeatureEnabled_shouldAddDefaultPanelDefaultsToTrue() { + featureFlags.set(Flags.APP_PANELS_REMOVE_APPS_ALLOWED, true) + + assertThat(repository.shouldAddDefaultComponent()).isTrue() + } + + @Test + fun testFeatureDisabled_shouldAddDefaultPanelDefaultsToTrue() { + featureFlags.set(Flags.APP_PANELS_REMOVE_APPS_ALLOWED, false) + + assertThat(repository.shouldAddDefaultComponent()).isTrue() + } + + @Test + fun testFeatureEnabled_shouldAddDefaultPanelChecked() { + featureFlags.set(Flags.APP_PANELS_REMOVE_APPS_ALLOWED, true) + repository.setShouldAddDefaultComponent(false) + + assertThat(repository.shouldAddDefaultComponent()).isFalse() + } + + @Test + fun testFeatureDisabled_shouldAlwaysAddDefaultPanelAlwaysTrue() { + featureFlags.set(Flags.APP_PANELS_REMOVE_APPS_ALLOWED, false) + repository.setShouldAddDefaultComponent(false) + + assertThat(repository.shouldAddDefaultComponent()).isTrue() + } + + @Test + fun testGetPreferredStructure_differentUserId() { + sharedPreferences.savePanel(COMPONENT_A) + whenever( + userFileManager.getSharedPreferences( + DeviceControlsControllerImpl.PREFS_CONTROLS_FILE, + 0, + 1, + ) + ) + .thenReturn(FakeSharedPreferences().also { it.savePanel(COMPONENT_B) }) + + val previousPreferredStructure = repository.getSelectedComponent() + whenever(userTracker.userId).thenReturn(1) + val currentPreferredStructure = repository.getSelectedComponent() + + assertThat(previousPreferredStructure).isEqualTo(COMPONENT_A) + assertThat(currentPreferredStructure).isNotEqualTo(previousPreferredStructure) + assertThat(currentPreferredStructure).isEqualTo(COMPONENT_B) + } + + private fun SharedPreferences.savePanel(panel: SelectedComponentRepository.SelectedComponent) { + edit() + .putString("controls_component", panel.componentName?.flattenToString()) + .putString("controls_structure", panel.name) + .putBoolean("controls_is_panel", panel.isPanel) + .commit() + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/settings/ControlsSettingsDialogManagerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/settings/ControlsSettingsDialogManagerImplTest.kt index 0c9986d82447..5a613aa9225e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/controls/settings/ControlsSettingsDialogManagerImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/settings/ControlsSettingsDialogManagerImplTest.kt @@ -104,7 +104,9 @@ class ControlsSettingsDialogManagerImplTest : SysuiTestCase() { controlsSettingsRepository, userTracker, activityStarter - ) { context, _ -> TestableAlertDialog(context).also { dialog = it } } + ) { context, _ -> + TestableAlertDialog(context).also { dialog = it } + } } @After diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/start/ControlsStartableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/start/ControlsStartableTest.kt index 7ecaca6c36d0..9d8084d4f2f4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/controls/start/ControlsStartableTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/start/ControlsStartableTest.kt @@ -23,17 +23,19 @@ import android.content.pm.ApplicationInfo import android.content.pm.ServiceInfo import android.testing.AndroidTestingRunner import androidx.test.filters.SmallTest -import com.android.systemui.R import com.android.systemui.SysuiTestCase import com.android.systemui.controls.ControlsServiceInfo import com.android.systemui.controls.controller.ControlsController import com.android.systemui.controls.dagger.ControlsComponent import com.android.systemui.controls.management.ControlsListingController +import com.android.systemui.controls.panels.AuthorizedPanelsRepository +import com.android.systemui.controls.panels.FakeSelectedComponentRepository import com.android.systemui.controls.ui.SelectedItem import com.android.systemui.settings.UserTracker import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.mock +import com.android.systemui.util.mockito.whenever import com.android.systemui.util.time.FakeSystemClock import java.util.Optional import org.junit.Before @@ -53,16 +55,16 @@ class ControlsStartableTest : SysuiTestCase() { @Mock private lateinit var controlsController: ControlsController @Mock private lateinit var controlsListingController: ControlsListingController @Mock private lateinit var userTracker: UserTracker + @Mock private lateinit var authorizedPanelsRepository: AuthorizedPanelsRepository + + private val preferredPanelsRepository = FakeSelectedComponentRepository() private lateinit var fakeExecutor: FakeExecutor @Before fun setUp() { MockitoAnnotations.initMocks(this) - context.orCreateTestableResources.addOverride( - R.array.config_controlsPreferredPackages, - arrayOf<String>() - ) + whenever(authorizedPanelsRepository.getPreferredPackages()).thenReturn(setOf()) fakeExecutor = FakeExecutor(FakeSystemClock()) } @@ -87,10 +89,8 @@ class ControlsStartableTest : SysuiTestCase() { @Test fun testPreferredPackagesNotInstalled_noNewSelection() { - context.orCreateTestableResources.addOverride( - R.array.config_controlsPreferredPackages, - arrayOf(TEST_PACKAGE_PANEL) - ) + whenever(authorizedPanelsRepository.getPreferredPackages()) + .thenReturn(setOf(TEST_PACKAGE_PANEL)) `when`(controlsController.getPreferredSelection()).thenReturn(SelectedItem.EMPTY_SELECTION) `when`(controlsListingController.getCurrentServices()).thenReturn(emptyList()) @@ -101,10 +101,8 @@ class ControlsStartableTest : SysuiTestCase() { @Test fun testPreferredPackageNotPanel_noNewSelection() { - context.orCreateTestableResources.addOverride( - R.array.config_controlsPreferredPackages, - arrayOf(TEST_PACKAGE_PANEL) - ) + whenever(authorizedPanelsRepository.getPreferredPackages()) + .thenReturn(setOf(TEST_PACKAGE_PANEL)) `when`(controlsController.getPreferredSelection()).thenReturn(SelectedItem.EMPTY_SELECTION) val listings = listOf(ControlsServiceInfo(TEST_COMPONENT, "not panel", hasPanel = false)) `when`(controlsListingController.getCurrentServices()).thenReturn(listings) @@ -116,10 +114,8 @@ class ControlsStartableTest : SysuiTestCase() { @Test fun testExistingSelection_noNewSelection() { - context.orCreateTestableResources.addOverride( - R.array.config_controlsPreferredPackages, - arrayOf(TEST_PACKAGE_PANEL) - ) + whenever(authorizedPanelsRepository.getPreferredPackages()) + .thenReturn(setOf(TEST_PACKAGE_PANEL)) `when`(controlsController.getPreferredSelection()) .thenReturn(mock<SelectedItem.PanelItem>()) val listings = listOf(ControlsServiceInfo(TEST_COMPONENT_PANEL, "panel", hasPanel = true)) @@ -132,10 +128,8 @@ class ControlsStartableTest : SysuiTestCase() { @Test fun testPanelAdded() { - context.orCreateTestableResources.addOverride( - R.array.config_controlsPreferredPackages, - arrayOf(TEST_PACKAGE_PANEL) - ) + whenever(authorizedPanelsRepository.getPreferredPackages()) + .thenReturn(setOf(TEST_PACKAGE_PANEL)) `when`(controlsController.getPreferredSelection()).thenReturn(SelectedItem.EMPTY_SELECTION) val listings = listOf(ControlsServiceInfo(TEST_COMPONENT_PANEL, "panel", hasPanel = true)) `when`(controlsListingController.getCurrentServices()).thenReturn(listings) @@ -147,10 +141,8 @@ class ControlsStartableTest : SysuiTestCase() { @Test fun testMultiplePreferredOnlyOnePanel_panelAdded() { - context.orCreateTestableResources.addOverride( - R.array.config_controlsPreferredPackages, - arrayOf("other_package", TEST_PACKAGE_PANEL) - ) + whenever(authorizedPanelsRepository.getPreferredPackages()) + .thenReturn(setOf(TEST_PACKAGE_PANEL)) `when`(controlsController.getPreferredSelection()).thenReturn(SelectedItem.EMPTY_SELECTION) val listings = listOf( @@ -166,10 +158,8 @@ class ControlsStartableTest : SysuiTestCase() { @Test fun testMultiplePreferredMultiplePanels_firstPreferredAdded() { - context.orCreateTestableResources.addOverride( - R.array.config_controlsPreferredPackages, - arrayOf(TEST_PACKAGE_PANEL, "other_package") - ) + whenever(authorizedPanelsRepository.getPreferredPackages()) + .thenReturn(setOf(TEST_PACKAGE_PANEL)) `when`(controlsController.getPreferredSelection()).thenReturn(SelectedItem.EMPTY_SELECTION) val listings = listOf( @@ -217,6 +207,20 @@ class ControlsStartableTest : SysuiTestCase() { verify(controlsController, never()).bindComponentForPanel(any()) } + @Test + fun testAlreadyAddedPanel_noNewSelection() { + preferredPanelsRepository.setShouldAddDefaultComponent(false) + whenever(authorizedPanelsRepository.getPreferredPackages()) + .thenReturn(setOf(TEST_PACKAGE_PANEL)) + `when`(controlsController.getPreferredSelection()).thenReturn(SelectedItem.EMPTY_SELECTION) + val listings = listOf(ControlsServiceInfo(TEST_COMPONENT_PANEL, "panel", hasPanel = true)) + `when`(controlsListingController.getCurrentServices()).thenReturn(listings) + + createStartable(enabled = true).start() + + verify(controlsController, never()).setPreferredSelection(any()) + } + private fun createStartable(enabled: Boolean): ControlsStartable { val component: ControlsComponent = mock() { @@ -230,7 +234,13 @@ class ControlsStartableTest : SysuiTestCase() { `when`(getControlsListingController()).thenReturn(Optional.empty()) } } - return ControlsStartable(context.resources, fakeExecutor, component, userTracker) + return ControlsStartable( + fakeExecutor, + component, + userTracker, + authorizedPanelsRepository, + preferredPanelsRepository, + ) } private fun ControlsServiceInfo( diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt index 23faa99c0b9d..3f61bf75740a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt @@ -42,16 +42,14 @@ import com.android.systemui.controls.controller.StructureInfo import com.android.systemui.controls.management.ControlsListingController import com.android.systemui.controls.management.ControlsProviderSelectorActivity import com.android.systemui.controls.panels.AuthorizedPanelsRepository +import com.android.systemui.controls.panels.FakeSelectedComponentRepository +import com.android.systemui.controls.panels.SelectedComponentRepository import com.android.systemui.controls.settings.FakeControlsSettingsRepository import com.android.systemui.dump.DumpManager import com.android.systemui.flags.FeatureFlags import com.android.systemui.plugins.ActivityStarter -import com.android.systemui.settings.UserFileManager import com.android.systemui.settings.UserTracker -import com.android.systemui.shade.ShadeController -import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl import com.android.systemui.statusbar.policy.KeyguardStateController -import com.android.systemui.util.FakeSharedPreferences import com.android.systemui.util.FakeSystemUIDialogController import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.mockito.any @@ -64,20 +62,18 @@ import com.android.systemui.util.time.FakeSystemClock import com.android.wm.shell.TaskView import com.android.wm.shell.TaskViewFactory import com.google.common.truth.Truth.assertThat +import java.util.Optional +import java.util.function.Consumer import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock -import org.mockito.Mockito.`when` -import org.mockito.Mockito.anyInt -import org.mockito.Mockito.anyString import org.mockito.Mockito.clearInvocations import org.mockito.Mockito.never import org.mockito.Mockito.spy import org.mockito.Mockito.verify +import org.mockito.Mockito.`when` import org.mockito.MockitoAnnotations -import java.util.Optional -import java.util.function.Consumer @SmallTest @RunWith(AndroidTestingRunner::class) @@ -87,11 +83,9 @@ class ControlsUiControllerImplTest : SysuiTestCase() { @Mock lateinit var controlsListingController: ControlsListingController @Mock lateinit var controlActionCoordinator: ControlActionCoordinator @Mock lateinit var activityStarter: ActivityStarter - @Mock lateinit var shadeController: ShadeController @Mock lateinit var iconCache: CustomIconCache @Mock lateinit var controlsMetricsLogger: ControlsMetricsLogger @Mock lateinit var keyguardStateController: KeyguardStateController - @Mock lateinit var userFileManager: UserFileManager @Mock lateinit var userTracker: UserTracker @Mock lateinit var taskViewFactory: TaskViewFactory @Mock lateinit var dumpManager: DumpManager @@ -99,7 +93,7 @@ class ControlsUiControllerImplTest : SysuiTestCase() { @Mock lateinit var featureFlags: FeatureFlags @Mock lateinit var packageManager: PackageManager - private val sharedPreferences = FakeSharedPreferences() + private val preferredPanelRepository = FakeSelectedComponentRepository() private val fakeDialogController = FakeSystemUIDialogController() private val uiExecutor = FakeExecutor(FakeSystemClock()) private val bgExecutor = FakeExecutor(FakeSystemClock()) @@ -138,94 +132,30 @@ class ControlsUiControllerImplTest : SysuiTestCase() { iconCache, controlsMetricsLogger, keyguardStateController, - userFileManager, userTracker, Optional.of(taskViewFactory), controlsSettingsRepository, authorizedPanelsRepository, + preferredPanelRepository, featureFlags, ControlsDialogsFactory { fakeDialogController.dialog }, dumpManager, ) - `when`( - userFileManager.getSharedPreferences( - DeviceControlsControllerImpl.PREFS_CONTROLS_FILE, - 0, - 0 - ) - ) - .thenReturn(sharedPreferences) - `when`(userFileManager.getSharedPreferences(anyString(), anyInt(), anyInt())) - .thenReturn(sharedPreferences) `when`(userTracker.userId).thenReturn(0) `when`(userTracker.userHandle).thenReturn(UserHandle.of(0)) } @Test - fun testGetPreferredStructure() { - val structureInfo = mock<StructureInfo>() - underTest.getPreferredSelectedItem(listOf(structureInfo)) - verify(userFileManager) - .getSharedPreferences( - fileName = DeviceControlsControllerImpl.PREFS_CONTROLS_FILE, - mode = 0, - userId = 0 - ) - } - - @Test - fun testGetPreferredStructure_differentUserId() { - val selectedItems = - listOf( - SelectedItem.StructureItem( - StructureInfo(ComponentName.unflattenFromString("pkg/.cls1"), "a", ArrayList()) - ), - SelectedItem.StructureItem( - StructureInfo(ComponentName.unflattenFromString("pkg/.cls2"), "b", ArrayList()) - ), - ) - val structures = selectedItems.map { it.structure } - sharedPreferences - .edit() - .putString("controls_component", selectedItems[0].componentName.flattenToString()) - .putString("controls_structure", selectedItems[0].name.toString()) - .commit() - - val differentSharedPreferences = FakeSharedPreferences() - differentSharedPreferences - .edit() - .putString("controls_component", selectedItems[1].componentName.flattenToString()) - .putString("controls_structure", selectedItems[1].name.toString()) - .commit() - - val previousPreferredStructure = underTest.getPreferredSelectedItem(structures) - - `when`( - userFileManager.getSharedPreferences( - DeviceControlsControllerImpl.PREFS_CONTROLS_FILE, - 0, - 1 - ) - ) - .thenReturn(differentSharedPreferences) - `when`(userTracker.userId).thenReturn(1) - - val currentPreferredStructure = underTest.getPreferredSelectedItem(structures) - - assertThat(previousPreferredStructure).isEqualTo(selectedItems[0]) - assertThat(currentPreferredStructure).isEqualTo(selectedItems[1]) - assertThat(currentPreferredStructure).isNotEqualTo(previousPreferredStructure) - } - - @Test fun testGetPreferredPanel() { val panel = SelectedItem.PanelItem("App name", ComponentName("pkg", "cls")) - sharedPreferences - .edit() - .putString("controls_component", panel.componentName.flattenToString()) - .putString("controls_structure", panel.appName.toString()) - .putBoolean("controls_is_panel", true) - .commit() + + preferredPanelRepository.setSelectedComponent( + SelectedComponentRepository.SelectedComponent( + name = panel.appName.toString(), + componentName = panel.componentName, + isPanel = true, + ) + ) val selected = underTest.getPreferredSelectedItem(emptyList()) @@ -369,11 +299,9 @@ class ControlsUiControllerImplTest : SysuiTestCase() { StructureInfo(ComponentName.unflattenFromString("pkg/.cls1"), "a", ArrayList()) ), ) - sharedPreferences - .edit() - .putString("controls_component", selectedItems[0].componentName.flattenToString()) - .putString("controls_structure", selectedItems[0].name.toString()) - .commit() + preferredPanelRepository.setSelectedComponent( + SelectedComponentRepository.SelectedComponent(selectedItems[0]) + ) assertThat(underTest.resolveActivity()) .isEqualTo(ControlsProviderSelectorActivity::class.java) @@ -418,12 +346,9 @@ class ControlsUiControllerImplTest : SysuiTestCase() { val componentName = ComponentName(context, "cls") whenever(controlsController.removeFavorites(eq(componentName))).thenReturn(true) val panel = SelectedItem.PanelItem("App name", componentName) - sharedPreferences - .edit() - .putString("controls_component", panel.componentName.flattenToString()) - .putString("controls_structure", panel.appName.toString()) - .putBoolean("controls_is_panel", true) - .commit() + preferredPanelRepository.setSelectedComponent( + SelectedComponentRepository.SelectedComponent(panel) + ) underTest.show(parent, {}, context) underTest.startRemovingApp(componentName, "Test App") @@ -432,11 +357,8 @@ class ControlsUiControllerImplTest : SysuiTestCase() { verify(controlsController).removeFavorites(eq(componentName)) assertThat(underTest.getPreferredSelectedItem(emptyList())) .isEqualTo(SelectedItem.EMPTY_SELECTION) - with(sharedPreferences) { - assertThat(contains("controls_component")).isFalse() - assertThat(contains("controls_structure")).isFalse() - assertThat(contains("controls_is_panel")).isFalse() - } + assertThat(preferredPanelRepository.shouldAddDefaultComponent()).isFalse() + assertThat(preferredPanelRepository.getSelectedComponent()).isNull() } @Test @@ -452,12 +374,9 @@ class ControlsUiControllerImplTest : SysuiTestCase() { private fun setUpPanel(panel: SelectedItem.PanelItem): ControlsServiceInfo { val activity = ComponentName(context, "activity") - sharedPreferences - .edit() - .putString("controls_component", panel.componentName.flattenToString()) - .putString("controls_structure", panel.appName.toString()) - .putBoolean("controls_is_panel", true) - .commit() + preferredPanelRepository.setSelectedComponent( + SelectedComponentRepository.SelectedComponent(panel) + ) return ControlsServiceInfo(panel.componentName, panel.appName, activity) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/OverflowMenuAdapterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/OverflowMenuAdapterTest.kt index dbaf94f1018c..483ab3bae6f1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/OverflowMenuAdapterTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/OverflowMenuAdapterTest.kt @@ -37,7 +37,9 @@ class OverflowMenuAdapterTest : SysuiTestCase() { context, layoutId = 0, labels.zip(ids).map { OverflowMenuAdapter.MenuItem(it.first, it.second) } - ) { true } + ) { + true + } ids.forEachIndexed { index, id -> assertThat(adapter.getItemId(index)).isEqualTo(id) } } @@ -51,7 +53,9 @@ class OverflowMenuAdapterTest : SysuiTestCase() { context, layoutId = 0, labels.zip(ids).map { OverflowMenuAdapter.MenuItem(it.first, it.second) } - ) { position -> position == 0 } + ) { position -> + position == 0 + } assertThat(adapter.isEnabled(0)).isTrue() assertThat(adapter.isEnabled(1)).isFalse() diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt index 6c23254941a8..0a9470617a5f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt @@ -1,6 +1,8 @@ package com.android.systemui.dreams +import android.animation.Animator import android.animation.AnimatorSet +import android.animation.ValueAnimator import android.testing.AndroidTestingRunner import android.view.View import androidx.test.filters.SmallTest @@ -10,13 +12,16 @@ import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransition import com.android.systemui.statusbar.BlurUtils import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.util.concurrency.DelayableExecutor +import com.android.systemui.util.mockito.argumentCaptor import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.runBlocking +import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +import org.mockito.ArgumentCaptor import org.mockito.Mock import org.mockito.Mockito.anyLong import org.mockito.Mockito.eq @@ -71,6 +76,19 @@ class DreamOverlayAnimationsControllerTest : SysuiTestCase() { } @Test + fun testExitAnimationUpdatesState() { + controller.startExitAnimations(animatorBuilder = { mockAnimator }) + + verify(stateController).setExitAnimationsRunning(true) + + val captor = argumentCaptor<Animator.AnimatorListener>() + verify(mockAnimator).addListener(captor.capture()) + + captor.value.onAnimationEnd(mockAnimator) + verify(stateController).setExitAnimationsRunning(false) + } + + @Test fun testWakeUpCallsExecutor() { val mockExecutor: DelayableExecutor = mock() val mockCallback: Runnable = mock() @@ -87,7 +105,7 @@ class DreamOverlayAnimationsControllerTest : SysuiTestCase() { fun testWakeUpAfterStartWillCancel() { val mockStartAnimator: AnimatorSet = mock() - controller.startEntryAnimations(animatorBuilder = { mockStartAnimator }) + controller.startEntryAnimations(false, animatorBuilder = { mockStartAnimator }) verify(mockStartAnimator, never()).cancel() @@ -100,4 +118,50 @@ class DreamOverlayAnimationsControllerTest : SysuiTestCase() { // animator. verify(mockStartAnimator, times(1)).cancel() } + + @Test + fun testEntryAnimations_translatesUpwards() { + val mockStartAnimator: AnimatorSet = mock() + + controller.startEntryAnimations( + /* downwards= */ false, + animatorBuilder = { mockStartAnimator } + ) + + val animatorCaptor = ArgumentCaptor.forClass(Animator::class.java) + verify(mockStartAnimator).playTogether(animatorCaptor.capture()) + + // Check if there's a ValueAnimator starting at the expected Y distance. + val animators: List<ValueAnimator> = animatorCaptor.allValues as List<ValueAnimator> + assertTrue( + animators.any { + // Call setCurrentFraction so the animated value jumps to the initial value. + it.setCurrentFraction(0f) + it.animatedValue == DREAM_IN_TRANSLATION_Y_DISTANCE.toFloat() + } + ) + } + + @Test + fun testEntryAnimations_translatesDownwards() { + val mockStartAnimator: AnimatorSet = mock() + + controller.startEntryAnimations( + /* downwards= */ true, + animatorBuilder = { mockStartAnimator } + ) + + val animatorCaptor = ArgumentCaptor.forClass(Animator::class.java) + verify(mockStartAnimator).playTogether(animatorCaptor.capture()) + + // Check if there's a ValueAnimator starting at the expected Y distance. + val animators: List<ValueAnimator> = animatorCaptor.allValues as List<ValueAnimator> + assertTrue( + animators.any { + // Call setCurrentFraction so the animated value jumps to the initial value. + it.setCurrentFraction(0f) + it.animatedValue == -DREAM_IN_TRANSLATION_Y_DISTANCE.toFloat() + } + ) + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java index 6b095ffd3977..2a72e7d85d3c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java @@ -17,6 +17,7 @@ package com.android.systemui.dreams; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyFloat; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; @@ -33,6 +34,7 @@ import android.view.ViewTreeObserver; import androidx.test.filters.SmallTest; +import com.android.dream.lowlight.LowLightTransitionCoordinator; import com.android.keyguard.BouncerPanelExpansionCalculator; import com.android.systemui.SysuiTestCase; import com.android.systemui.dreams.complication.ComplicationHostViewController; @@ -65,6 +67,9 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase { DreamOverlayStatusBarViewController mDreamOverlayStatusBarViewController; @Mock + LowLightTransitionCoordinator mLowLightTransitionCoordinator; + + @Mock DreamOverlayContainerView mDreamOverlayContainerView; @Mock @@ -109,6 +114,7 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase { mComplicationHostViewController, mDreamOverlayContentView, mDreamOverlayStatusBarViewController, + mLowLightTransitionCoordinator, mBlurUtils, mHandler, mResources, @@ -200,7 +206,7 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase { mController.onViewAttached(); - verify(mAnimationsController).startEntryAnimations(); + verify(mAnimationsController).startEntryAnimations(false); verify(mAnimationsController, never()).cancelAnimations(); } @@ -210,11 +216,11 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase { mController.onViewAttached(); - verify(mAnimationsController, never()).startEntryAnimations(); + verify(mAnimationsController, never()).startEntryAnimations(anyBoolean()); } @Test - public void testSkipEntryAnimationsWhenExitingLowLight() { + public void testDownwardEntryAnimationsWhenExitingLowLight() { ArgumentCaptor<DreamOverlayStateController.Callback> callbackCaptor = ArgumentCaptor.forClass(DreamOverlayStateController.Callback.class); when(mStateController.isLowLightActive()).thenReturn(false); @@ -230,8 +236,14 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase { mController.onViewAttached(); // Entry animations should be started then immediately ended to skip to the end. - verify(mAnimationsController).startEntryAnimations(); - verify(mAnimationsController).endAnimations(); + verify(mAnimationsController).startEntryAnimations(true); + } + + @Test + public void testStartsExitAnimationsBeforeEnteringLowLight() { + mController.onBeforeEnterLowLight(); + + verify(mAnimationsController).startExitAnimations(); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationHostViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationHostViewControllerTest.java index dcd8736711f6..068852de7a43 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationHostViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationHostViewControllerTest.java @@ -22,6 +22,8 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.os.UserHandle; +import android.provider.Settings; import android.testing.AndroidTestingRunner; import android.view.View; @@ -33,6 +35,8 @@ import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; import com.android.systemui.dreams.DreamOverlayStateController; +import com.android.systemui.util.settings.FakeSettings; +import com.android.systemui.util.settings.SecureSettings; import org.junit.Before; import org.junit.Test; @@ -96,6 +100,10 @@ public class ComplicationHostViewControllerTest extends SysuiTestCase { private ComplicationHostViewController mController; + private SecureSettings mSecureSettings; + + private static final int CURRENT_USER_ID = UserHandle.USER_SYSTEM; + @Before public void setup() { MockitoAnnotations.initMocks(this); @@ -108,12 +116,17 @@ public class ComplicationHostViewControllerTest extends SysuiTestCase { when(mViewHolder.getLayoutParams()).thenReturn(mComplicationLayoutParams); when(mComplicationView.getParent()).thenReturn(mComplicationHostView); + mSecureSettings = new FakeSettings(); + mSecureSettings.putFloatForUser( + Settings.Global.ANIMATOR_DURATION_SCALE, 1.0f, CURRENT_USER_ID); + mController = new ComplicationHostViewController( mComplicationHostView, mLayoutEngine, mDreamOverlayStateController, mLifecycleOwner, - mViewModel); + mViewModel, + mSecureSettings); mController.init(); } @@ -188,6 +201,23 @@ public class ComplicationHostViewControllerTest extends SysuiTestCase { verify(mComplicationView, never()).setVisibility(View.INVISIBLE); } + @Test + public void testAnimationsDisabled_ComplicationsNeverSetToInvisible() { + //Disable animations + mController.mIsAnimationEnabled = false; + + final Observer<Collection<ComplicationViewModel>> observer = + captureComplicationViewModelsObserver(); + + // Add a complication before entry animations are finished. + final HashSet<ComplicationViewModel> complications = new HashSet<>( + Collections.singletonList(mComplicationViewModel)); + observer.onChanged(complications); + + // The complication view should not be set to invisible. + verify(mComplicationView, never()).setVisibility(View.INVISIBLE); + } + private Observer<Collection<ComplicationViewModel>> captureComplicationViewModelsObserver() { verify(mComplicationViewModelLiveData).observe(eq(mLifecycleOwner), mObserverCaptor.capture()); diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java index 3a168d4e234b..d6dbd730368e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java @@ -450,6 +450,15 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase { swipeToPosition(0f, Direction.DOWN, 0); } + @Test + public void testTouchSessionOnRemovedCalledTwice() { + mTouchHandler.onSessionStart(mTouchSession); + ArgumentCaptor<DreamTouchHandler.TouchSession.Callback> onRemovedCallbackCaptor = + ArgumentCaptor.forClass(DreamTouchHandler.TouchSession.Callback.class); + verify(mTouchSession).registerCallback(onRemovedCallbackCaptor.capture()); + onRemovedCallbackCaptor.getValue().onRemoved(); + onRemovedCallbackCaptor.getValue().onRemoved(); + } private void swipeToPosition(float percent, Direction direction, float velocityY) { Mockito.clearInvocations(mTouchSession); diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/domain/interactor/KeyboardBacklightInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/domain/interactor/KeyboardBacklightInteractorTest.kt new file mode 100644 index 000000000000..ec94cdec78f0 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/domain/interactor/KeyboardBacklightInteractorTest.kt @@ -0,0 +1,73 @@ +/* + * 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.systemui.keyboard.backlight.domain.interactor + +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.keyboard.data.repository.FakeKeyboardRepository +import com.android.systemui.keyboard.shared.model.BacklightModel +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +@OptIn(ExperimentalCoroutinesApi::class) +@SmallTest +@RunWith(JUnit4::class) +class KeyboardBacklightInteractorTest : SysuiTestCase() { + + private val keyboardRepository = FakeKeyboardRepository() + private lateinit var underTest: KeyboardBacklightInteractor + + @Before + fun setUp() { + underTest = KeyboardBacklightInteractor(keyboardRepository) + } + + @Test + fun emitsNull_whenKeyboardJustConnected() = runTest { + val latest by collectLastValue(underTest.backlight) + keyboardRepository.setKeyboardConnected(true) + + assertThat(latest).isNull() + } + + @Test + fun emitsBacklight_whenKeyboardConnectedAndBacklightChanged() = runTest { + keyboardRepository.setKeyboardConnected(true) + keyboardRepository.setBacklight(BacklightModel(1, 5)) + + assertThat(underTest.backlight.first()).isEqualTo(BacklightModel(1, 5)) + } + + @Test + fun emitsNull_afterKeyboardDisconnecting() = runTest { + val latest by collectLastValue(underTest.backlight) + keyboardRepository.setKeyboardConnected(true) + keyboardRepository.setBacklight(BacklightModel(1, 5)) + + keyboardRepository.setKeyboardConnected(false) + + assertThat(latest).isNull() + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogViewModelTest.kt new file mode 100644 index 000000000000..ec05d10b793c --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogViewModelTest.kt @@ -0,0 +1,102 @@ +/* + * 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.systemui.keyboard.backlight.ui.viewmodel + +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.keyboard.backlight.domain.interactor.KeyboardBacklightInteractor +import com.android.systemui.keyboard.data.repository.FakeKeyboardRepository +import com.android.systemui.keyboard.shared.model.BacklightModel +import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper +import com.android.systemui.util.mockito.any +import com.android.systemui.util.mockito.whenever +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.test.advanceTimeBy +import kotlinx.coroutines.test.runTest +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.MockitoAnnotations + +@OptIn(ExperimentalCoroutinesApi::class) +@SmallTest +@RunWith(JUnit4::class) +class BacklightDialogViewModelTest : SysuiTestCase() { + + private val keyboardRepository = FakeKeyboardRepository() + private lateinit var underTest: BacklightDialogViewModel + @Mock private lateinit var accessibilityManagerWrapper: AccessibilityManagerWrapper + private val timeoutMillis = 3000L + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + whenever(accessibilityManagerWrapper.getRecommendedTimeoutMillis(any(), any())) + .thenReturn(timeoutMillis.toInt()) + underTest = + BacklightDialogViewModel( + KeyboardBacklightInteractor(keyboardRepository), + accessibilityManagerWrapper + ) + keyboardRepository.setKeyboardConnected(true) + } + + @Test + fun emitsViewModel_whenBacklightChanged() = runTest { + keyboardRepository.setBacklight(BacklightModel(1, 5)) + + assertThat(underTest.dialogContent.first()).isEqualTo(BacklightDialogContentViewModel(1, 5)) + } + + @Test + fun emitsNull_afterTimeout() = runTest { + val latest by collectLastValue(underTest.dialogContent) + keyboardRepository.setBacklight(BacklightModel(1, 5)) + + assertThat(latest).isEqualTo(BacklightDialogContentViewModel(1, 5)) + advanceTimeBy(timeoutMillis + 1) + assertThat(latest).isNull() + } + + @Test + fun emitsNull_after5secDelay_fromLastBacklightChange() = runTest { + val latest by collectLastValue(underTest.dialogContent) + keyboardRepository.setKeyboardConnected(true) + + keyboardRepository.setBacklight(BacklightModel(1, 5)) + assertThat(latest).isEqualTo(BacklightDialogContentViewModel(1, 5)) + + advanceTimeBy(timeoutMillis * 2 / 3) + // timeout yet to pass, no new emission + keyboardRepository.setBacklight(BacklightModel(2, 5)) + assertThat(latest).isEqualTo(BacklightDialogContentViewModel(2, 5)) + + advanceTimeBy(timeoutMillis * 2 / 3) + // timeout refreshed because of last `setBacklight`, still content present + assertThat(latest).isEqualTo(BacklightDialogContentViewModel(2, 5)) + + advanceTimeBy(timeoutMillis * 2 / 3) + // finally timeout reached and null emitted + assertThat(latest).isNull() + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt index 0469e77ca991..0e6f8d4e0720 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt @@ -219,6 +219,29 @@ class KeyguardRepositoryImplTest : SysuiTestCase() { } @Test + fun isKeyguardUnlocked() = + runTest(UnconfinedTestDispatcher()) { + whenever(keyguardStateController.isUnlocked).thenReturn(false) + var latest: Boolean? = null + val job = underTest.isKeyguardUnlocked.onEach { latest = it }.launchIn(this) + + assertThat(latest).isFalse() + + val captor = argumentCaptor<KeyguardStateController.Callback>() + verify(keyguardStateController).addCallback(captor.capture()) + + whenever(keyguardStateController.isUnlocked).thenReturn(true) + captor.value.onUnlockedChanged() + assertThat(latest).isTrue() + + whenever(keyguardStateController.isUnlocked).thenReturn(false) + captor.value.onUnlockedChanged() + assertThat(latest).isFalse() + + job.cancel() + } + + @Test fun isDozing() = runTest(UnconfinedTestDispatcher()) { var latest: Boolean? = null diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt index d2db910ad443..f9493d10ff61 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt @@ -62,7 +62,9 @@ class LightRevealScrimRepositoryTest : SysuiTestCase() { fakeKeyguardRepository.setBiometricUnlockState(BiometricUnlockModel.WAKE_AND_UNLOCK) runCurrent() - values.assertEffectsMatchPredicates({ it == DEFAULT_REVEAL_EFFECT },) + values.assertEffectsMatchPredicates( + { it == DEFAULT_REVEAL_EFFECT }, + ) // We got a source but still have no sensor locations, so should be sticking with // the default effect. @@ -71,14 +73,18 @@ class LightRevealScrimRepositoryTest : SysuiTestCase() { ) runCurrent() - values.assertEffectsMatchPredicates({ it == DEFAULT_REVEAL_EFFECT },) + values.assertEffectsMatchPredicates( + { it == DEFAULT_REVEAL_EFFECT }, + ) // We got a location for the face sensor, but we unlocked with fingerprint. val faceLocation = Point(250, 0) fakeKeyguardRepository.setFaceSensorLocation(faceLocation) runCurrent() - values.assertEffectsMatchPredicates({ it == DEFAULT_REVEAL_EFFECT },) + values.assertEffectsMatchPredicates( + { it == DEFAULT_REVEAL_EFFECT }, + ) // Now we have fingerprint sensor locations, and wake and unlock via fingerprint. val fingerprintLocation = Point(500, 500) 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 ae7a928cdb2c..fe9098fa5c25 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 @@ -19,6 +19,8 @@ package com.android.systemui.keyguard.domain.interactor import android.animation.ValueAnimator import androidx.test.filters.FlakyTest import androidx.test.filters.SmallTest +import com.android.keyguard.KeyguardSecurityModel +import com.android.keyguard.KeyguardSecurityModel.SecurityMode.PIN import com.android.systemui.SysuiTestCase import com.android.systemui.animation.Interpolators import com.android.systemui.flags.FakeFeatureFlags @@ -40,6 +42,7 @@ import com.android.systemui.keyguard.util.KeyguardTransitionRunner import com.android.systemui.shade.data.repository.FakeShadeRepository import com.android.systemui.shade.data.repository.ShadeRepository import com.android.systemui.statusbar.CommandQueue +import com.android.systemui.util.mockito.whenever import com.android.systemui.util.mockito.withArgCaptor import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.cancelChildren @@ -51,6 +54,8 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 +import org.mockito.ArgumentMatchers.anyBoolean +import org.mockito.ArgumentMatchers.anyInt import org.mockito.Mock import org.mockito.Mockito.reset import org.mockito.Mockito.verify @@ -77,6 +82,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { // Used to verify transition requests for test output @Mock private lateinit var mockTransitionRepository: KeyguardTransitionRepository @Mock private lateinit var commandQueue: CommandQueue + @Mock private lateinit var keyguardSecurityModel: KeyguardSecurityModel private lateinit var fromLockscreenTransitionInteractor: FromLockscreenTransitionInteractor private lateinit var fromDreamingTransitionInteractor: FromDreamingTransitionInteractor @@ -102,6 +108,8 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { transitionRepository = KeyguardTransitionRepositoryImpl() runner = KeyguardTransitionRunner(transitionRepository) + whenever(keyguardSecurityModel.getSecurityMode(anyInt())).thenReturn(PIN) + val featureFlags = FakeFeatureFlags().apply { set(Flags.FACE_AUTH_REFACTOR, true) } fromLockscreenTransitionInteractor = FromLockscreenTransitionInteractor( @@ -173,16 +181,17 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { keyguardInteractor = createKeyguardInteractor(featureFlags), keyguardTransitionRepository = mockTransitionRepository, keyguardTransitionInteractor = KeyguardTransitionInteractor(transitionRepository), + keyguardSecurityModel = keyguardSecurityModel, ) fromPrimaryBouncerTransitionInteractor.start() } @Test - fun `DREAMING to LOCKSCREEN - dreaming state changes first`() = + fun `DREAMING to LOCKSCREEN`() = testScope.runTest { - // GIVEN a device is dreaming and occluded + // GIVEN a device is dreaming keyguardRepository.setDreamingWithOverlay(true) - keyguardRepository.setKeyguardOccluded(true) + keyguardRepository.setWakefulnessModel(startingToWake()) runCurrent() // GIVEN a prior transition has run to DREAMING @@ -215,56 +224,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { val info = withArgCaptor<TransitionInfo> { - verify(mockTransitionRepository).startTransition(capture()) - } - // THEN a transition to BOUNCER should occur - assertThat(info.ownerName).isEqualTo("FromDreamingTransitionInteractor") - assertThat(info.from).isEqualTo(KeyguardState.DREAMING) - assertThat(info.to).isEqualTo(KeyguardState.LOCKSCREEN) - assertThat(info.animator).isNotNull() - - coroutineContext.cancelChildren() - } - - @Test - fun `DREAMING to LOCKSCREEN - occluded state changes first`() = - testScope.runTest { - // GIVEN a device is dreaming and occluded - keyguardRepository.setDreamingWithOverlay(true) - keyguardRepository.setKeyguardOccluded(true) - runCurrent() - - // GIVEN a prior transition has run to DREAMING - runner.startTransition( - testScope, - TransitionInfo( - ownerName = "", - from = KeyguardState.LOCKSCREEN, - to = KeyguardState.DREAMING, - animator = - ValueAnimator().apply { - duration = 10 - interpolator = Interpolators.LINEAR - }, - ) - ) - runCurrent() - reset(mockTransitionRepository) - - // WHEN doze is complete - keyguardRepository.setDozeTransitionModel( - DozeTransitionModel(from = DozeStateModel.DOZE, to = DozeStateModel.FINISH) - ) - // AND occluded has stopped - keyguardRepository.setKeyguardOccluded(false) - advanceUntilIdle() - // AND then dreaming has stopped - keyguardRepository.setDreamingWithOverlay(false) - advanceUntilIdle() - - val info = - withArgCaptor<TransitionInfo> { - verify(mockTransitionRepository).startTransition(capture()) + verify(mockTransitionRepository).startTransition(capture(), anyBoolean()) } // THEN a transition to BOUNCER should occur assertThat(info.ownerName).isEqualTo("FromDreamingTransitionInteractor") @@ -304,7 +264,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { val info = withArgCaptor<TransitionInfo> { - verify(mockTransitionRepository).startTransition(capture()) + verify(mockTransitionRepository).startTransition(capture(), anyBoolean()) } // THEN a transition to PRIMARY_BOUNCER should occur assertThat(info.ownerName).isEqualTo("FromLockscreenTransitionInteractor") @@ -345,7 +305,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { val info = withArgCaptor<TransitionInfo> { - verify(mockTransitionRepository).startTransition(capture()) + verify(mockTransitionRepository).startTransition(capture(), anyBoolean()) } // THEN a transition to DOZING should occur assertThat(info.ownerName).isEqualTo("FromOccludedTransitionInteractor") @@ -386,7 +346,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { val info = withArgCaptor<TransitionInfo> { - verify(mockTransitionRepository).startTransition(capture()) + verify(mockTransitionRepository).startTransition(capture(), anyBoolean()) } // THEN a transition to DOZING should occur assertThat(info.ownerName).isEqualTo("FromOccludedTransitionInteractor") @@ -427,7 +387,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { val info = withArgCaptor<TransitionInfo> { - verify(mockTransitionRepository).startTransition(capture()) + verify(mockTransitionRepository).startTransition(capture(), anyBoolean()) } // THEN a transition to DOZING should occur assertThat(info.ownerName).isEqualTo("FromLockscreenTransitionInteractor") @@ -468,7 +428,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { val info = withArgCaptor<TransitionInfo> { - verify(mockTransitionRepository).startTransition(capture()) + verify(mockTransitionRepository).startTransition(capture(), anyBoolean()) } // THEN a transition to DOZING should occur assertThat(info.ownerName).isEqualTo("FromLockscreenTransitionInteractor") @@ -505,7 +465,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { val info = withArgCaptor<TransitionInfo> { - verify(mockTransitionRepository).startTransition(capture()) + verify(mockTransitionRepository).startTransition(capture(), anyBoolean()) } // THEN a transition to DOZING should occur assertThat(info.ownerName).isEqualTo("FromDozingTransitionInteractor") @@ -542,7 +502,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { val info = withArgCaptor<TransitionInfo> { - verify(mockTransitionRepository).startTransition(capture()) + verify(mockTransitionRepository).startTransition(capture(), anyBoolean()) } // THEN a transition to DOZING should occur assertThat(info.ownerName).isEqualTo("FromDozingTransitionInteractor") @@ -583,7 +543,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { val info = withArgCaptor<TransitionInfo> { - verify(mockTransitionRepository).startTransition(capture()) + verify(mockTransitionRepository).startTransition(capture(), anyBoolean()) } // THEN a transition to DOZING should occur assertThat(info.ownerName).isEqualTo("FromGoneTransitionInteractor") @@ -624,7 +584,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { val info = withArgCaptor<TransitionInfo> { - verify(mockTransitionRepository).startTransition(capture()) + verify(mockTransitionRepository).startTransition(capture(), anyBoolean()) } // THEN a transition to AOD should occur assertThat(info.ownerName).isEqualTo("FromGoneTransitionInteractor") @@ -661,7 +621,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { val info = withArgCaptor<TransitionInfo> { - verify(mockTransitionRepository).startTransition(capture()) + verify(mockTransitionRepository).startTransition(capture(), anyBoolean()) } // THEN a transition to AOD should occur assertThat(info.ownerName).isEqualTo("FromGoneTransitionInteractor") @@ -677,6 +637,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { testScope.runTest { // GIVEN a device that is not dreaming or dozing keyguardRepository.setDreamingWithOverlay(false) + keyguardRepository.setWakefulnessModel(startingToWake()) keyguardRepository.setDozeTransitionModel( DozeTransitionModel(from = DozeStateModel.DOZE, to = DozeStateModel.FINISH) ) @@ -704,7 +665,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { val info = withArgCaptor<TransitionInfo> { - verify(mockTransitionRepository).startTransition(capture()) + verify(mockTransitionRepository).startTransition(capture(), anyBoolean()) } // THEN a transition to DREAMING should occur assertThat(info.ownerName).isEqualTo("FromGoneTransitionInteractor") @@ -741,7 +702,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { val info = withArgCaptor<TransitionInfo> { - verify(mockTransitionRepository).startTransition(capture()) + verify(mockTransitionRepository).startTransition(capture(), anyBoolean()) } // THEN a transition to PRIMARY_BOUNCER should occur assertThat(info.ownerName).isEqualTo("FromAlternateBouncerTransitionInteractor") @@ -784,7 +745,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { val info = withArgCaptor<TransitionInfo> { - verify(mockTransitionRepository).startTransition(capture()) + verify(mockTransitionRepository).startTransition(capture(), anyBoolean()) } // THEN a transition to AOD should occur assertThat(info.ownerName).isEqualTo("FromAlternateBouncerTransitionInteractor") @@ -828,7 +789,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { val info = withArgCaptor<TransitionInfo> { - verify(mockTransitionRepository).startTransition(capture()) + verify(mockTransitionRepository).startTransition(capture(), anyBoolean()) } // THEN a transition to DOZING should occur assertThat(info.ownerName).isEqualTo("FromAlternateBouncerTransitionInteractor") @@ -870,7 +831,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { val info = withArgCaptor<TransitionInfo> { - verify(mockTransitionRepository).startTransition(capture()) + verify(mockTransitionRepository).startTransition(capture(), anyBoolean()) } // THEN a transition to LOCKSCREEN should occur assertThat(info.ownerName).isEqualTo("FromAlternateBouncerTransitionInteractor") @@ -912,7 +873,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { val info = withArgCaptor<TransitionInfo> { - verify(mockTransitionRepository).startTransition(capture()) + verify(mockTransitionRepository).startTransition(capture(), anyBoolean()) } // THEN a transition to AOD should occur assertThat(info.ownerName).isEqualTo("FromPrimaryBouncerTransitionInteractor") @@ -954,7 +915,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { val info = withArgCaptor<TransitionInfo> { - verify(mockTransitionRepository).startTransition(capture()) + verify(mockTransitionRepository).startTransition(capture(), anyBoolean()) } // THEN a transition to DOZING should occur assertThat(info.ownerName).isEqualTo("FromPrimaryBouncerTransitionInteractor") @@ -995,7 +956,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { val info = withArgCaptor<TransitionInfo> { - verify(mockTransitionRepository).startTransition(capture()) + verify(mockTransitionRepository).startTransition(capture(), anyBoolean()) } // THEN a transition to LOCKSCREEN should occur assertThat(info.ownerName).isEqualTo("FromPrimaryBouncerTransitionInteractor") diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt new file mode 100644 index 000000000000..2a91799741b7 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt @@ -0,0 +1,109 @@ +/* + * 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.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.keyguard.data.repository.FakeKeyguardTransitionRepository +import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor +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.statusbar.SysuiStatusBarStateController +import com.android.systemui.util.mockito.whenever +import com.google.common.collect.Range +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.test.UnconfinedTestDispatcher +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.MockitoAnnotations + +@SmallTest +@RunWith(AndroidJUnit4::class) +class PrimaryBouncerToGoneTransitionViewModelTest : SysuiTestCase() { + private lateinit var underTest: PrimaryBouncerToGoneTransitionViewModel + private lateinit var repository: FakeKeyguardTransitionRepository + @Mock private lateinit var statusBarStateController: SysuiStatusBarStateController + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + repository = FakeKeyguardTransitionRepository() + val interactor = KeyguardTransitionInteractor(repository) + underTest = PrimaryBouncerToGoneTransitionViewModel(interactor, statusBarStateController) + } + + @Test + fun scrimBehindAlpha_leaveShadeOpen() = + runTest(UnconfinedTestDispatcher()) { + val values = mutableListOf<Float>() + + val job = underTest.scrimBehindAlpha.onEach { values.add(it) }.launchIn(this) + + whenever(statusBarStateController.leaveOpenOnKeyguardHide()).thenReturn(true) + + repository.sendTransitionStep(step(0f, TransitionState.STARTED)) + repository.sendTransitionStep(step(0.3f)) + repository.sendTransitionStep(step(0.6f)) + repository.sendTransitionStep(step(1f)) + + assertThat(values.size).isEqualTo(4) + values.forEach { assertThat(it).isEqualTo(1f) } + + job.cancel() + } + + @Test + fun scrimBehindAlpha_doNotLeaveShadeOpen() = + runTest(UnconfinedTestDispatcher()) { + val values = mutableListOf<Float>() + + val job = underTest.scrimBehindAlpha.onEach { values.add(it) }.launchIn(this) + + whenever(statusBarStateController.leaveOpenOnKeyguardHide()).thenReturn(false) + + repository.sendTransitionStep(step(0f, TransitionState.STARTED)) + repository.sendTransitionStep(step(0.3f)) + repository.sendTransitionStep(step(0.6f)) + repository.sendTransitionStep(step(1f)) + + assertThat(values.size).isEqualTo(4) + values.forEach { assertThat(it).isIn(Range.closed(0f, 1f)) } + assertThat(values[3]).isEqualTo(0f) + + job.cancel() + } + + private fun step( + value: Float, + state: TransitionState = TransitionState.RUNNING + ): TransitionStep { + return TransitionStep( + from = KeyguardState.PRIMARY_BOUNCER, + to = KeyguardState.GONE, + value = value, + transitionState = state, + ownerName = "PrimaryBouncerToGoneTransitionViewModelTest" + ) + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt index 7f5707722b9c..e0ca90ec2c58 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt @@ -18,7 +18,6 @@ package com.android.systemui.media.controls.ui import android.app.PendingIntent import android.content.res.ColorStateList -import android.content.res.Configuration import android.testing.AndroidTestingRunner import android.testing.TestableLooper import android.util.MathUtils.abs @@ -685,46 +684,6 @@ class MediaCarouselControllerTest : SysuiTestCase() { } @Test - fun testOnConfigChanged_playersAreAddedBack() { - mediaCarouselController.pageIndicator = pageIndicator - - listener.value.onMediaDataLoaded( - "playing local", - null, - DATA.copy( - active = true, - isPlaying = true, - playbackLocation = MediaData.PLAYBACK_LOCAL, - resumption = false - ) - ) - listener.value.onMediaDataLoaded( - "paused local", - null, - DATA.copy( - active = true, - isPlaying = false, - playbackLocation = MediaData.PLAYBACK_LOCAL, - resumption = false - ) - ) - runAllReady() - - val playersSize = MediaPlayerData.players().size - - configListener.value.onConfigChanged(Configuration()) - runAllReady() - - verify(pageIndicator).tintList = - ColorStateList.valueOf(context.getColor(R.color.media_paging_indicator)) - assertEquals(playersSize, MediaPlayerData.players().size) - assertEquals( - MediaPlayerData.getMediaPlayerIndex("playing local"), - mediaCarouselController.mediaCarouselScrollHandler.visibleMediaIndex - ) - } - - @Test fun testOnUiModeChanged_playersAreAddedBack() { mediaCarouselController.pageIndicator = pageIndicator diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt index 55a33b6636e0..fd353afff7c0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt @@ -27,6 +27,7 @@ import android.content.pm.PackageManager import android.graphics.Bitmap import android.graphics.Canvas import android.graphics.Color +import android.graphics.Matrix import android.graphics.drawable.Animatable2 import android.graphics.drawable.AnimatedVectorDrawable import android.graphics.drawable.Drawable @@ -78,6 +79,8 @@ import com.android.systemui.media.controls.pipeline.EMPTY_SMARTSPACE_MEDIA_DATA import com.android.systemui.media.controls.pipeline.MediaDataManager import com.android.systemui.media.controls.util.MediaUiEventLogger import com.android.systemui.media.dialog.MediaOutputDialogFactory +import com.android.systemui.monet.ColorScheme +import com.android.systemui.monet.Style import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.FalsingManager import com.android.systemui.statusbar.NotificationLockscreenUserManager @@ -214,6 +217,7 @@ public class MediaControlPanelTest : SysuiTestCase() { @Mock private lateinit var recSubtitleMock2: TextView @Mock private lateinit var recSubtitleMock3: TextView @Mock private lateinit var coverItem: ImageView + @Mock private lateinit var matrix: Matrix private lateinit var coverItem1: ImageView private lateinit var coverItem2: ImageView private lateinit var coverItem3: ImageView @@ -700,6 +704,46 @@ public class MediaControlPanelTest : SysuiTestCase() { } @Test + fun addTwoPlayerGradients_differentStates() { + // Setup redArtwork and its color scheme. + val redBmp = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888) + val redCanvas = Canvas(redBmp) + redCanvas.drawColor(Color.RED) + val redArt = Icon.createWithBitmap(redBmp) + val redWallpaperColor = player.getWallpaperColor(redArt) + val redColorScheme = ColorScheme(redWallpaperColor, true, Style.CONTENT) + + // Setup greenArt and its color scheme. + val greenBmp = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888) + val greenCanvas = Canvas(greenBmp) + greenCanvas.drawColor(Color.GREEN) + val greenArt = Icon.createWithBitmap(greenBmp) + val greenWallpaperColor = player.getWallpaperColor(greenArt) + val greenColorScheme = ColorScheme(greenWallpaperColor, true, Style.CONTENT) + + // Add gradient to both icons. + val redArtwork = player.addGradientToPlayerAlbum(redArt, redColorScheme, 10, 10) + val greenArtwork = player.addGradientToPlayerAlbum(greenArt, greenColorScheme, 10, 10) + + // They should have different constant states as they have different gradient color. + assertThat(redArtwork.getDrawable(1).constantState) + .isNotEqualTo(greenArtwork.getDrawable(1).constantState) + } + + @Test + fun getWallpaperColor_recycledBitmap_notCrashing() { + // Setup redArt icon. + val redBmp = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888) + val redArt = Icon.createWithBitmap(redBmp) + + // Recycle bitmap of redArt icon. + redArt.bitmap.recycle() + + // get wallpaperColor without illegal exception. + player.getWallpaperColor(redArt) + } + + @Test fun bind_seekBarDisabled_hasActions_seekBarVisibilityIsSetToInvisible() { useRealConstraintSets() @@ -2092,6 +2136,7 @@ public class MediaControlPanelTest : SysuiTestCase() { .thenReturn(listOf(recProgressBar1, recProgressBar2, recProgressBar3)) whenever(recommendationViewHolder.mediaSubtitles) .thenReturn(listOf(recSubtitleMock1, recSubtitleMock2, recSubtitleMock3)) + whenever(coverItem.imageMatrix).thenReturn(matrix) val bmp = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888) val canvas = Canvas(bmp) @@ -2127,6 +2172,7 @@ public class MediaControlPanelTest : SysuiTestCase() { verify(recCardTitle).setTextColor(any<Int>()) verify(recAppIconItem, times(3)).setImageDrawable(any(Drawable::class.java)) verify(coverItem, times(3)).setImageDrawable(any(Drawable::class.java)) + verify(coverItem, times(3)).imageMatrix = any() } @Test @@ -2189,6 +2235,34 @@ public class MediaControlPanelTest : SysuiTestCase() { } @Test + fun addTwoRecommendationGradients_differentStates() { + // Setup redArtwork and its color scheme. + val redBmp = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888) + val redCanvas = Canvas(redBmp) + redCanvas.drawColor(Color.RED) + val redArt = Icon.createWithBitmap(redBmp) + val redWallpaperColor = player.getWallpaperColor(redArt) + val redColorScheme = ColorScheme(redWallpaperColor, true, Style.CONTENT) + + // Setup greenArt and its color scheme. + val greenBmp = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888) + val greenCanvas = Canvas(greenBmp) + greenCanvas.drawColor(Color.GREEN) + val greenArt = Icon.createWithBitmap(greenBmp) + val greenWallpaperColor = player.getWallpaperColor(greenArt) + val greenColorScheme = ColorScheme(greenWallpaperColor, true, Style.CONTENT) + + // Add gradient to both icons. + val redArtwork = player.addGradientToRecommendationAlbum(redArt, redColorScheme, 10, 10) + val greenArtwork = + player.addGradientToRecommendationAlbum(greenArt, greenColorScheme, 10, 10) + + // They should have different constant states as they have different gradient color. + assertThat(redArtwork.getDrawable(1).constantState) + .isNotEqualTo(greenArtwork.getDrawable(1).constantState) + } + + @Test fun onButtonClick_touchRippleFlagEnabled_playsTouchRipple() { fakeFeatureFlag.set(Flags.UMO_SURFACE_RIPPLE, true) val semanticActions = diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaViewControllerTest.kt index af91cdb1522c..0fac3db2dc1f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaViewControllerTest.kt @@ -16,9 +16,12 @@ package com.android.systemui.media.controls.ui +import android.content.res.Configuration +import android.content.res.Configuration.ORIENTATION_LANDSCAPE import android.testing.AndroidTestingRunner import android.testing.TestableLooper import android.view.View +import androidx.constraintlayout.widget.ConstraintSet import androidx.test.filters.SmallTest import com.android.systemui.R import com.android.systemui.SysuiTestCase @@ -58,6 +61,8 @@ class MediaViewControllerTest : SysuiTestCase() { @Mock private lateinit var mediaSubTitleWidgetState: WidgetState @Mock private lateinit var mediaContainerWidgetState: WidgetState @Mock private lateinit var mediaFlags: MediaFlags + @Mock private lateinit var expandedLayout: ConstraintSet + @Mock private lateinit var collapsedLayout: ConstraintSet val delta = 0.1F @@ -77,6 +82,19 @@ class MediaViewControllerTest : SysuiTestCase() { } @Test + fun testOrientationChanged_layoutsAreLoaded() { + mediaViewController.expandedLayout = expandedLayout + mediaViewController.collapsedLayout = collapsedLayout + + val newConfig = Configuration() + newConfig.orientation = ORIENTATION_LANDSCAPE + configurationController.onConfigurationChanged(newConfig) + + verify(expandedLayout).load(context, R.xml.media_session_expanded) + verify(collapsedLayout).load(context, R.xml.media_session_collapsed) + } + + @Test fun testObtainViewState_applySquishFraction_toPlayerTransitionViewState_height() { mediaViewController.attach(player, MediaViewController.TYPE.PLAYER) player.measureState = diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttUtilsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttUtilsTest.kt index 4fc9ca71aeaa..85e8d072bd99 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttUtilsTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttUtilsTest.kt @@ -70,8 +70,7 @@ class MediaTttUtilsTest : SysuiTestCase() { context, appPackageName = null, isReceiver = false, - ) { - } + ) {} assertThat(iconInfo.isAppIcon).isFalse() assertThat(iconInfo.contentDescription.loadContentDescription(context)) @@ -86,8 +85,7 @@ class MediaTttUtilsTest : SysuiTestCase() { context, appPackageName = null, isReceiver = true, - ) { - } + ) {} assertThat(iconInfo.isAppIcon).isFalse() assertThat(iconInfo.contentDescription.loadContentDescription(context)) @@ -119,8 +117,7 @@ class MediaTttUtilsTest : SysuiTestCase() { context, appPackageName = "fakePackageName", isReceiver = false, - ) { - } + ) {} assertThat(iconInfo.isAppIcon).isFalse() assertThat(iconInfo.contentDescription.loadContentDescription(context)) @@ -135,8 +132,7 @@ class MediaTttUtilsTest : SysuiTestCase() { context, appPackageName = "fakePackageName", isReceiver = true, - ) { - } + ) {} assertThat(iconInfo.isAppIcon).isFalse() assertThat(iconInfo.contentDescription.loadContentDescription(context)) @@ -154,7 +150,9 @@ class MediaTttUtilsTest : SysuiTestCase() { context, appPackageName = "fakePackageName", isReceiver = false - ) { exceptionTriggered = true } + ) { + exceptionTriggered = true + } assertThat(exceptionTriggered).isTrue() } @@ -167,7 +165,9 @@ class MediaTttUtilsTest : SysuiTestCase() { context, appPackageName = "fakePackageName", isReceiver = true - ) { exceptionTriggered = true } + ) { + exceptionTriggered = true + } assertThat(exceptionTriggered).isTrue() } @@ -179,8 +179,7 @@ class MediaTttUtilsTest : SysuiTestCase() { context, PACKAGE_NAME, isReceiver = false, - ) { - } + ) {} assertThat(iconInfo.isAppIcon).isTrue() assertThat(iconInfo.icon).isEqualTo(MediaTttIcon.Loaded(appIconFromPackageName)) @@ -194,8 +193,7 @@ class MediaTttUtilsTest : SysuiTestCase() { context, PACKAGE_NAME, isReceiver = true, - ) { - } + ) {} assertThat(iconInfo.isAppIcon).isTrue() assertThat(iconInfo.icon).isEqualTo(MediaTttIcon.Loaded(appIconFromPackageName)) diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt index 8644b5ea18ae..5be95d6f6255 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt @@ -57,6 +57,7 @@ import org.mockito.ArgumentMatchers.anyInt import org.mockito.ArgumentMatchers.anyString import org.mockito.Mock import org.mockito.Mockito.`when` +import org.mockito.Mockito.clearInvocations import org.mockito.Mockito.mock import org.mockito.Mockito.never import org.mockito.Mockito.reset @@ -351,4 +352,44 @@ class CustomTileTest : SysuiTestCase() { .startPendingIntentDismissingKeyguard( eq(pi), nullable(), nullable<ActivityLaunchAnimator.Controller>()) } + + @Test + fun testActiveTileListensOnceAfterCreated() { + `when`(tileServiceManager.isActiveTile).thenReturn(true) + + val tile = CustomTile.create(customTileBuilder, TILE_SPEC, mContext) + tile.initialize() + tile.postStale() + testableLooper.processAllMessages() + + verify(tileServiceManager).setBindRequested(true) + verify(tileService).onStartListening() + } + + @Test + fun testActiveTileDoesntListenAfterFirstTime() { + `when`(tileServiceManager.isActiveTile).thenReturn(true) + + val tile = CustomTile.create(customTileBuilder, TILE_SPEC, mContext) + tile.initialize() + // Make sure we have an icon in the tile because we don't have a default icon + // This should not be overridden by the retrieved tile that has null icon. + tile.qsTile.icon = mock(Icon::class.java) + `when`(tile.qsTile.icon.loadDrawable(any(Context::class.java))) + .thenReturn(mock(Drawable::class.java)) + + tile.postStale() + testableLooper.processAllMessages() + + // postStale will set it to not listening after it's done + verify(tileService).onStopListening() + + clearInvocations(tileServiceManager, tileService) + + tile.setListening(Any(), true) + testableLooper.processAllMessages() + + verify(tileServiceManager, never()).setBindRequested(true) + verify(tileService, never()).onStartListening() + } }
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java index 52b0b6abda1d..4f469f753bdf 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java @@ -551,6 +551,7 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { mNotificationStackSizeCalculator, mUnlockedScreenOffAnimationController, mShadeTransitionController, + mInteractionJankMonitor, systemClock, mKeyguardBottomAreaViewModel, mKeyguardBottomAreaInteractor, diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt index 0a401b09b6cf..82a57438052f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt @@ -33,6 +33,7 @@ import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteracto import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.keyguard.ui.viewmodel.KeyguardBouncerViewModel +import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel import com.android.systemui.shade.NotificationShadeWindowView.InteractionEventHandler import com.android.systemui.statusbar.LockscreenShadeTransitionController import com.android.systemui.statusbar.NotificationInsetsController @@ -65,48 +66,32 @@ import org.mockito.MockitoAnnotations @RunWith(AndroidTestingRunner::class) @RunWithLooper(setAsMainLooper = true) class NotificationShadeWindowViewControllerTest : SysuiTestCase() { - @Mock - private lateinit var view: NotificationShadeWindowView - @Mock - private lateinit var sysuiStatusBarStateController: SysuiStatusBarStateController - @Mock - private lateinit var centralSurfaces: CentralSurfaces - @Mock - private lateinit var dockManager: DockManager - @Mock - private lateinit var notificationPanelViewController: NotificationPanelViewController - @Mock - private lateinit var notificationShadeDepthController: NotificationShadeDepthController - @Mock - private lateinit var notificationShadeWindowController: NotificationShadeWindowController - @Mock - private lateinit var keyguardUnlockAnimationController: KeyguardUnlockAnimationController - @Mock - private lateinit var ambientState: AmbientState - @Mock - private lateinit var keyguardBouncerViewModel: KeyguardBouncerViewModel - @Mock - private lateinit var stackScrollLayoutController: NotificationStackScrollLayoutController - @Mock - private lateinit var statusBarKeyguardViewManager: StatusBarKeyguardViewManager - @Mock - private lateinit var statusBarWindowStateController: StatusBarWindowStateController + @Mock private lateinit var view: NotificationShadeWindowView + @Mock private lateinit var sysuiStatusBarStateController: SysuiStatusBarStateController + @Mock private lateinit var centralSurfaces: CentralSurfaces + @Mock private lateinit var dockManager: DockManager + @Mock private lateinit var notificationPanelViewController: NotificationPanelViewController + @Mock private lateinit var notificationShadeDepthController: NotificationShadeDepthController + @Mock private lateinit var notificationShadeWindowController: NotificationShadeWindowController + @Mock private lateinit var keyguardUnlockAnimationController: KeyguardUnlockAnimationController + @Mock private lateinit var ambientState: AmbientState + @Mock private lateinit var keyguardBouncerViewModel: KeyguardBouncerViewModel + @Mock private lateinit var stackScrollLayoutController: NotificationStackScrollLayoutController + @Mock private lateinit var statusBarKeyguardViewManager: StatusBarKeyguardViewManager + @Mock private lateinit var statusBarWindowStateController: StatusBarWindowStateController @Mock private lateinit var lockscreenShadeTransitionController: LockscreenShadeTransitionController - @Mock - private lateinit var lockIconViewController: LockIconViewController - @Mock - private lateinit var phoneStatusBarViewController: PhoneStatusBarViewController - @Mock - private lateinit var pulsingGestureListener: PulsingGestureListener - @Mock - private lateinit var notificationInsetsController: NotificationInsetsController - @Mock - private lateinit var alternateBouncerInteractor: AlternateBouncerInteractor + @Mock private lateinit var lockIconViewController: LockIconViewController + @Mock private lateinit var phoneStatusBarViewController: PhoneStatusBarViewController + @Mock private lateinit var pulsingGestureListener: PulsingGestureListener + @Mock private lateinit var notificationInsetsController: NotificationInsetsController + @Mock private lateinit var alternateBouncerInteractor: AlternateBouncerInteractor @Mock lateinit var keyguardBouncerComponentFactory: KeyguardBouncerComponent.Factory @Mock lateinit var keyguardBouncerComponent: KeyguardBouncerComponent @Mock lateinit var keyguardSecurityContainerController: KeyguardSecurityContainerController @Mock lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor + @Mock + lateinit var primaryBouncerToGoneTransitionViewModel: PrimaryBouncerToGoneTransitionViewModel private lateinit var interactionEventHandlerCaptor: ArgumentCaptor<InteractionEventHandler> private lateinit var interactionEventHandler: InteractionEventHandler @@ -118,43 +103,44 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() { MockitoAnnotations.initMocks(this) whenever(view.bottom).thenReturn(VIEW_BOTTOM) whenever(view.findViewById<ViewGroup>(R.id.keyguard_bouncer_container)) - .thenReturn(mock(ViewGroup::class.java)) + .thenReturn(mock(ViewGroup::class.java)) whenever(keyguardBouncerComponentFactory.create(any(ViewGroup::class.java))) - .thenReturn(keyguardBouncerComponent) + .thenReturn(keyguardBouncerComponent) whenever(keyguardBouncerComponent.securityContainerController) - .thenReturn(keyguardSecurityContainerController) + .thenReturn(keyguardSecurityContainerController) whenever(keyguardTransitionInteractor.lockscreenToDreamingTransition) - .thenReturn(emptyFlow<TransitionStep>()) - underTest = NotificationShadeWindowViewController( - lockscreenShadeTransitionController, - FalsingCollectorFake(), - sysuiStatusBarStateController, - dockManager, - notificationShadeDepthController, - view, - notificationPanelViewController, - ShadeExpansionStateManager(), - stackScrollLayoutController, - statusBarKeyguardViewManager, - statusBarWindowStateController, - lockIconViewController, - centralSurfaces, - notificationShadeWindowController, - keyguardUnlockAnimationController, - notificationInsetsController, - ambientState, - pulsingGestureListener, - keyguardBouncerViewModel, - keyguardBouncerComponentFactory, - alternateBouncerInteractor, - keyguardTransitionInteractor, - ) + .thenReturn(emptyFlow<TransitionStep>()) + underTest = + NotificationShadeWindowViewController( + lockscreenShadeTransitionController, + FalsingCollectorFake(), + sysuiStatusBarStateController, + dockManager, + notificationShadeDepthController, + view, + notificationPanelViewController, + ShadeExpansionStateManager(), + stackScrollLayoutController, + statusBarKeyguardViewManager, + statusBarWindowStateController, + lockIconViewController, + centralSurfaces, + notificationShadeWindowController, + keyguardUnlockAnimationController, + notificationInsetsController, + ambientState, + pulsingGestureListener, + keyguardBouncerViewModel, + keyguardBouncerComponentFactory, + alternateBouncerInteractor, + keyguardTransitionInteractor, + primaryBouncerToGoneTransitionViewModel, + ) underTest.setupExpandedStatusBar() - interactionEventHandlerCaptor = - ArgumentCaptor.forClass(InteractionEventHandler::class.java) + interactionEventHandlerCaptor = ArgumentCaptor.forClass(InteractionEventHandler::class.java) verify(view).setInteractionEventHandler(interactionEventHandlerCaptor.capture()) - interactionEventHandler = interactionEventHandlerCaptor.value + interactionEventHandler = interactionEventHandlerCaptor.value } // Note: So far, these tests only cover interactions with the status bar view controller. More @@ -184,14 +170,11 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() { @Test fun handleDispatchTouchEvent_downTouchBelowViewThenAnotherTouch_sendsTouchToSb() { underTest.setStatusBarViewController(phoneStatusBarViewController) - val downEvBelow = MotionEvent.obtain( - 0L, 0L, MotionEvent.ACTION_DOWN, 0f, VIEW_BOTTOM + 4f, 0 - ) + val downEvBelow = + MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, VIEW_BOTTOM + 4f, 0) interactionEventHandler.handleDispatchTouchEvent(downEvBelow) - val nextEvent = MotionEvent.obtain( - 0L, 0L, MotionEvent.ACTION_MOVE, 0f, VIEW_BOTTOM + 5f, 0 - ) + val nextEvent = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_MOVE, 0f, VIEW_BOTTOM + 5f, 0) whenever(phoneStatusBarViewController.sendTouchToView(nextEvent)).thenReturn(true) val returnVal = interactionEventHandler.handleDispatchTouchEvent(nextEvent) diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java index 5d719790386a..faa6221b675c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java @@ -46,6 +46,7 @@ import com.android.systemui.keyguard.KeyguardUnlockAnimationController; import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor; import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor; import com.android.systemui.keyguard.ui.viewmodel.KeyguardBouncerViewModel; +import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel; import com.android.systemui.statusbar.DragDownHelper; import com.android.systemui.statusbar.LockscreenShadeTransitionController; import com.android.systemui.statusbar.NotificationInsetsController; @@ -101,6 +102,7 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase { @Mock private NotificationInsetsController mNotificationInsetsController; @Mock private AlternateBouncerInteractor mAlternateBouncerInteractor; @Mock private KeyguardTransitionInteractor mKeyguardTransitionInteractor; + @Mock private PrimaryBouncerToGoneTransitionViewModel mPrimaryBouncerToGoneTransitionViewModel; @Captor private ArgumentCaptor<NotificationShadeWindowView.InteractionEventHandler> mInteractionEventHandlerCaptor; @@ -150,7 +152,8 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase { mKeyguardBouncerViewModel, mKeyguardBouncerComponentFactory, mAlternateBouncerInteractor, - mKeyguardTransitionInteractor + mKeyguardTransitionInteractor, + mPrimaryBouncerToGoneTransitionViewModel ); mController.setupExpandedStatusBar(); mController.setDragDownHelper(mDragDownHelper); diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimatorTest.kt index 7a74b1229c5c..56fc0c74dafa 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimatorTest.kt @@ -36,21 +36,26 @@ class UnfoldConstantTranslateAnimatorTest : SysuiTestCase() { private val progressProvider = TestUnfoldTransitionProvider() - @Mock private lateinit var parent: ViewGroup + @Mock + private lateinit var parent: ViewGroup + + @Mock + private lateinit var shouldBeAnimated: () -> Boolean private lateinit var animator: UnfoldConstantTranslateAnimator - private val viewsIdToRegister = - setOf( - ViewIdToTranslate(START_VIEW_ID, Direction.START), - ViewIdToTranslate(END_VIEW_ID, Direction.END)) + private val viewsIdToRegister + get() = + setOf( + ViewIdToTranslate(START_VIEW_ID, Direction.START, shouldBeAnimated), + ViewIdToTranslate(END_VIEW_ID, Direction.END, shouldBeAnimated) + ) @Before fun setup() { MockitoAnnotations.initMocks(this) - - animator = - UnfoldConstantTranslateAnimator(viewsIdToRegister, progressProvider) + whenever(shouldBeAnimated.invoke()).thenReturn(true) + animator = UnfoldConstantTranslateAnimator(viewsIdToRegister, progressProvider) animator.init(parent, MAX_TRANSLATION) } @@ -96,6 +101,20 @@ class UnfoldConstantTranslateAnimatorTest : SysuiTestCase() { moveAndValidate(listOf(leftView to START, rightView to END), View.LAYOUT_DIRECTION_LTR) } + @Test + fun onTransition_completeStartedTranslation() { + // GIVEN + val leftView = View(context) + whenever(parent.findViewById<View>(START_VIEW_ID)).thenReturn(leftView) + // To start animation, shouldBeAnimated should return true. + // There is a possibility for shouldBeAnimated to return false during the animation. + whenever(shouldBeAnimated.invoke()).thenReturn(true).thenReturn(false) + + // shouldBeAnimated state may change during the animation. + // However, started animation should be completed. + moveAndValidate(listOf(leftView to START), View.LAYOUT_DIRECTION_LTR) + } + private fun moveAndValidate(list: List<Pair<View, Int>>, layoutDirection: Int) { // Compare values as ints because -0f != 0f diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt index d99cdd514f37..ab615f99ebad 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt @@ -211,16 +211,6 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() { } @Test - fun testTriggeringBouncerWhenPrivateNotificationsArentAllowed() { - whenever(lockScreenUserManager.userAllowsPrivateNotificationsInPublic(anyInt())).thenReturn( - false) - transitionController.goToLockedShade(null) - verify(statusbarStateController, never()).setState(anyInt()) - verify(statusbarStateController).setLeaveOpenOnKeyguardHide(true) - verify(mCentralSurfaces).showBouncerWithDimissAndCancelIfKeyguard(anyObject(), anyObject()) - } - - @Test fun testTriggeringBouncerNoNotificationsOnLockscreen() { whenever(lockScreenUserManager.shouldShowLockscreenNotifications()).thenReturn(false) transitionController.goToLockedShade(null) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt new file mode 100644 index 000000000000..95591a4b321c --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt @@ -0,0 +1,163 @@ +/* + * 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.systemui.statusbar.notification + +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase; +import com.android.systemui.dump.DumpManager +import com.android.systemui.plugins.statusbar.StatusBarStateController +import com.android.systemui.statusbar.StatusBarState +import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController +import com.android.systemui.statusbar.phone.DozeParameters +import com.android.systemui.statusbar.phone.KeyguardBypassController +import com.android.systemui.statusbar.phone.ScreenOffAnimationController +import com.android.systemui.statusbar.policy.HeadsUpManager +import com.android.systemui.util.mockito.mock +import com.android.systemui.util.mockito.whenever +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.Mockito.anyFloat +import org.mockito.Mockito.clearInvocations +import org.mockito.Mockito.verify + +@RunWith(AndroidTestingRunner::class) +@SmallTest +class NotificationWakeUpCoordinatorTest : SysuiTestCase() { + + private val dumpManager: DumpManager = mock() + private val headsUpManager: HeadsUpManager = mock() + private val statusBarStateController: StatusBarStateController = mock() + private val bypassController: KeyguardBypassController = mock() + private val dozeParameters: DozeParameters = mock() + private val screenOffAnimationController: ScreenOffAnimationController = mock() + private val logger: NotificationWakeUpCoordinatorLogger = mock() + private val stackScrollerController: NotificationStackScrollLayoutController = mock() + + private lateinit var notificationWakeUpCoordinator: NotificationWakeUpCoordinator + private lateinit var statusBarStateCallback: StatusBarStateController.StateListener + private lateinit var bypassChangeCallback: KeyguardBypassController.OnBypassStateChangedListener + + private var bypassEnabled: Boolean = false + private var statusBarState: Int = StatusBarState.KEYGUARD + private var dozeAmount: Float = 0f + + private fun setBypassEnabled(enabled: Boolean) { + bypassEnabled = enabled + bypassChangeCallback.onBypassStateChanged(enabled) + } + + private fun setStatusBarState(state: Int) { + statusBarState = state + statusBarStateCallback.onStateChanged(state) + } + + private fun setDozeAmount(dozeAmount: Float) { + this.dozeAmount = dozeAmount + statusBarStateCallback.onDozeAmountChanged(dozeAmount, dozeAmount) + } + + @Before + fun setup() { + whenever(bypassController.bypassEnabled).then { bypassEnabled } + whenever(statusBarStateController.state).then { statusBarState } + notificationWakeUpCoordinator = + NotificationWakeUpCoordinator( + dumpManager, + headsUpManager, + statusBarStateController, + bypassController, + dozeParameters, + screenOffAnimationController, + logger, + ) + statusBarStateCallback = withArgCaptor { + verify(statusBarStateController).addCallback(capture()) + } + bypassChangeCallback = withArgCaptor { + verify(bypassController).registerOnBypassStateChangedListener(capture()) + } + notificationWakeUpCoordinator.setStackScroller(stackScrollerController) + } + + @Test + fun setDozeToOneWillFullyHideNotifications() { + setDozeAmount(1f) + verifyStackScrollerDozeAndHideAmount(dozeAmount = 1f, hideAmount = 1f) + assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isTrue() + } + + @Test + fun setDozeToZeroWillFullyShowNotifications() { + setDozeAmount(0f) + verifyStackScrollerDozeAndHideAmount(dozeAmount = 0f, hideAmount = 0f) + assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isFalse() + } + + @Test + fun setDozeToOneThenZeroWillFullyShowNotifications() { + setDozeToOneWillFullyHideNotifications() + clearInvocations(stackScrollerController) + setDozeToZeroWillFullyShowNotifications() + } + + @Test + fun setDozeToHalfWillHalfShowNotifications() { + setDozeAmount(0.5f) + verifyStackScrollerDozeAndHideAmount(dozeAmount = 0.5f, hideAmount = 0.5f) + assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isFalse() + } + + @Test + fun setDozeToZeroWithBypassWillFullyHideNotifications() { + bypassEnabled = true + setDozeAmount(0f) + verifyStackScrollerDozeAndHideAmount(dozeAmount = 01f, hideAmount = 1f) + assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isTrue() + } + + @Test + fun disablingBypassWillShowNotifications() { + setDozeToZeroWithBypassWillFullyHideNotifications() + clearInvocations(stackScrollerController) + setBypassEnabled(false) + verifyStackScrollerDozeAndHideAmount(dozeAmount = 0f, hideAmount = 0f) + assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isFalse() + } + + @Test + fun switchingToShadeWithBypassEnabledWillShowNotifications() { + setDozeToZeroWithBypassWillFullyHideNotifications() + clearInvocations(stackScrollerController) + setStatusBarState(StatusBarState.SHADE) + verifyStackScrollerDozeAndHideAmount(dozeAmount = 0f, hideAmount = 0f) + assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isFalse() + assertThat(notificationWakeUpCoordinator.statusBarState).isEqualTo(StatusBarState.SHADE) + } + + private fun verifyStackScrollerDozeAndHideAmount(dozeAmount: Float, hideAmount: Float) { + // First verify that we did in-fact receive the correct values + verify(stackScrollerController).setDozeAmount(dozeAmount) + verify(stackScrollerController).setHideAmount(hideAmount, hideAmount) + // Now verify that there was just this ONE call to each of these methods + verify(stackScrollerController).setDozeAmount(anyFloat()) + verify(stackScrollerController).setHideAmount(anyFloat(), anyFloat()) + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java index 9f6f082d07c4..ff26a43c0006 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java @@ -413,6 +413,37 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase { verify(mNotificationStackScrollLayout).updateEmptyShadeView(anyBoolean(), anyBoolean()); } + @Test + public void testAttach_updatesViewStatusBarState() { + // GIVEN: Controller is attached + mController.attach(mNotificationStackScrollLayout); + ArgumentCaptor<StatusBarStateController.StateListener> captor = + ArgumentCaptor.forClass(StatusBarStateController.StateListener.class); + verify(mSysuiStatusBarStateController).addCallback(captor.capture(), anyInt()); + StatusBarStateController.StateListener stateListener = captor.getValue(); + + // WHEN: StatusBarState changes to SHADE + when(mSysuiStatusBarStateController.getState()).thenReturn(SHADE); + stateListener.onStateChanged(SHADE); + + // THEN: NSSL is updated with the current state + verify(mNotificationStackScrollLayout).setStatusBarState(SHADE); + + // WHEN: Controller is detached + mController.mOnAttachStateChangeListener + .onViewDetachedFromWindow(mNotificationStackScrollLayout); + + // WHEN: StatusBarState changes to KEYGUARD + when(mSysuiStatusBarStateController.getState()).thenReturn(KEYGUARD); + + // WHEN: Controller is re-attached + mController.mOnAttachStateChangeListener + .onViewAttachedToWindow(mNotificationStackScrollLayout); + + // THEN: NSSL is updated with the current state + verify(mNotificationStackScrollLayout).setStatusBarState(KEYGUARD); + } + private LogMaker logMatcher(int category, int type) { return argThat(new LogMatcher(category, type)); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java index dd7143ae7e16..cbf841b5a1f7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java @@ -17,6 +17,7 @@ package com.android.systemui.statusbar.notification.stack; import static android.view.View.GONE; +import static android.view.WindowInsets.Type.ime; import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_ALL; import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_GENTLE; @@ -46,6 +47,7 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.graphics.Insets; import android.graphics.Rect; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -54,6 +56,8 @@ import android.util.MathUtils; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; +import android.view.WindowInsets; +import android.view.WindowInsetsAnimation; import android.widget.TextView; import androidx.test.annotation.UiThreadTest; @@ -91,6 +95,8 @@ import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; +import java.util.ArrayList; + /** * Tests for {@link NotificationStackScrollLayout}. */ @@ -843,6 +849,19 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { verify(mEmptyShadeView).setFooterText(not(0)); } + @Test + public void testWindowInsetAnimationProgress_updatesBottomInset() { + int bottomImeInset = 100; + mStackScrollerInternal.setAnimatedInsetsEnabled(true); + WindowInsets windowInsets = new WindowInsets.Builder() + .setInsets(ime(), Insets.of(0, 0, 0, bottomImeInset)).build(); + ArrayList<WindowInsetsAnimation> windowInsetsAnimations = new ArrayList<>(); + mStackScrollerInternal + .dispatchWindowInsetsAnimationProgress(windowInsets, windowInsetsAnimations); + + assertEquals(bottomImeInset, mStackScrollerInternal.mBottomInset); + } + private void setBarStateForTest(int state) { // Can't inject this through the listener or we end up on the actual implementation // rather than the mock because the spy just coppied the anonymous inner /shruggie. diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java index eb5edbc21d89..f5b7ca804fbc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java @@ -180,6 +180,7 @@ public class DozeParametersTest extends SysuiTestCase { when(mAmbientDisplayConfiguration.alwaysOnEnabled(anyInt())).thenReturn(true); mDozeParameters.onTuningChanged(Settings.Secure.DOZE_ALWAYS_ON, "1"); + verify(mScreenOffAnimationController).onAlwaysOnChanged(false); assertThat(mDozeParameters.getAlwaysOn()).isFalse(); } @@ -196,13 +197,16 @@ public class DozeParametersTest extends SysuiTestCase { mBatteryStateChangeCallback.getValue().onPowerSaveChanged(true); verify(callback, times(2)).onAlwaysOnChange(); + verify(mScreenOffAnimationController, times(2)).onAlwaysOnChanged(false); assertThat(mDozeParameters.getAlwaysOn()).isFalse(); + reset(mScreenOffAnimationController); reset(callback); when(mBatteryController.isAodPowerSave()).thenReturn(false); mBatteryStateChangeCallback.getValue().onPowerSaveChanged(true); verify(callback).onAlwaysOnChange(); + verify(mScreenOffAnimationController).onAlwaysOnChanged(true); assertThat(mDozeParameters.getAlwaysOn()).isTrue(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java index dc5a0472f49e..e1fba816382c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java @@ -24,6 +24,8 @@ import static com.android.systemui.statusbar.phone.ScrimState.SHADE_LOCKED; import static com.google.common.truth.Truth.assertThat; +import static kotlinx.coroutines.flow.FlowKt.emptyFlow; + import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyFloat; @@ -58,8 +60,14 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.animation.ShadeInterpolation; import com.android.systemui.dock.DockManager; import com.android.systemui.keyguard.KeyguardUnlockAnimationController; +import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor; import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants; +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.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel; import com.android.systemui.scrim.ScrimView; +import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.policy.FakeConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.concurrency.FakeExecutor; @@ -85,8 +93,10 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Map; +import kotlinx.coroutines.CoroutineDispatcher; + @RunWith(AndroidTestingRunner.class) -@TestableLooper.RunWithLooper +@TestableLooper.RunWithLooper(setAsMainLooper = true) @SmallTest public class ScrimControllerTest extends SysuiTestCase { @@ -115,6 +125,11 @@ public class ScrimControllerTest extends SysuiTestCase { @Mock private DockManager mDockManager; @Mock private ScreenOffAnimationController mScreenOffAnimationController; @Mock private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController; + @Mock private PrimaryBouncerToGoneTransitionViewModel mPrimaryBouncerToGoneTransitionViewModel; + @Mock private KeyguardTransitionInteractor mKeyguardTransitionInteractor; + @Mock private CoroutineDispatcher mMainDispatcher; + @Mock private SysuiStatusBarStateController mSysuiStatusBarStateController; + // TODO(b/204991468): Use a real PanelExpansionStateManager object once this bug is fixed. (The // event-dispatch-on-registration pattern caused some of these unit tests to fail.) @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; @@ -225,13 +240,22 @@ public class ScrimControllerTest extends SysuiTestCase { when(mDelayedWakeLockBuilder.build()).thenReturn(mWakeLock); when(mDockManager.isDocked()).thenReturn(false); + when(mKeyguardTransitionInteractor.getPrimaryBouncerToGoneTransition()) + .thenReturn(emptyFlow()); + when(mPrimaryBouncerToGoneTransitionViewModel.getScrimBehindAlpha()) + .thenReturn(emptyFlow()); + mScrimController = new ScrimController(mLightBarController, mDozeParameters, mAlarmManager, mKeyguardStateController, mDelayedWakeLockBuilder, new FakeHandler(mLooper.getLooper()), mKeyguardUpdateMonitor, mDockManager, mConfigurationController, new FakeExecutor(new FakeSystemClock()), mScreenOffAnimationController, mKeyguardUnlockAnimationController, - mStatusBarKeyguardViewManager); + mStatusBarKeyguardViewManager, + mPrimaryBouncerToGoneTransitionViewModel, + mKeyguardTransitionInteractor, + mSysuiStatusBarStateController, + mMainDispatcher); mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible); mScrimController.attachViews(mScrimBehind, mNotificationsScrim, mScrimInFront); mScrimController.setAnimatorListener(mAnimatorListener); @@ -861,7 +885,11 @@ public class ScrimControllerTest extends SysuiTestCase { mDockManager, mConfigurationController, new FakeExecutor(new FakeSystemClock()), mScreenOffAnimationController, mKeyguardUnlockAnimationController, - mStatusBarKeyguardViewManager); + mStatusBarKeyguardViewManager, + mPrimaryBouncerToGoneTransitionViewModel, + mKeyguardTransitionInteractor, + mSysuiStatusBarStateController, + mMainDispatcher); mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible); mScrimController.attachViews(mScrimBehind, mNotificationsScrim, mScrimInFront); mScrimController.setAnimatorListener(mAnimatorListener); @@ -1629,6 +1657,28 @@ public class ScrimControllerTest extends SysuiTestCase { assertScrimAlpha(mScrimBehind, 0); } + @Test + public void ignoreTransitionRequestWhileKeyguardTransitionRunning() { + mScrimController.transitionTo(ScrimState.UNLOCKED); + mScrimController.mPrimaryBouncerToGoneTransition.accept( + new TransitionStep(KeyguardState.PRIMARY_BOUNCER, KeyguardState.GONE, 0f, + TransitionState.RUNNING, "ScrimControllerTest")); + + // This request should not happen + mScrimController.transitionTo(ScrimState.BOUNCER); + assertThat(mScrimController.getState()).isEqualTo(ScrimState.UNLOCKED); + } + + @Test + public void primaryBouncerToGoneOnFinishCallsKeyguardFadedAway() { + when(mKeyguardStateController.isKeyguardFadingAway()).thenReturn(true); + mScrimController.mPrimaryBouncerToGoneTransition.accept( + new TransitionStep(KeyguardState.PRIMARY_BOUNCER, KeyguardState.GONE, 0f, + TransitionState.FINISHED, "ScrimControllerTest")); + + verify(mStatusBarKeyguardViewManager).onKeyguardFadedAway(); + } + private void assertAlphaAfterExpansion(ScrimView scrim, float expectedAlpha, float expansion) { mScrimController.setRawPanelExpansionFraction(expansion); finishAnimationsImmediately(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationControllerTest.kt index 1779de729e5b..7594c90daa8b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationControllerTest.kt @@ -8,13 +8,14 @@ import android.view.WindowManager import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.unfold.TestUnfoldTransitionProvider +import com.android.systemui.unfold.util.CurrentActivityTypeProvider import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider +import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Test import org.mockito.ArgumentMatchers.any import org.mockito.Mock -import org.mockito.Mockito.`when` import org.mockito.MockitoAnnotations @SmallTest @@ -26,6 +27,9 @@ class StatusBarMoveFromCenterAnimationControllerTest : SysuiTestCase() { @Mock private lateinit var display: Display + @Mock + private lateinit var currentActivityTypeProvider: CurrentActivityTypeProvider + private val view: View = View(context) private val progressProvider = TestUnfoldTransitionProvider() private val scopedProvider = ScopedUnfoldTransitionProgressProvider(progressProvider) @@ -36,9 +40,9 @@ class StatusBarMoveFromCenterAnimationControllerTest : SysuiTestCase() { fun setUp() { MockitoAnnotations.initMocks(this) - `when`(windowManager.defaultDisplay).thenReturn(display) - `when`(display.rotation).thenReturn(Surface.ROTATION_0) - `when`(display.getSize(any())).thenAnswer { + whenever(windowManager.defaultDisplay).thenReturn(display) + whenever(display.rotation).thenReturn(Surface.ROTATION_0) + whenever(display.getSize(any())).thenAnswer { val point = it.arguments[0] as Point point.x = 100 point.y = 100 @@ -47,7 +51,12 @@ class StatusBarMoveFromCenterAnimationControllerTest : SysuiTestCase() { scopedProvider.setReadyToHandleTransition(true) - controller = StatusBarMoveFromCenterAnimationController(scopedProvider, windowManager) + controller = + StatusBarMoveFromCenterAnimationController( + scopedProvider, + currentActivityTypeProvider, + windowManager + ) } @Test @@ -99,6 +108,31 @@ class StatusBarMoveFromCenterAnimationControllerTest : SysuiTestCase() { } @Test + fun alpha_onLauncher_alphaDoesNotChange() { + whenever(currentActivityTypeProvider.isHomeActivity).thenReturn(true) + controller.onViewsReady(arrayOf(view)) + progressProvider.onTransitionStarted() + progressProvider.onTransitionProgress(0.0f) + assertThat(view.alpha).isEqualTo(1.0f) + + progressProvider.onTransitionProgress(1.0f) + + assertThat(view.alpha).isEqualTo(1.0f) + } + + @Test + fun alpha_NotOnLauncher_alphaChanges() { + whenever(currentActivityTypeProvider.isHomeActivity).thenReturn(false) + controller.onViewsReady(arrayOf(view)) + progressProvider.onTransitionStarted() + assertThat(view.alpha).isEqualTo(1.0f) + + progressProvider.onTransitionProgress(0.5f) + + assertThat(view.alpha).isNotEqualTo(1.0f) + } + + @Test fun transitionFinished_viewReAttached_noChangesToTranslation() { controller.onViewsReady(arrayOf(view)) progressProvider.onTransitionProgress(0.5f) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/shared/MobileInputLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/MobileInputLoggerTest.kt index 86529dce948a..7c9351c8495d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/shared/MobileInputLoggerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/MobileInputLoggerTest.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.statusbar.pipeline.mobile.shared +package com.android.systemui.statusbar.pipeline.mobile.data import android.net.Network import android.net.NetworkCapabilities @@ -47,14 +47,14 @@ class MobileInputLoggerTest : SysuiTestCase() { val expectedNetId = NET_1_ID.toString() val expectedCaps = NET_1_CAPS.toString() - assertThat(actualString).contains("true") + assertThat(actualString).contains("onDefaultCapabilitiesChanged") assertThat(actualString).contains(expectedNetId) assertThat(actualString).contains(expectedCaps) } @Test fun testLogOnLost_bufferHasNetIdOfLostNetwork() { - logger.logOnLost(NET_1) + logger.logOnLost(NET_1, isDefaultNetworkCallback = false) val stringWriter = StringWriter() buffer.dump(PrintWriter(stringWriter), tailLength = 0) @@ -62,6 +62,7 @@ class MobileInputLoggerTest : SysuiTestCase() { val expectedNetId = NET_1_ID.toString() + assertThat(actualString).contains("onLost") assertThat(actualString).contains(expectedNetId) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryTest.kt index 0145103d55e1..dfef62e95eda 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryTest.kt @@ -24,8 +24,8 @@ import androidx.test.filters.SmallTest import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession import com.android.systemui.SysuiTestCase import com.android.systemui.dump.DumpManager +import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfigTest.Companion.createTestConfig -import com.android.systemui.statusbar.pipeline.mobile.shared.MobileInputLogger import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt index 17502f28a479..07c8cee9a3d4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt @@ -27,13 +27,13 @@ import com.android.systemui.demomode.DemoModeController import com.android.systemui.dump.DumpManager import com.android.systemui.log.table.TableLogBuffer import com.android.systemui.log.table.TableLogBufferFactory +import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.DemoMobileConnectionsRepository import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.DemoModeMobileConnectionDataSource import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.validMobileEvent import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileConnectionsRepositoryImpl -import com.android.systemui.statusbar.pipeline.mobile.shared.MobileInputLogger import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.DemoModeWifiDataSource diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt index 00ce412f2a65..b072deedb9c9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt @@ -239,6 +239,7 @@ internal class DemoMobileConnectionParameterizedTest(private val testCase: TestC * list2 = [false, true] * list3 = [a, b, c] * ``` + * * We'll generate test cases for: * * Test (1, false, a) Test (2, false, a) Test (3, false, a) Test (1, true, a) Test (1, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt index b2577e349da7..bd5a4d7f7385 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt @@ -53,6 +53,7 @@ import android.telephony.TelephonyManager.NETWORK_TYPE_LTE import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.log.table.TableLogBuffer +import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectionModel import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel @@ -65,7 +66,6 @@ import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrier import com.android.systemui.statusbar.pipeline.mobile.data.model.toNetworkNameModel import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS -import com.android.systemui.statusbar.pipeline.mobile.shared.MobileInputLogger import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt index 09b7a66c925d..68b1cda62f4c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt @@ -37,12 +37,12 @@ import com.android.settingslib.mobile.MobileMappings import com.android.systemui.SysuiTestCase import com.android.systemui.log.table.TableLogBuffer import com.android.systemui.log.table.TableLogBufferFactory +import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel import com.android.systemui.statusbar.pipeline.mobile.data.repository.CarrierConfigRepository import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Factory.Companion.tableBufferLogName -import com.android.systemui.statusbar.pipeline.mobile.shared.MobileInputLogger import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLoggerTest.kt new file mode 100644 index 000000000000..4aa48d6f25f1 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLoggerTest.kt @@ -0,0 +1,100 @@ +/* + * 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.systemui.statusbar.pipeline.mobile.ui + +import android.widget.TextView +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.dump.DumpManager +import com.android.systemui.log.LogBufferFactory +import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags +import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger.Companion.getIdForLogging +import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.KeyguardMobileIconViewModel +import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconViewModel +import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.QsMobileIconViewModel +import com.android.systemui.util.mockito.mock +import com.google.common.truth.Truth.assertThat +import java.io.PrintWriter +import java.io.StringWriter +import org.junit.Before +import org.junit.Test +import org.mockito.Mock +import org.mockito.MockitoAnnotations + +@SmallTest +class MobileViewLoggerTest : SysuiTestCase() { + private val buffer = LogBufferFactory(DumpManager(), mock()).create("buffer", 10) + private val stringWriter = StringWriter() + private val printWriter = PrintWriter(stringWriter) + + private val underTest = MobileViewLogger(buffer, mock()) + + @Mock private lateinit var flags: StatusBarPipelineFlags + @Mock private lateinit var commonViewModel: MobileIconViewModel + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + } + + @Test + fun collectionStarted_dumpHasInfo() { + val view = TextView(context) + val viewModel = QsMobileIconViewModel(commonViewModel, flags) + + underTest.logCollectionStarted(view, viewModel) + + val dumpString = getDumpString() + assertThat(dumpString).contains("${view.getIdForLogging()}, isCollecting=true") + } + + @Test + fun collectionStarted_multipleViews_dumpHasInfo() { + val view = TextView(context) + val view2 = TextView(context) + val viewModel = QsMobileIconViewModel(commonViewModel, flags) + val viewModel2 = KeyguardMobileIconViewModel(commonViewModel, flags) + + underTest.logCollectionStarted(view, viewModel) + underTest.logCollectionStarted(view2, viewModel2) + + val dumpString = getDumpString() + assertThat(dumpString).contains("${view.getIdForLogging()}, isCollecting=true") + assertThat(dumpString).contains("${view2.getIdForLogging()}, isCollecting=true") + } + + @Test + fun collectionStopped_dumpHasInfo() { + val view = TextView(context) + val view2 = TextView(context) + val viewModel = QsMobileIconViewModel(commonViewModel, flags) + val viewModel2 = KeyguardMobileIconViewModel(commonViewModel, flags) + + underTest.logCollectionStarted(view, viewModel) + underTest.logCollectionStarted(view2, viewModel2) + underTest.logCollectionStopped(view, viewModel) + + val dumpString = getDumpString() + assertThat(dumpString).contains("${view.getIdForLogging()}, isCollecting=false") + assertThat(dumpString).contains("${view2.getIdForLogging()}, isCollecting=true") + } + + private fun getDumpString(): String { + underTest.dump(printWriter, args = arrayOf()) + return stringWriter.toString() + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileViewTest.kt index e68a3970ae93..7420db2e895e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileViewTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileViewTest.kt @@ -32,6 +32,7 @@ import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconInteractor +import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.LocationBasedMobileViewModel import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconViewModel import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.QsMobileIconViewModel @@ -60,6 +61,7 @@ class ModernStatusBarMobileViewTest : SysuiTestCase() { @Mock private lateinit var statusBarPipelineFlags: StatusBarPipelineFlags @Mock private lateinit var tableLogBuffer: TableLogBuffer + @Mock private lateinit var viewLogger: MobileViewLogger @Mock private lateinit var constants: ConnectivityConstants private lateinit var interactor: FakeMobileIconInteractor private lateinit var airplaneModeRepository: FakeAirplaneModeRepository @@ -94,7 +96,13 @@ class ModernStatusBarMobileViewTest : SysuiTestCase() { @Test fun setVisibleState_icon_iconShownDotHidden() { - val view = ModernStatusBarMobileView.constructAndBind(context, SLOT_NAME, viewModel) + val view = + ModernStatusBarMobileView.constructAndBind( + context, + viewLogger, + SLOT_NAME, + viewModel, + ) view.setVisibleState(StatusBarIconView.STATE_ICON, /* animate= */ false) @@ -109,8 +117,13 @@ class ModernStatusBarMobileViewTest : SysuiTestCase() { @Test fun setVisibleState_dot_iconHiddenDotShown() { - val view = ModernStatusBarMobileView.constructAndBind(context, SLOT_NAME, viewModel) - + val view = + ModernStatusBarMobileView.constructAndBind( + context, + viewLogger, + SLOT_NAME, + viewModel, + ) view.setVisibleState(StatusBarIconView.STATE_DOT, /* animate= */ false) ViewUtils.attachView(view) @@ -124,8 +137,13 @@ class ModernStatusBarMobileViewTest : SysuiTestCase() { @Test fun setVisibleState_hidden_iconAndDotHidden() { - val view = ModernStatusBarMobileView.constructAndBind(context, SLOT_NAME, viewModel) - + val view = + ModernStatusBarMobileView.constructAndBind( + context, + viewLogger, + SLOT_NAME, + viewModel, + ) view.setVisibleState(StatusBarIconView.STATE_HIDDEN, /* animate= */ false) ViewUtils.attachView(view) @@ -142,8 +160,13 @@ class ModernStatusBarMobileViewTest : SysuiTestCase() { whenever(constants.hasDataCapabilities).thenReturn(false) createViewModel() - val view = ModernStatusBarMobileView.constructAndBind(context, SLOT_NAME, viewModel) - + val view = + ModernStatusBarMobileView.constructAndBind( + context, + viewLogger, + SLOT_NAME, + viewModel, + ) ViewUtils.attachView(view) testableLooper.processAllMessages() @@ -157,8 +180,13 @@ class ModernStatusBarMobileViewTest : SysuiTestCase() { whenever(constants.hasDataCapabilities).thenReturn(true) createViewModel() - val view = ModernStatusBarMobileView.constructAndBind(context, SLOT_NAME, viewModel) - + val view = + ModernStatusBarMobileView.constructAndBind( + context, + viewLogger, + SLOT_NAME, + viewModel, + ) ViewUtils.attachView(view) testableLooper.processAllMessages() @@ -171,8 +199,13 @@ class ModernStatusBarMobileViewTest : SysuiTestCase() { fun isIconVisible_notAirplaneMode_outputsTrue() { airplaneModeRepository.setIsAirplaneMode(false) - val view = ModernStatusBarMobileView.constructAndBind(context, SLOT_NAME, viewModel) - + val view = + ModernStatusBarMobileView.constructAndBind( + context, + viewLogger, + SLOT_NAME, + viewModel, + ) ViewUtils.attachView(view) testableLooper.processAllMessages() @@ -185,8 +218,13 @@ class ModernStatusBarMobileViewTest : SysuiTestCase() { fun isIconVisible_airplaneMode_outputsTrue() { airplaneModeRepository.setIsAirplaneMode(true) - val view = ModernStatusBarMobileView.constructAndBind(context, SLOT_NAME, viewModel) - + val view = + ModernStatusBarMobileView.constructAndBind( + context, + viewLogger, + SLOT_NAME, + viewModel, + ) ViewUtils.attachView(view) testableLooper.processAllMessages() @@ -198,7 +236,13 @@ class ModernStatusBarMobileViewTest : SysuiTestCase() { @Test fun onDarkChanged_iconHasNewColor() { whenever(statusBarPipelineFlags.useDebugColoring()).thenReturn(false) - val view = ModernStatusBarMobileView.constructAndBind(context, SLOT_NAME, viewModel) + val view = + ModernStatusBarMobileView.constructAndBind( + context, + viewLogger, + SLOT_NAME, + viewModel, + ) ViewUtils.attachView(view) testableLooper.processAllMessages() @@ -214,7 +258,13 @@ class ModernStatusBarMobileViewTest : SysuiTestCase() { @Test fun setStaticDrawableColor_iconHasNewColor() { whenever(statusBarPipelineFlags.useDebugColoring()).thenReturn(false) - val view = ModernStatusBarMobileView.constructAndBind(context, SLOT_NAME, viewModel) + val view = + ModernStatusBarMobileView.constructAndBind( + context, + viewLogger, + SLOT_NAME, + viewModel, + ) ViewUtils.attachView(view) testableLooper.processAllMessages() diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelTest.kt index f9830309252d..a6d915243f60 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelTest.kt @@ -28,6 +28,7 @@ import com.android.systemui.statusbar.pipeline.mobile.ui.model.SignalIconModel import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconViewModelTest.Companion.defaultSignal import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository +import com.android.systemui.util.mockito.mock import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.launchIn @@ -84,7 +85,7 @@ class LocationBasedMobileIconViewModelTest : SysuiTestCase() { testScope.backgroundScope, ) - homeIcon = HomeMobileIconViewModel(commonImpl, statusBarPipelineFlags) + homeIcon = HomeMobileIconViewModel(commonImpl, statusBarPipelineFlags, mock()) qsIcon = QsMobileIconViewModel(commonImpl, statusBarPipelineFlags) keyguardIcon = KeyguardMobileIconViewModel(commonImpl, statusBarPipelineFlags) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt index 4628f8410245..ddb7f4d88d30 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt @@ -24,6 +24,8 @@ import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirp import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor +import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger +import com.android.systemui.statusbar.pipeline.mobile.ui.VerboseMobileViewLogger import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository @@ -51,6 +53,8 @@ class MobileIconsViewModelTest : SysuiTestCase() { private lateinit var airplaneModeInteractor: AirplaneModeInteractor @Mock private lateinit var statusBarPipelineFlags: StatusBarPipelineFlags @Mock private lateinit var constants: ConnectivityConstants + @Mock private lateinit var logger: MobileViewLogger + @Mock private lateinit var verboseLogger: VerboseMobileViewLogger private val testDispatcher = UnconfinedTestDispatcher() private val testScope = TestScope(testDispatcher) @@ -73,6 +77,8 @@ class MobileIconsViewModelTest : SysuiTestCase() { underTest = MobileIconsViewModel( subscriptionIdsFlow, + logger, + verboseLogger, interactor, airplaneModeInteractor, constants, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarViewTest.kt index e4c8fd0cd8a1..b4039d906810 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarViewTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarViewTest.kt @@ -164,6 +164,10 @@ class ModernStatusBarViewTest : SysuiTestCase() { override fun getShouldIconBeVisible(): Boolean { return shouldIconBeVisibleInternal } + + override fun isCollecting(): Boolean { + return true + } } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java index 48b17322da4d..481d453fa0b1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java @@ -38,6 +38,7 @@ import com.android.internal.R; import com.android.internal.view.RotationPolicy; import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager; import com.android.systemui.SysuiTestCase; +import com.android.systemui.dump.DumpManager; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.time.FakeSystemClock; import com.android.systemui.util.wrapper.RotationPolicyWrapper; @@ -55,10 +56,12 @@ public class DeviceStateRotationLockSettingControllerTest extends SysuiTestCase private static final String[] DEFAULT_SETTINGS = new String[]{"0:1", "2:0:1", "1:2"}; + @Mock private DeviceStateManager mDeviceStateManager; + @Mock private DeviceStateRotationLockSettingControllerLogger mLogger; + @Mock private DumpManager mDumpManager; + private final FakeSystemClock mFakeSystemClock = new FakeSystemClock(); private final FakeExecutor mFakeExecutor = new FakeExecutor(mFakeSystemClock); - @Mock - private DeviceStateManager mDeviceStateManager; private final RotationPolicyWrapper mFakeRotationPolicy = new FakeRotationPolicy(); private DeviceStateRotationLockSettingController mDeviceStateRotationLockSettingController; private DeviceStateManager.DeviceStateCallback mDeviceStateCallback; @@ -78,7 +81,13 @@ public class DeviceStateRotationLockSettingControllerTest extends SysuiTestCase mSettingsManager = DeviceStateRotationLockSettingsManager.getInstance(mContext); mDeviceStateRotationLockSettingController = new DeviceStateRotationLockSettingController( - mFakeRotationPolicy, mDeviceStateManager, mFakeExecutor, mSettingsManager); + mFakeRotationPolicy, + mDeviceStateManager, + mFakeExecutor, + mSettingsManager, + mLogger, + mDumpManager + ); mDeviceStateRotationLockSettingController.setListening(true); verify(mDeviceStateManager) @@ -173,15 +182,11 @@ public class DeviceStateRotationLockSettingControllerTest extends SysuiTestCase } @Test - public void whenDeviceStateSwitchedToIgnoredState_usePreviousSetting() { - initializeSettingsWith( - 0, DEVICE_STATE_ROTATION_LOCK_IGNORED, 1, DEVICE_STATE_ROTATION_LOCK_UNLOCKED); - mFakeRotationPolicy.setRotationLock(true); - - mDeviceStateCallback.onStateChanged(1); - assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse(); - + public void whenDeviceStateSwitchedToIgnoredState_useFallbackSetting() { mDeviceStateCallback.onStateChanged(0); + assertThat(mFakeRotationPolicy.isRotationLocked()).isTrue(); + + mDeviceStateCallback.onStateChanged(2); assertThat(mFakeRotationPolicy.isRotationLocked()).isFalse(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/RotationChangeProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/RotationChangeProviderTest.kt index 85cfef727954..fd368eb07b5b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/RotationChangeProviderTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/RotationChangeProviderTest.kt @@ -16,22 +16,24 @@ package com.android.systemui.unfold.updates +import android.content.Context +import android.hardware.display.DisplayManager +import android.os.Looper import android.testing.AndroidTestingRunner -import android.view.IRotationWatcher -import android.view.IWindowManager +import android.view.Display import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.unfold.updates.RotationChangeProvider.RotationListener -import com.android.systemui.util.concurrency.FakeExecutor -import com.android.systemui.util.time.FakeSystemClock +import com.android.systemui.util.mockito.whenever +import com.android.systemui.utils.os.FakeHandler import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor import org.mockito.ArgumentMatchers.any -import org.mockito.ArgumentMatchers.anyInt import org.mockito.Captor import org.mockito.Mock +import org.mockito.Mockito.spy import org.mockito.Mockito.verify import org.mockito.Mockito.verifyNoMoreInteractions import org.mockito.MockitoAnnotations @@ -42,19 +44,23 @@ class RotationChangeProviderTest : SysuiTestCase() { private lateinit var rotationChangeProvider: RotationChangeProvider - @Mock lateinit var windowManagerInterface: IWindowManager + @Mock lateinit var displayManager: DisplayManager @Mock lateinit var listener: RotationListener - @Captor lateinit var rotationWatcher: ArgumentCaptor<IRotationWatcher> - private val fakeExecutor = FakeExecutor(FakeSystemClock()) + @Mock lateinit var display: Display + @Captor lateinit var displayListener: ArgumentCaptor<DisplayManager.DisplayListener> + private val fakeHandler = FakeHandler(Looper.getMainLooper()) + + private lateinit var spyContext: Context @Before fun setup() { MockitoAnnotations.initMocks(this) - rotationChangeProvider = - RotationChangeProvider(windowManagerInterface, context, fakeExecutor) + spyContext = spy(context) + whenever(spyContext.display).thenReturn(display) + rotationChangeProvider = RotationChangeProvider(displayManager, spyContext, fakeHandler) rotationChangeProvider.addCallback(listener) - fakeExecutor.runAllReady() - verify(windowManagerInterface).watchRotation(rotationWatcher.capture(), anyInt()) + fakeHandler.dispatchQueuedMessages() + verify(displayManager).registerDisplayListener(displayListener.capture(), any()) } @Test @@ -70,15 +76,16 @@ class RotationChangeProviderTest : SysuiTestCase() { verify(listener).onRotationChanged(42) rotationChangeProvider.removeCallback(listener) - fakeExecutor.runAllReady() + fakeHandler.dispatchQueuedMessages() sendRotationUpdate(43) - verify(windowManagerInterface).removeRotationWatcher(any()) + verify(displayManager).unregisterDisplayListener(any()) verifyNoMoreInteractions(listener) } private fun sendRotationUpdate(newRotation: Int) { - rotationWatcher.value.onRotationChanged(newRotation) - fakeExecutor.runAllReady() + whenever(display.rotation).thenReturn(newRotation) + displayListener.allValues.forEach { it.onDisplayChanged(display.displayId) } + fakeHandler.dispatchQueuedMessages() } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java index 31cce4f3168b..468c5a73645b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java @@ -88,7 +88,7 @@ public class ImageWallpaperTest extends SysuiTestCase { @Mock private Bitmap mWallpaperBitmap; FakeSystemClock mFakeSystemClock = new FakeSystemClock(); - FakeExecutor mFakeBackgroundExecutor = new FakeExecutor(mFakeSystemClock); + FakeExecutor mFakeExecutor = new FakeExecutor(mFakeSystemClock); @Before public void setUp() throws Exception { @@ -125,7 +125,7 @@ public class ImageWallpaperTest extends SysuiTestCase { @Test public void testBitmapWallpaper_normal() { - // Will use a image wallpaper with dimensions DISPLAY_WIDTH x DISPLAY_WIDTH. + // Will use an image wallpaper with dimensions DISPLAY_WIDTH x DISPLAY_WIDTH. // Then we expect the surface size will be also DISPLAY_WIDTH x DISPLAY_WIDTH. int bitmapSide = DISPLAY_WIDTH; testSurfaceHelper( @@ -137,7 +137,7 @@ public class ImageWallpaperTest extends SysuiTestCase { @Test public void testBitmapWallpaper_low_resolution() { - // Will use a image wallpaper with dimensions BMP_WIDTH x BMP_HEIGHT. + // Will use an image wallpaper with dimensions BMP_WIDTH x BMP_HEIGHT. // Then we expect the surface size will be also BMP_WIDTH x BMP_HEIGHT. testSurfaceHelper(LOW_BMP_WIDTH /* bitmapWidth */, LOW_BMP_HEIGHT /* bitmapHeight */, @@ -161,13 +161,13 @@ public class ImageWallpaperTest extends SysuiTestCase { ImageWallpaper.CanvasEngine spyEngine = getSpyEngine(); spyEngine.onCreate(mSurfaceHolder); spyEngine.onSurfaceRedrawNeeded(mSurfaceHolder); - assertThat(mFakeBackgroundExecutor.numPending()).isAtLeast(1); + assertThat(mFakeExecutor.numPending()).isAtLeast(1); int n = 0; - while (mFakeBackgroundExecutor.numPending() >= 1) { + while (mFakeExecutor.numPending() >= 1) { n++; assertThat(n).isAtMost(10); - mFakeBackgroundExecutor.runNextReady(); + mFakeExecutor.runNextReady(); mFakeSystemClock.advanceTime(1000); } @@ -176,7 +176,7 @@ public class ImageWallpaperTest extends SysuiTestCase { } private ImageWallpaper createImageWallpaper() { - return new ImageWallpaper(mFakeBackgroundExecutor, mUserTracker) { + return new ImageWallpaper(mFakeExecutor, mUserTracker) { @Override public Engine onCreateEngine() { return new CanvasEngine() { diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/coroutines/Flow.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/coroutines/Flow.kt index 9b4f4969f9e9..c2947b42f56d 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/coroutines/Flow.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/coroutines/Flow.kt @@ -29,6 +29,7 @@ import kotlinx.coroutines.test.runCurrent /** * Collect [flow] in a new [Job] and return a getter for the last collected value. + * * ``` * fun myTest() = runTest { * // ... diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/data/repository/FakeKeyboardRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/data/repository/FakeKeyboardRepository.kt new file mode 100644 index 000000000000..4e435462be50 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/data/repository/FakeKeyboardRepository.kt @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.android.systemui.keyboard.data.repository + +import com.android.systemui.keyboard.shared.model.BacklightModel +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.filterNotNull + +class FakeKeyboardRepository : KeyboardRepository { + + private val _keyboardConnected = MutableStateFlow(false) + override val keyboardConnected: Flow<Boolean> = _keyboardConnected + + private val _backlightState: MutableStateFlow<BacklightModel?> = MutableStateFlow(null) + // filtering to make sure backlight doesn't have default initial value + override val backlight: Flow<BacklightModel> = _backlightState.filterNotNull() + + fun setBacklight(state: BacklightModel) { + _backlightState.value = state + } + + fun setKeyboardConnected(connected: Boolean) { + _keyboardConnected.value = connected + } +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt index 1a371c73550c..194ed02712b2 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt @@ -47,6 +47,9 @@ class FakeKeyguardRepository : KeyguardRepository { private val _isKeyguardShowing = MutableStateFlow(false) override val isKeyguardShowing: Flow<Boolean> = _isKeyguardShowing + private val _isKeyguardUnlocked = MutableStateFlow(false) + override val isKeyguardUnlocked: Flow<Boolean> = _isKeyguardUnlocked + private val _isKeyguardOccluded = MutableStateFlow(false) override val isKeyguardOccluded: Flow<Boolean> = _isKeyguardOccluded diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt index eac1bd145033..16442bb525b6 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt @@ -37,7 +37,7 @@ class FakeKeyguardTransitionRepository : KeyguardTransitionRepository { _transitions.emit(step) } - override fun startTransition(info: TransitionInfo): UUID? { + override fun startTransition(info: TransitionInfo, resetIfCanceled: Boolean): UUID? { return null } diff --git a/packages/SystemUI/unfold/Android.bp b/packages/SystemUI/unfold/Android.bp index 180b611aa13b..2e0a9462ffbe 100644 --- a/packages/SystemUI/unfold/Android.bp +++ b/packages/SystemUI/unfold/Android.bp @@ -35,6 +35,7 @@ android_library { ], kotlincflags: ["-Xjvm-default=enable"], java_version: "1.8", + sdk_version: "current", min_sdk_version: "current", plugins: ["dagger2-compiler"], } diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt index 068347cfe9d8..c3a6cf035d09 100644 --- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt +++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt @@ -19,14 +19,15 @@ package com.android.systemui.unfold import android.content.ContentResolver import android.content.Context import android.hardware.SensorManager +import android.hardware.display.DisplayManager import android.os.Handler -import android.view.IWindowManager import com.android.systemui.unfold.config.UnfoldTransitionConfig import com.android.systemui.unfold.dagger.UnfoldMain import com.android.systemui.unfold.dagger.UnfoldSingleThreadBg import com.android.systemui.unfold.progress.RemoteUnfoldTransitionReceiver import com.android.systemui.unfold.updates.FoldProvider import com.android.systemui.unfold.updates.RotationChangeProvider +import com.android.systemui.unfold.updates.hinge.HingeAngleProvider import com.android.systemui.unfold.updates.screen.ScreenStatusProvider import com.android.systemui.unfold.util.CurrentActivityTypeProvider import com.android.systemui.unfold.util.UnfoldTransitionATracePrefix @@ -61,12 +62,13 @@ interface UnfoldSharedComponent { @BindsInstance @UnfoldMain executor: Executor, @BindsInstance @UnfoldSingleThreadBg singleThreadBgExecutor: Executor, @BindsInstance @UnfoldTransitionATracePrefix tracingTagPrefix: String, - @BindsInstance windowManager: IWindowManager, + @BindsInstance displayManager: DisplayManager, @BindsInstance contentResolver: ContentResolver = context.contentResolver ): UnfoldSharedComponent } val unfoldTransitionProvider: Optional<UnfoldTransitionProgressProvider> + val hingeAngleProvider: HingeAngleProvider val rotationChangeProvider: RotationChangeProvider } @@ -84,8 +86,9 @@ interface RemoteUnfoldSharedComponent { @BindsInstance context: Context, @BindsInstance config: UnfoldTransitionConfig, @BindsInstance @UnfoldMain executor: Executor, + @BindsInstance @UnfoldMain handler: Handler, @BindsInstance @UnfoldSingleThreadBg singleThreadBgExecutor: Executor, - @BindsInstance windowManager: IWindowManager, + @BindsInstance displayManager: DisplayManager, @BindsInstance @UnfoldTransitionATracePrefix tracingTagPrefix: String, ): RemoteUnfoldSharedComponent } diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt index 8eb79df55496..18399194434a 100644 --- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt +++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt @@ -19,8 +19,8 @@ package com.android.systemui.unfold import android.content.Context import android.hardware.SensorManager +import android.hardware.display.DisplayManager import android.os.Handler -import android.view.IWindowManager import com.android.systemui.unfold.config.UnfoldTransitionConfig import com.android.systemui.unfold.updates.FoldProvider import com.android.systemui.unfold.updates.screen.ScreenStatusProvider @@ -47,7 +47,7 @@ fun createUnfoldSharedComponent( mainExecutor: Executor, singleThreadBgExecutor: Executor, tracingTagPrefix: String, - windowManager: IWindowManager, + displayManager: DisplayManager, ): UnfoldSharedComponent = DaggerUnfoldSharedComponent.factory() .create( @@ -61,7 +61,7 @@ fun createUnfoldSharedComponent( mainExecutor, singleThreadBgExecutor, tracingTagPrefix, - windowManager, + displayManager, ) /** @@ -73,16 +73,18 @@ fun createRemoteUnfoldSharedComponent( context: Context, config: UnfoldTransitionConfig, mainExecutor: Executor, + mainHandler: Handler, singleThreadBgExecutor: Executor, tracingTagPrefix: String, - windowManager: IWindowManager, + displayManager: DisplayManager, ): RemoteUnfoldSharedComponent = DaggerRemoteUnfoldSharedComponent.factory() .create( context, config, mainExecutor, + mainHandler, singleThreadBgExecutor, - windowManager, + displayManager, tracingTagPrefix, ) diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt index d19b414cb963..28e493651137 100644 --- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt +++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt @@ -16,7 +16,6 @@ package com.android.systemui.unfold.progress import android.os.Trace -import android.os.Trace.TRACE_TAG_APP import android.util.Log import androidx.dynamicanimation.animation.DynamicAnimation import androidx.dynamicanimation.animation.FloatPropertyCompat @@ -110,7 +109,7 @@ class PhysicsBasedUnfoldTransitionProgressProvider @Inject constructor( if (DEBUG) { Log.d(TAG, "onFoldUpdate = ${update.name()}") - Trace.traceCounter(Trace.TRACE_TAG_APP, "fold_update", update) + Trace.setCounter("fold_update", update.toLong()) } } diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt index 82fd2258120a..d653fc7beff2 100644 --- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt +++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt @@ -119,7 +119,7 @@ constructor( "lastHingeAngle: $lastHingeAngle, " + "lastHingeAngleBeforeTransition: $lastHingeAngleBeforeTransition" ) - Trace.traceCounter(Trace.TRACE_TAG_APP, "hinge_angle", angle.toInt()) + Trace.setCounter( "hinge_angle", angle.toLong()) } val currentDirection = diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt index 0cf8224d3a3f..ce8f1a178d05 100644 --- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt +++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt @@ -17,36 +17,32 @@ package com.android.systemui.unfold.updates import android.content.Context +import android.hardware.display.DisplayManager +import android.os.Handler import android.os.RemoteException -import android.view.IRotationWatcher -import android.view.IWindowManager -import android.view.Surface.Rotation import com.android.systemui.unfold.dagger.UnfoldMain import com.android.systemui.unfold.util.CallbackController -import java.util.concurrent.Executor import javax.inject.Inject /** - * Allows to subscribe to rotation changes. - * - * This is needed as rotation updates from [IWindowManager] are received in a binder thread, while - * most of the times we want them in the main one. Updates are provided for the display associated + * Allows to subscribe to rotation changes. Updates are provided for the display associated * to [context]. */ class RotationChangeProvider @Inject constructor( - private val windowManagerInterface: IWindowManager, + private val displayManager: DisplayManager, private val context: Context, - @UnfoldMain private val mainExecutor: Executor, + @UnfoldMain private val mainHandler: Handler, ) : CallbackController<RotationChangeProvider.RotationListener> { private val listeners = mutableListOf<RotationListener>() - private val rotationWatcher = RotationWatcher() + private val displayListener = RotationDisplayListener() + private var lastRotation: Int? = null override fun addCallback(listener: RotationListener) { - mainExecutor.execute { + mainHandler.post { if (listeners.isEmpty()) { subscribeToRotation() } @@ -55,17 +51,18 @@ constructor( } override fun removeCallback(listener: RotationListener) { - mainExecutor.execute { + mainHandler.post { listeners -= listener if (listeners.isEmpty()) { unsubscribeToRotation() + lastRotation = null } } } private fun subscribeToRotation() { try { - windowManagerInterface.watchRotation(rotationWatcher, context.displayId) + displayManager.registerDisplayListener(displayListener, mainHandler) } catch (e: RemoteException) { throw e.rethrowFromSystemServer() } @@ -73,7 +70,7 @@ constructor( private fun unsubscribeToRotation() { try { - windowManagerInterface.removeRotationWatcher(rotationWatcher) + displayManager.unregisterDisplayListener(displayListener) } catch (e: RemoteException) { throw e.rethrowFromSystemServer() } @@ -82,12 +79,25 @@ constructor( /** Gets notified of rotation changes. */ fun interface RotationListener { /** Called once rotation changes. */ - fun onRotationChanged(@Rotation newRotation: Int) + fun onRotationChanged(newRotation: Int) } - private inner class RotationWatcher : IRotationWatcher.Stub() { - override fun onRotationChanged(rotation: Int) { - mainExecutor.execute { listeners.forEach { it.onRotationChanged(rotation) } } + private inner class RotationDisplayListener : DisplayManager.DisplayListener { + + override fun onDisplayChanged(displayId: Int) { + val display = context.display ?: return + + if (displayId == display.displayId) { + val currentRotation = display.rotation + if (lastRotation == null || lastRotation != currentRotation) { + listeners.forEach { it.onRotationChanged(currentRotation) } + lastRotation = currentRotation + } + } } + + override fun onDisplayAdded(displayId: Int) {} + + override fun onDisplayRemoved(displayId: Int) {} } } diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScaleAwareTransitionProgressProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScaleAwareTransitionProgressProvider.kt index 06ca153b694b..ce5c5f91914b 100644 --- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScaleAwareTransitionProgressProvider.kt +++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScaleAwareTransitionProgressProvider.kt @@ -79,10 +79,9 @@ constructor( companion object { fun ContentResolver.areAnimationsEnabled(): Boolean { val animationScale = - Settings.Global.getStringForUser( + Settings.Global.getString( this, Settings.Global.ANIMATOR_DURATION_SCALE, - this.userId ) ?.toFloatOrNull() ?: 1f diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScopedUnfoldTransitionProgressProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScopedUnfoldTransitionProgressProvider.kt index b7bab3e5ed5a..f9751d9c279c 100644 --- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScopedUnfoldTransitionProgressProvider.kt +++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScopedUnfoldTransitionProgressProvider.kt @@ -47,6 +47,7 @@ constructor(source: UnfoldTransitionProgressProvider? = null) : /** * Sets the source for the unfold transition progress updates. Replaces current provider if it * is already set + * * @param provider transition provider that emits transition progress updates */ fun setSourceProvider(provider: UnfoldTransitionProgressProvider?) { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index d78fe8628c60..f0dac2607a4e 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -3831,8 +3831,20 @@ public class ActivityManagerService extends IActivityManager.Stub Slog.w(TAG, msg); throw new SecurityException(msg); } + final int callingUid = Binder.getCallingUid(); + final int callingPid = Binder.getCallingPid(); + final int callingAppId = UserHandle.getAppId(callingUid); - userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), + ProcessRecord proc; + synchronized (mPidsSelfLocked) { + proc = mPidsSelfLocked.get(callingPid); + } + final boolean hasKillAllPermission = PERMISSION_GRANTED == checkPermission( + android.Manifest.permission.FORCE_STOP_PACKAGES, callingPid, callingUid) + || UserHandle.isCore(callingUid) + || (proc != null && proc.info.isSystemApp()); + + userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, true, ALLOW_FULL_ONLY, "killBackgroundProcesses", null); final int[] userIds = mUserController.expandUserId(userId); @@ -3847,7 +3859,7 @@ public class ActivityManagerService extends IActivityManager.Stub targetUserId)); } catch (RemoteException e) { } - if (appId == -1) { + if (appId == -1 || (!hasKillAllPermission && appId != callingAppId)) { Slog.w(TAG, "Invalid packageName: " + packageName); return; } @@ -3875,6 +3887,22 @@ public class ActivityManagerService extends IActivityManager.Stub throw new SecurityException(msg); } + final int callingUid = Binder.getCallingUid(); + final int callingPid = Binder.getCallingPid(); + + ProcessRecord proc; + synchronized (mPidsSelfLocked) { + proc = mPidsSelfLocked.get(callingPid); + } + if (callingUid >= FIRST_APPLICATION_UID + && (proc == null || !proc.info.isSystemApp())) { + final String msg = "Permission Denial: killAllBackgroundProcesses() from pid=" + + callingPid + ", uid=" + callingUid + " is not allowed"; + Slog.w(TAG, msg); + // Silently return to avoid existing apps from crashing. + return; + } + final long callingId = Binder.clearCallingIdentity(); try { synchronized (this) { @@ -13089,12 +13117,17 @@ public class ActivityManagerService extends IActivityManager.Stub public Intent registerReceiverWithFeature(IApplicationThread caller, String callerPackage, String callerFeatureId, String receiverId, IIntentReceiver receiver, IntentFilter filter, String permission, int userId, int flags) { + enforceNotIsolatedCaller("registerReceiver"); + // Allow Sandbox process to register only unexported receivers. - if ((flags & Context.RECEIVER_NOT_EXPORTED) != 0) { - enforceNotIsolatedCaller("registerReceiver"); - } else if (mSdkSandboxSettings.isBroadcastReceiverRestrictionsEnforced()) { - enforceNotIsolatedOrSdkSandboxCaller("registerReceiver"); + boolean unexported = (flags & Context.RECEIVER_NOT_EXPORTED) != 0; + if (mSdkSandboxSettings.isBroadcastReceiverRestrictionsEnforced() + && Process.isSdkSandboxUid(Binder.getCallingUid()) + && !unexported) { + throw new SecurityException("SDK sandbox process not allowed to call " + + "registerReceiver"); } + ArrayList<Intent> stickyIntents = null; ProcessRecord callerApp = null; final boolean visibleToInstantApps diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java index 2f95716639f0..207c10c44c9b 100644 --- a/services/core/java/com/android/server/am/BatteryStatsService.java +++ b/services/core/java/com/android/server/am/BatteryStatsService.java @@ -21,7 +21,6 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED; import static android.os.BatteryStats.POWER_DATA_UNAVAILABLE; import android.annotation.NonNull; -import android.app.AlarmManager; import android.app.StatsManager; import android.app.usage.NetworkStatsManager; import android.bluetooth.BluetoothActivityEnergyInfo; @@ -357,16 +356,6 @@ public final class BatteryStatsService extends IBatteryStats.Stub mStats.setRadioScanningTimeoutLocked(mContext.getResources().getInteger( com.android.internal.R.integer.config_radioScanningTimeout) * 1000L); mStats.setPowerProfileLocked(mPowerProfile); - - final boolean resetOnUnplugHighBatteryLevel = context.getResources().getBoolean( - com.android.internal.R.bool.config_batteryStatsResetOnUnplugHighBatteryLevel); - final boolean resetOnUnplugAfterSignificantCharge = context.getResources().getBoolean( - com.android.internal.R.bool.config_batteryStatsResetOnUnplugAfterSignificantCharge); - mStats.setBatteryStatsConfig( - new BatteryStatsImpl.BatteryStatsConfig.Builder() - .setResetOnUnplugHighBatteryLevel(resetOnUnplugHighBatteryLevel) - .setResetOnUnplugAfterSignificantCharge(resetOnUnplugAfterSignificantCharge) - .build()); mStats.startTrackingSystemServerCpuTime(); if (BATTERY_USAGE_STORE_ENABLED) { @@ -397,18 +386,6 @@ public final class BatteryStatsService extends IBatteryStats.Stub Slog.e(TAG, "Could not register INetworkManagement event observer " + e); } - final AlarmManager am = mContext.getSystemService(AlarmManager.class); - mHandler.post(() -> { - synchronized (mStats) { - mStats.setLongPlugInAlarmInterface(new AlarmInterface(am, () -> { - synchronized (mStats) { - if (mStats.isOnBattery()) return; - mStats.maybeResetWhilePluggedInLocked(); - } - })); - } - }); - synchronized (mPowerStatsLock) { mPowerStatsInternal = LocalServices.getService(PowerStatsInternal.class); if (mPowerStatsInternal != null) { @@ -2282,32 +2259,6 @@ public final class BatteryStatsService extends IBatteryStats.Stub } } - final class AlarmInterface implements BatteryStatsImpl.AlarmInterface, - AlarmManager.OnAlarmListener { - private AlarmManager mAm; - private Runnable mOnAlarm; - - AlarmInterface(AlarmManager am, Runnable onAlarm) { - mAm = am; - mOnAlarm = onAlarm; - } - - @Override - public void schedule(long rtcTimeMs, long windowLengthMs) { - mAm.setWindow(AlarmManager.RTC, rtcTimeMs, windowLengthMs, TAG, this, mHandler); - } - - @Override - public void cancel() { - mAm.cancel(this); - } - - @Override - public void onAlarm() { - mOnAlarm.run(); - } - } - private static native int nativeWaitWakeup(ByteBuffer outBuffer); private void dumpHelp(PrintWriter pw) { @@ -2494,8 +2445,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub } else if ("--reset-all".equals(arg)) { awaitCompletion(); synchronized (mStats) { - mStats.resetAllStatsAndHistoryLocked( - BatteryStatsImpl.RESET_REASON_ADB_COMMAND); + mStats.resetAllStatsCmdLocked(); mBatteryUsageStatsStore.removeAllSnapshots(); pw.println("Battery stats and history reset."); noOutput = true; @@ -2503,8 +2453,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub } else if ("--reset".equals(arg)) { awaitCompletion(); synchronized (mStats) { - mStats.resetAllStatsAndHistoryLocked( - BatteryStatsImpl.RESET_REASON_ADB_COMMAND); + mStats.resetAllStatsCmdLocked(); pw.println("Battery stats reset."); noOutput = true; } diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 9700e562b518..8c9373b98c58 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -3005,9 +3005,10 @@ public final class ProcessList { hostingRecord.getDefiningUid(), hostingRecord.getDefiningProcessName()); final ProcessStateRecord state = r.mState; - if (!mService.mBooted && !mService.mBooting + if (!isolated && !isSdkSandbox && userId == UserHandle.USER_SYSTEM - && (info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) { + && (info.flags & PERSISTENT_MASK) == PERSISTENT_MASK + && (TextUtils.equals(proc, info.processName))) { // The system process is initialized to SCHED_GROUP_DEFAULT in init.rc. state.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_DEFAULT); state.setSetSchedGroup(ProcessList.SCHED_GROUP_DEFAULT); diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 9f1512825c3a..521f342455d6 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -8396,7 +8396,9 @@ public class AudioService extends IAudioService.Stub if (isMutable()) { // For call stream, align mute only when muted, not when index is set to 0 mVolumeGroupState.mute( - forceMuteState ? mIsMuted : groupIndex == 0 || mIsMuted); + forceMuteState ? mIsMuted : + (groupIndex == 0 && !isCallStream(mStreamType)) + || mIsMuted); } } } diff --git a/services/core/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java index 76d71e2b968a..bb39307bdc0d 100644 --- a/services/core/java/com/android/server/display/DisplayDevice.java +++ b/services/core/java/com/android/server/display/DisplayDevice.java @@ -22,6 +22,7 @@ import android.graphics.Point; import android.graphics.Rect; import android.hardware.display.DisplayViewport; import android.os.IBinder; +import android.util.Slog; import android.view.Display; import android.view.DisplayAddress; import android.view.Surface; @@ -37,6 +38,7 @@ import java.io.PrintWriter; * </p> */ abstract class DisplayDevice { + private static final String TAG = "DisplayDevice"; private static final Display.Mode EMPTY_DISPLAY_MODE = new Display.Mode.Builder().build(); private final DisplayAdapter mDisplayAdapter; @@ -266,10 +268,13 @@ abstract class DisplayDevice { /** * Sets the display layer stack while in a transaction. */ - public final void setLayerStackLocked(SurfaceControl.Transaction t, int layerStack) { + public final void setLayerStackLocked(SurfaceControl.Transaction t, int layerStack, + int layerStackTag) { if (mCurrentLayerStack != layerStack) { mCurrentLayerStack = layerStack; t.setDisplayLayerStack(mDisplayToken, layerStack); + Slog.i(TAG, "[" + layerStackTag + "] Layerstack set to " + layerStack + " for " + + mUniqueId); } } diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java index e6f27c1b0dd9..7dc412ed1cf8 100644 --- a/services/core/java/com/android/server/display/LogicalDisplay.java +++ b/services/core/java/com/android/server/display/LogicalDisplay.java @@ -494,7 +494,7 @@ final class LogicalDisplay { DisplayDevice device, boolean isBlanked) { // Set the layer stack. - device.setLayerStackLocked(t, isBlanked ? BLANK_LAYER_STACK : mLayerStack); + device.setLayerStackLocked(t, isBlanked ? BLANK_LAYER_STACK : mLayerStack, mDisplayId); // Also inform whether the device is the same one sent to inputflinger for its layerstack. // Prevent displays that are disabled from receiving input. // TODO(b/188914255): Remove once input can dispatch against device vs layerstack. diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java index 350aa6b2f686..2a807b2a3ef3 100644 --- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java +++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java @@ -608,6 +608,9 @@ class MediaRouter2ServiceImpl { /* package */ void updateRunningUserAndProfiles(int newActiveUserId) { synchronized (mLock) { if (mCurrentActiveUserId != newActiveUserId) { + Slog.i(TAG, TextUtils.formatSimple( + "switchUser | user: %d", newActiveUserId)); + mCurrentActiveUserId = newActiveUserId; for (int i = 0; i < mUserRecords.size(); i++) { int userId = mUserRecords.keyAt(i); @@ -679,6 +682,10 @@ class MediaRouter2ServiceImpl { userRecord.mHandler.sendMessage( obtainMessage(UserHandler::notifyRouterRegistered, userRecord.mHandler, routerRecord)); + + Slog.i(TAG, TextUtils.formatSimple( + "registerRouter2 | package: %s, uid: %d, pid: %d, router: %d", + packageName, uid, pid, routerRecord.mRouterId)); } @GuardedBy("mLock") @@ -689,6 +696,11 @@ class MediaRouter2ServiceImpl { return; } + Slog.i(TAG, TextUtils.formatSimple( + "unregisterRouter2 | package: %s, router: %d", + routerRecord.mPackageName, + routerRecord.mRouterId)); + UserRecord userRecord = routerRecord.mUserRecord; userRecord.mRouterRecords.remove(routerRecord); routerRecord.mUserRecord.mHandler.sendMessage( @@ -707,6 +719,11 @@ class MediaRouter2ServiceImpl { if (routerRecord.mDiscoveryPreference.equals(discoveryRequest)) { return; } + + Slog.i(TAG, TextUtils.formatSimple( + "setDiscoveryRequestWithRouter2 | router: %d, discovery request: %s", + routerRecord.mRouterId, discoveryRequest.toString())); + routerRecord.mDiscoveryPreference = discoveryRequest; routerRecord.mUserRecord.mHandler.sendMessage( obtainMessage(UserHandler::notifyDiscoveryPreferenceChangedToManagers, @@ -724,6 +741,10 @@ class MediaRouter2ServiceImpl { RouterRecord routerRecord = mAllRouterRecords.get(binder); if (routerRecord != null) { + Slog.i(TAG, TextUtils.formatSimple( + "setRouteVolumeWithRouter2 | router: %d, volume: %d", + routerRecord.mRouterId, volume)); + routerRecord.mUserRecord.mHandler.sendMessage( obtainMessage(UserHandler::setRouteVolumeOnHandler, routerRecord.mUserRecord.mHandler, @@ -804,6 +825,10 @@ class MediaRouter2ServiceImpl { return; } + Slog.i(TAG, TextUtils.formatSimple( + "selectRouteWithRouter2 | router: %d, route: %s", + routerRecord.mRouterId, route.getId())); + routerRecord.mUserRecord.mHandler.sendMessage( obtainMessage(UserHandler::selectRouteOnHandler, routerRecord.mUserRecord.mHandler, @@ -819,6 +844,10 @@ class MediaRouter2ServiceImpl { return; } + Slog.i(TAG, TextUtils.formatSimple( + "deselectRouteWithRouter2 | router: %d, route: %s", + routerRecord.mRouterId, route.getId())); + routerRecord.mUserRecord.mHandler.sendMessage( obtainMessage(UserHandler::deselectRouteOnHandler, routerRecord.mUserRecord.mHandler, @@ -834,6 +863,10 @@ class MediaRouter2ServiceImpl { return; } + Slog.i(TAG, TextUtils.formatSimple( + "transferToRouteWithRouter2 | router: %d, route: %s", + routerRecord.mRouterId, route.getId())); + String defaultRouteId = routerRecord.mUserRecord.mHandler.mSystemProvider.getDefaultRoute().getId(); if (route.isSystemRoute() && !routerRecord.mHasModifyAudioRoutingPermission @@ -859,6 +892,10 @@ class MediaRouter2ServiceImpl { return; } + Slog.i(TAG, TextUtils.formatSimple( + "setSessionVolumeWithRouter2 | router: %d, session: %s, volume: %d", + routerRecord.mRouterId, uniqueSessionId, volume)); + routerRecord.mUserRecord.mHandler.sendMessage( obtainMessage(UserHandler::setSessionVolumeOnHandler, routerRecord.mUserRecord.mHandler, @@ -874,6 +911,10 @@ class MediaRouter2ServiceImpl { return; } + Slog.i(TAG, TextUtils.formatSimple( + "releaseSessionWithRouter2 | router: %d, session: %s", + routerRecord.mRouterId, uniqueSessionId)); + routerRecord.mUserRecord.mHandler.sendMessage( obtainMessage(UserHandler::releaseSessionOnHandler, routerRecord.mUserRecord.mHandler, @@ -916,6 +957,10 @@ class MediaRouter2ServiceImpl { return; } + Slog.i(TAG, TextUtils.formatSimple( + "registerManager | uid: %d, pid: %d, package: %s, user: %d", + uid, pid, packageName, userId)); + mContext.enforcePermission(Manifest.permission.MEDIA_CONTENT_CONTROL, pid, uid, "Must hold MEDIA_CONTENT_CONTROL permission."); @@ -951,6 +996,13 @@ class MediaRouter2ServiceImpl { return; } UserRecord userRecord = managerRecord.mUserRecord; + + Slog.i(TAG, TextUtils.formatSimple( + "unregisterManager | package: %s, user: %d, manager: %d", + managerRecord.mPackageName, + userRecord.mUserId, + managerRecord.mManagerId)); + userRecord.mManagerRecords.remove(managerRecord); managerRecord.dispose(); disposeUserIfNeededLocked(userRecord); // since manager removed from user @@ -962,6 +1014,10 @@ class MediaRouter2ServiceImpl { if (managerRecord == null) { return; } + + Slog.i(TAG, TextUtils.formatSimple( + "startScan | manager: %d", managerRecord.mManagerId)); + managerRecord.startScan(); } @@ -971,6 +1027,10 @@ class MediaRouter2ServiceImpl { if (managerRecord == null) { return; } + + Slog.i(TAG, TextUtils.formatSimple( + "stopScan | manager: %d", managerRecord.mManagerId)); + managerRecord.stopScan(); } @@ -984,6 +1044,10 @@ class MediaRouter2ServiceImpl { return; } + Slog.i(TAG, TextUtils.formatSimple( + "setRouteVolumeWithManager | manager: %d, route: %s, volume: %d", + managerRecord.mManagerId, route.getId(), volume)); + long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId); managerRecord.mUserRecord.mHandler.sendMessage( obtainMessage(UserHandler::setRouteVolumeOnHandler, @@ -999,6 +1063,10 @@ class MediaRouter2ServiceImpl { return; } + Slog.i(TAG, TextUtils.formatSimple( + "requestCreateSessionWithManager | manager: %d, route: %s", + managerRecord.mManagerId, route.getId())); + String packageName = oldSession.getClientPackageName(); RouterRecord routerRecord = managerRecord.mUserRecord.findRouterRecordLocked(packageName); @@ -1044,6 +1112,10 @@ class MediaRouter2ServiceImpl { return; } + Slog.i(TAG, TextUtils.formatSimple( + "selectRouteWithManager | manager: %d, session: %s, route: %s", + managerRecord.mManagerId, uniqueSessionId, route.getId())); + // Can be null if the session is system's or RCN. RouterRecord routerRecord = managerRecord.mUserRecord.mHandler .findRouterWithSessionLocked(uniqueSessionId); @@ -1065,6 +1137,10 @@ class MediaRouter2ServiceImpl { return; } + Slog.i(TAG, TextUtils.formatSimple( + "deselectRouteWithManager | manager: %d, session: %s, route: %s", + managerRecord.mManagerId, uniqueSessionId, route.getId())); + // Can be null if the session is system's or RCN. RouterRecord routerRecord = managerRecord.mUserRecord.mHandler .findRouterWithSessionLocked(uniqueSessionId); @@ -1086,6 +1162,10 @@ class MediaRouter2ServiceImpl { return; } + Slog.i(TAG, TextUtils.formatSimple( + "transferToRouteWithManager | manager: %d, session: %s, route: %s", + managerRecord.mManagerId, uniqueSessionId, route.getId())); + // Can be null if the session is system's or RCN. RouterRecord routerRecord = managerRecord.mUserRecord.mHandler .findRouterWithSessionLocked(uniqueSessionId); @@ -1107,6 +1187,10 @@ class MediaRouter2ServiceImpl { return; } + Slog.i(TAG, TextUtils.formatSimple( + "setSessionVolumeWithManager | manager: %d, session: %s, volume: %d", + managerRecord.mManagerId, uniqueSessionId, volume)); + long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId); managerRecord.mUserRecord.mHandler.sendMessage( obtainMessage(UserHandler::setSessionVolumeOnHandler, @@ -1124,6 +1208,10 @@ class MediaRouter2ServiceImpl { return; } + Slog.i(TAG, TextUtils.formatSimple( + "releaseSessionWithManager | manager: %d, session: %s", + managerRecord.mManagerId, uniqueSessionId)); + RouterRecord routerRecord = managerRecord.mUserRecord.mHandler .findRouterWithSessionLocked(uniqueSessionId); @@ -1484,6 +1572,24 @@ class MediaRouter2ServiceImpl { List<IMediaRouter2> routersWithModifyAudioRoutingPermission = getRouters(true); List<IMediaRouter2> routersWithoutModifyAudioRoutingPermission = getRouters(false); + + if (!addedRoutes.isEmpty()) { + // If routes were added, currentInfo cannot be null. + Slog.i(TAG, + toLoggingMessage( + /* source= */ "addProviderRoutes", + currentInfo.getUniqueId(), + (ArrayList) addedRoutes)); + } + if (!removedRoutes.isEmpty()) { + // If routes were removed, prevInfo cannot be null. + Slog.i(TAG, + toLoggingMessage( + /* source= */ "removeProviderRoutes", + prevInfo.getUniqueId(), + (ArrayList) removedRoutes)); + } + List<IMediaRouter2Manager> managers = getManagers(); List<MediaRoute2Info> defaultRoute = new ArrayList<>(); defaultRoute.add(mSystemProvider.getDefaultRoute()); @@ -1522,6 +1628,16 @@ class MediaRouter2ServiceImpl { } } + private static String toLoggingMessage( + String source, String providerId, ArrayList<MediaRoute2Info> routes) { + String routesString = + routes.stream() + .map(it -> String.format("%s | %s", it.getOriginalId(), it.getName())) + .collect(Collectors.joining(/* delimiter= */ ", ")); + return TextUtils.formatSimple("%s | provider: %s, routes: [%s]", + source, providerId, routesString); + } + private int getLastProviderInfoIndex(@NonNull String providerId) { for (int i = 0; i < mLastProviderInfos.size(); i++) { MediaRoute2ProviderInfo providerInfo = mLastProviderInfos.get(i); diff --git a/services/core/java/com/android/server/media/MediaSessionStack.java b/services/core/java/com/android/server/media/MediaSessionStack.java index b75ba75e028b..c5a337d853a6 100644 --- a/services/core/java/com/android/server/media/MediaSessionStack.java +++ b/services/core/java/com/android/server/media/MediaSessionStack.java @@ -21,7 +21,9 @@ import static com.android.server.media.MediaSessionPolicyProvider.SESSION_POLICY import android.media.Session2Token; import android.media.session.MediaSession; import android.os.UserHandle; +import android.text.TextUtils; import android.util.Log; +import android.util.Slog; import android.util.SparseArray; import java.io.PrintWriter; @@ -82,6 +84,10 @@ class MediaSessionStack { * @param record The record to add. */ public void addSession(MediaSessionRecordImpl record) { + Slog.i(TAG, TextUtils.formatSimple( + "addSession to bottom of stack | record: %s", + record + )); mSessions.add(record); clearCache(record.getUserId()); @@ -97,6 +103,10 @@ class MediaSessionStack { * @param record The record to remove. */ public void removeSession(MediaSessionRecordImpl record) { + Slog.i(TAG, TextUtils.formatSimple( + "removeSession | record: %s", + record + )); mSessions.remove(record); if (mMediaButtonSession == record) { // When the media button session is removed, nullify the media button session and do not @@ -142,6 +152,10 @@ class MediaSessionStack { public void onPlaybackStateChanged( MediaSessionRecordImpl record, boolean shouldUpdatePriority) { if (shouldUpdatePriority) { + Slog.i(TAG, TextUtils.formatSimple( + "onPlaybackStateChanged - Pushing session to top | record: %s", + record + )); mSessions.remove(record); mSessions.add(0, record); clearCache(record.getUserId()); diff --git a/services/core/java/com/android/server/media/projection/OWNERS b/services/core/java/com/android/server/media/projection/OWNERS index 9ca391013aa3..832bcd9d70e6 100644 --- a/services/core/java/com/android/server/media/projection/OWNERS +++ b/services/core/java/com/android/server/media/projection/OWNERS @@ -1,2 +1 @@ -michaelwr@google.com -santoscordon@google.com +include /media/java/android/media/projection/OWNERS diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index ab7292d49c7d..6e342939c95a 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -152,6 +152,13 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S_V2) static final long REQUEST_LISTENING_MUST_MATCH_PACKAGE = 172251878L; + /** + * @hide + */ + @ChangeId + @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.TIRAMISU) + static final long REQUEST_LISTENING_OTHER_USER_NOOP = 242194868L; + private final Context mContext; private final Handler mHandler = new Handler(); @@ -1859,7 +1866,12 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D // Check current user if (userId != currentUser) { - throw new IllegalArgumentException("User " + userId + " is not the current user."); + if (CompatChanges.isChangeEnabled(REQUEST_LISTENING_OTHER_USER_NOOP, callingUid)) { + return; + } else { + throw new IllegalArgumentException( + "User " + userId + " is not the current user."); + } } } if (mBar != null) { diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java index 7489f80946eb..7c9244e39e67 100644 --- a/services/core/java/com/android/server/wm/ActivityClientController.java +++ b/services/core/java/com/android/server/wm/ActivityClientController.java @@ -696,6 +696,8 @@ class ActivityClientController extends IActivityClientController.Stub { synchronized (mGlobalLock) { final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token); if (r != null) { + EventLogTags.writeWmSetRequestedOrientation(requestedOrientation, + r.shortComponentName); r.setRequestedOrientation(requestedOrientation); } } diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 5f8e01e583c4..de5defa1bcd4 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -1487,6 +1487,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A mLastReportedMultiWindowMode = inPictureInPictureMode; ensureActivityConfiguration(0 /* globalChanges */, PRESERVE_WINDOWS, true /* ignoreVisibility */); + if (inPictureInPictureMode && findMainWindow() == null) { + // Prevent malicious app entering PiP without valid WindowState, which can in turn + // result a non-touchable PiP window since the InputConsumer for PiP requires it. + EventLog.writeEvent(0x534e4554, "265293293", -1, ""); + removeImmediately(); + } } } @@ -7973,11 +7979,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return false; } } - // Activity should be resizable if the task is. - final boolean isResizeable = task != null - ? task.isResizeable() || isResizeable() - : isResizeable(); - return !isResizeable && (info.isFixedOrientation() || hasFixedAspectRatio()) + return !isResizeable() && (info.isFixedOrientation() || hasFixedAspectRatio()) // The configuration of non-standard type should be enforced by system. // {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD} is set when this activity is // added to a task, but this function is called when resolving the launch params, at @@ -8012,9 +8014,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // The smallest screen width is the short side of screen bounds. Because the bounds // and density won't be changed, smallestScreenWidthDp is also fixed. overrideConfig.smallestScreenWidthDp = fullConfig.smallestScreenWidthDp; - // TODO(b/264276741): Check whether the runtime orietnation request is fixed rather than - // the manifest orientation which may be obsolete. - if (info.isFixedOrientation()) { + if (ActivityInfo.isFixedOrientation(getOverrideOrientation())) { // lock rotation too. When in size-compat, onConfigurationChanged will watch for and // apply runtime rotation changes. overrideConfig.windowConfiguration.setRotation( @@ -8039,7 +8039,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } // Clear config override in #updateCompatDisplayInsets(). - onRequestedOverrideConfigurationChanged(EMPTY); + final int activityType = getActivityType(); + final Configuration overrideConfig = getRequestedOverrideConfiguration(); + overrideConfig.unset(); + // Keep the activity type which was set when attaching to a task to prevent leaving it + // undefined. + overrideConfig.windowConfiguration.setActivityType(activityType); + onRequestedOverrideConfigurationChanged(overrideConfig); } @Override @@ -8099,9 +8105,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (isFixedOrientationLetterboxAllowed) { resolveFixedOrientationConfiguration(newParentConfiguration); } - - if (getCompatDisplayInsets() != null) { - resolveSizeCompatModeConfiguration(newParentConfiguration); + final CompatDisplayInsets compatDisplayInsets = getCompatDisplayInsets(); + if (compatDisplayInsets != null) { + resolveSizeCompatModeConfiguration(newParentConfiguration, compatDisplayInsets); } else if (inMultiWindowMode() && !isFixedOrientationLetterboxAllowed) { // We ignore activities' requested orientation in multi-window modes. They may be // taken into consideration in resolveFixedOrientationConfiguration call above. @@ -8118,7 +8124,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A resolveAspectRatioRestriction(newParentConfiguration); } - if (isFixedOrientationLetterboxAllowed || getCompatDisplayInsets() != null + if (isFixedOrientationLetterboxAllowed || compatDisplayInsets != null // In fullscreen, can be letterboxed for aspect ratio. || !inMultiWindowMode()) { updateResolvedBoundsPosition(newParentConfiguration); @@ -8126,7 +8132,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A boolean isIgnoreOrientationRequest = mDisplayContent != null && mDisplayContent.getIgnoreOrientationRequest(); - if (getCompatDisplayInsets() == null + if (compatDisplayInsets == null // for size compat mode set in updateCompatDisplayInsets // Fixed orientation letterboxing is possible on both large screen devices // with ignoreOrientationRequest enabled and on phones in split screen even with @@ -8173,7 +8179,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A info.neverSandboxDisplayApis(sConstrainDisplayApisConfig), info.alwaysSandboxDisplayApis(sConstrainDisplayApisConfig), !matchParentBounds(), - getCompatDisplayInsets() != null, + compatDisplayInsets != null, shouldCreateCompatDisplayInsets()); } resolvedConfig.windowConfiguration.setMaxBounds(mTmpBounds); @@ -8185,7 +8191,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A /** * @return The orientation to use to understand if reachability is enabled. */ - @ActivityInfo.ScreenOrientation + @Configuration.Orientation int getOrientationForReachability() { return mLetterboxUiController.hasInheritedLetterboxBehavior() ? mLetterboxUiController.getInheritedOrientation() @@ -8581,7 +8587,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A * Resolves consistent screen configuration for orientation and rotation changes without * inheriting the parent bounds. */ - private void resolveSizeCompatModeConfiguration(Configuration newParentConfiguration) { + private void resolveSizeCompatModeConfiguration(Configuration newParentConfiguration, + @NonNull CompatDisplayInsets compatDisplayInsets) { final Configuration resolvedConfig = getResolvedOverrideConfiguration(); final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds(); @@ -8602,13 +8609,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A ? requestedOrientation // We should use the original orientation of the activity when possible to avoid // forcing the activity in the opposite orientation. - : getCompatDisplayInsets().mOriginalRequestedOrientation != ORIENTATION_UNDEFINED - ? getCompatDisplayInsets().mOriginalRequestedOrientation + : compatDisplayInsets.mOriginalRequestedOrientation != ORIENTATION_UNDEFINED + ? compatDisplayInsets.mOriginalRequestedOrientation : newParentConfiguration.orientation; int rotation = newParentConfiguration.windowConfiguration.getRotation(); final boolean isFixedToUserRotation = mDisplayContent == null || mDisplayContent.getDisplayRotation().isFixedToUserRotation(); - if (!isFixedToUserRotation && !getCompatDisplayInsets().mIsFloating) { + if (!isFixedToUserRotation && !compatDisplayInsets.mIsFloating) { // Use parent rotation because the original display can be rotated. resolvedConfig.windowConfiguration.setRotation(rotation); } else { @@ -8624,11 +8631,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // rely on them to contain the original and unchanging width and height of the app. final Rect containingAppBounds = new Rect(); final Rect containingBounds = mTmpBounds; - getCompatDisplayInsets().getContainerBounds(containingAppBounds, containingBounds, rotation, + compatDisplayInsets.getContainerBounds(containingAppBounds, containingBounds, rotation, orientation, orientationRequested, isFixedToUserRotation); resolvedBounds.set(containingBounds); // The size of floating task is fixed (only swap), so the aspect ratio is already correct. - if (!getCompatDisplayInsets().mIsFloating) { + if (!compatDisplayInsets.mIsFloating) { mIsAspectRatioApplied = applyAspectRatio(resolvedBounds, containingAppBounds, containingBounds); } @@ -8637,7 +8644,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // are calculated in compat container space. The actual position on screen will be applied // later, so the calculation is simpler that doesn't need to involve offset from parent. getTaskFragment().computeConfigResourceOverrides(resolvedConfig, newParentConfiguration, - getCompatDisplayInsets()); + compatDisplayInsets); // Use current screen layout as source because the size of app is independent to parent. resolvedConfig.screenLayout = TaskFragment.computeScreenLayoutOverride( getConfiguration().screenLayout, resolvedConfig.screenWidthDp, diff --git a/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java b/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java index 47bdba34ee24..41eb2c92923f 100644 --- a/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java @@ -359,12 +359,6 @@ final class DisplayRotationCompatPolicy { CAMERA_OPENED_ROTATION_UPDATE_DELAY_MS); } - private void updateOrientationWithWmLock() { - synchronized (mWmService.mGlobalLock) { - mDisplayContent.updateOrientation(); - } - } - private void delayedUpdateOrientationWithWmLock( @NonNull String cameraId, @NonNull String packageName) { synchronized (this) { @@ -375,25 +369,28 @@ final class DisplayRotationCompatPolicy { } mCameraIdPackageBiMap.put(packageName, cameraId); } - ActivityRecord topActivity = mDisplayContent.topRunningActivity( - /* considerKeyguardState= */ true); - if (topActivity == null || topActivity.getTask() == null) { - return; - } - // Checking whether an activity in fullscreen rather than the task as this camera compat - // treatment doesn't cover activity embedding. - if (topActivity.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) { - if (topActivity.mLetterboxUiController.isOverrideOrientationOnlyForCameraEnabled()) { - topActivity.recomputeConfiguration(); + synchronized (mWmService.mGlobalLock) { + ActivityRecord topActivity = mDisplayContent.topRunningActivity( + /* considerKeyguardState= */ true); + if (topActivity == null || topActivity.getTask() == null) { + return; + } + // Checking whether an activity in fullscreen rather than the task as this camera + // compat treatment doesn't cover activity embedding. + if (topActivity.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) { + if (topActivity.mLetterboxUiController + .isOverrideOrientationOnlyForCameraEnabled()) { + topActivity.recomputeConfiguration(); + } + mDisplayContent.updateOrientation(); + return; + } + // Checking that the whole app is in multi-window mode as we shouldn't show toast + // for the activity embedding case. + if (topActivity.getTask().getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW + && isTreatmentEnabledForActivity(topActivity, /* mustBeFullscreen */ false)) { + showToast(R.string.display_rotation_camera_compat_toast_in_split_screen); } - updateOrientationWithWmLock(); - return; - } - // Checking that the whole app is in multi-window mode as we shouldn't show toast - // for the activity embedding case. - if (topActivity.getTask().getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW - && isTreatmentEnabledForActivity(topActivity, /* mustBeFullscreen */ false)) { - showToast(R.string.display_rotation_camera_compat_toast_in_split_screen); } } @@ -441,18 +438,20 @@ final class DisplayRotationCompatPolicy { ProtoLog.v(WM_DEBUG_ORIENTATION, "Display id=%d is notified that Camera %s is closed, updating rotation.", mDisplayContent.mDisplayId, cameraId); - ActivityRecord topActivity = mDisplayContent.topRunningActivity( - /* considerKeyguardState= */ true); - if (topActivity == null - // Checking whether an activity in fullscreen rather than the task as this camera - // compat treatment doesn't cover activity embedding. - || topActivity.getWindowingMode() != WINDOWING_MODE_FULLSCREEN) { - return; - } - if (topActivity.mLetterboxUiController.isOverrideOrientationOnlyForCameraEnabled()) { - topActivity.recomputeConfiguration(); + synchronized (mWmService.mGlobalLock) { + ActivityRecord topActivity = mDisplayContent.topRunningActivity( + /* considerKeyguardState= */ true); + if (topActivity == null + // Checking whether an activity in fullscreen rather than the task as this + // camera compat treatment doesn't cover activity embedding. + || topActivity.getWindowingMode() != WINDOWING_MODE_FULLSCREEN) { + return; + } + if (topActivity.mLetterboxUiController.isOverrideOrientationOnlyForCameraEnabled()) { + topActivity.recomputeConfiguration(); + } + mDisplayContent.updateOrientation(); } - updateOrientationWithWmLock(); } private boolean isActivityForCameraIdRefreshing(String cameraId) { diff --git a/services/core/java/com/android/server/wm/EventLogTags.logtags b/services/core/java/com/android/server/wm/EventLogTags.logtags index 1e5a219e5e52..48ce22e227dd 100644 --- a/services/core/java/com/android/server/wm/EventLogTags.logtags +++ b/services/core/java/com/android/server/wm/EventLogTags.logtags @@ -1,4 +1,4 @@ -# See system/core/logcat/event.logtags for a description of the format of this file. +# See system/logging/logcat/event.logtags for a description of the format of this file. option java_package com.android.server.wm @@ -62,6 +62,10 @@ option java_package com.android.server.wm 31002 wm_task_moved (TaskId|1|5),(ToTop|1),(Index|1) # Task removed with source explanation. 31003 wm_task_removed (TaskId|1|5),(Reason|3) + +# Set the requested orientation of an activity. +31006 wm_set_requested_orientation (Orientation|1|5),(Component Name|3) + # bootanim finished: 31007 wm_boot_animation_done (time|2|3) diff --git a/services/core/java/com/android/server/wm/LetterboxConfigurationPersister.java b/services/core/java/com/android/server/wm/LetterboxConfigurationPersister.java index 4a99db594755..3b10debaa753 100644 --- a/services/core/java/com/android/server/wm/LetterboxConfigurationPersister.java +++ b/services/core/java/com/android/server/wm/LetterboxConfigurationPersister.java @@ -216,6 +216,10 @@ class LetterboxConfigurationPersister { } private void readCurrentConfiguration() { + if (!mConfigurationFile.exists()) { + useDefaultValue(); + return; + } FileInputStream fis = null; try { fis = mConfigurationFile.openRead(); diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java index e1dbe01aca61..d9f2b6e4a0a3 100644 --- a/services/core/java/com/android/server/wm/LetterboxUiController.java +++ b/services/core/java/com/android/server/wm/LetterboxUiController.java @@ -870,10 +870,9 @@ final class LetterboxUiController { return mActivityRecord.mWmService.mContext.getResources(); } - private void handleHorizontalDoubleTap(int x) { - // TODO(b/260857308): Investigate if enabling reachability for translucent activity - if (hasInheritedLetterboxBehavior() || !isHorizontalReachabilityEnabled() - || mActivityRecord.isInTransition()) { + @VisibleForTesting + void handleHorizontalDoubleTap(int x) { + if (!isHorizontalReachabilityEnabled() || mActivityRecord.isInTransition()) { return; } @@ -911,10 +910,9 @@ final class LetterboxUiController { mActivityRecord.recomputeConfiguration(); } - private void handleVerticalDoubleTap(int y) { - // TODO(b/260857308): Investigate if enabling reachability for translucent activity - if (hasInheritedLetterboxBehavior() || !isVerticalReachabilityEnabled() - || mActivityRecord.isInTransition()) { + @VisibleForTesting + void handleVerticalDoubleTap(int y) { + if (!isVerticalReachabilityEnabled() || mActivityRecord.isInTransition()) { return; } @@ -1435,7 +1433,7 @@ final class LetterboxUiController { * the first opaque activity beneath. */ boolean hasInheritedLetterboxBehavior() { - return mLetterboxConfigListener != null && !mActivityRecord.matchParentBounds(); + return mLetterboxConfigListener != null; } /** diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java index 79be9463aa05..2086b522aa66 100644 --- a/services/core/java/com/android/server/wm/TaskDisplayArea.java +++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java @@ -1222,7 +1222,7 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> { // Clear last paused activity if focused root task changed while sleeping, so that the // top activity of current focused task can be resumed. - if (mDisplayContent.isSleeping()) { + if (mDisplayContent.isSleeping() && currentFocusedTask != null) { currentFocusedTask.clearLastPausedActivity(); } diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index ce032442e4af..9e0e8c477573 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -1436,7 +1436,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< * {@link Configuration#ORIENTATION_PORTRAIT}, * {@link Configuration#ORIENTATION_UNDEFINED}). */ - @ScreenOrientation + @Configuration.Orientation int getRequestedConfigurationOrientation() { return getRequestedConfigurationOrientation(false /* forDisplay */); } @@ -1454,7 +1454,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< * {@link Configuration#ORIENTATION_PORTRAIT}, * {@link Configuration#ORIENTATION_UNDEFINED}). */ - @ScreenOrientation + @Configuration.Orientation int getRequestedConfigurationOrientation(boolean forDisplay) { int requestedOrientation = getOverrideOrientation(); final RootDisplayArea root = getRootDisplayArea(); diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 8931d8030df2..e6c1e75da581 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -6198,9 +6198,10 @@ public class WindowManagerService extends IWindowManager.Stub waitingForConfig = waitingForRemoteDisplayChange = false; numOpeningApps = 0; } - if (waitingForConfig || waitingForRemoteDisplayChange || mAppsFreezingScreen > 0 - || mWindowsFreezingScreen == WINDOWS_FREEZING_SCREENS_ACTIVE - || mClientFreezingScreen || numOpeningApps > 0) { + final boolean waitingForApps = mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_TIMEOUT + && (mAppsFreezingScreen > 0 || numOpeningApps > 0); + if (waitingForConfig || waitingForRemoteDisplayChange || waitingForApps + || mClientFreezingScreen) { ProtoLog.d(WM_DEBUG_ORIENTATION, "stopFreezingDisplayLocked: Returning " + "waitingForConfig=%b, waitingForRemoteDisplayChange=%b, " + "mAppsFreezingScreen=%d, mWindowsFreezingScreen=%d, " diff --git a/services/people/java/com/android/server/people/data/DataManager.java b/services/people/java/com/android/server/people/data/DataManager.java index 37f0624464e5..eff9e8da9a76 100644 --- a/services/people/java/com/android/server/people/data/DataManager.java +++ b/services/people/java/com/android/server/people/data/DataManager.java @@ -113,7 +113,6 @@ public class DataManager { private static final long USAGE_STATS_QUERY_INTERVAL_SEC = 120L; @VisibleForTesting static final int MAX_CACHED_RECENT_SHORTCUTS = 30; - private static final int DEBOUNCE_LENGTH_MS = 500; private final Context mContext; private final Injector mInjector; @@ -130,7 +129,6 @@ public class DataManager { private final List<PeopleService.ConversationsListener> mConversationsListeners = new ArrayList<>(1); private final Handler mHandler; - private final PerPackageThrottler mShortcutsThrottler; private ContentObserver mCallLogContentObserver; private ContentObserver mMmsSmsContentObserver; @@ -142,17 +140,14 @@ public class DataManager { private ConversationStatusExpirationBroadcastReceiver mStatusExpReceiver; public DataManager(Context context) { - this(context, new Injector(), BackgroundThread.get().getLooper(), - new PerPackageThrottlerImpl(BackgroundThread.getHandler(), DEBOUNCE_LENGTH_MS)); + this(context, new Injector(), BackgroundThread.get().getLooper()); } - DataManager(Context context, Injector injector, Looper looper, - PerPackageThrottler shortcutsThrottler) { + DataManager(Context context, Injector injector, Looper looper) { mContext = context; mInjector = injector; mScheduledExecutor = mInjector.createScheduledExecutor(); mHandler = new Handler(looper); - mShortcutsThrottler = shortcutsThrottler; } /** Initialization. Called when the system services are up running. */ @@ -856,12 +851,12 @@ public class DataManager { // pair of <package name, conversation info> List<Pair<String, ConversationInfo>> cachedConvos = new ArrayList<>(); userData.forAllPackages(packageData -> { - packageData.forAllConversations(conversationInfo -> { - if (isEligibleForCleanUp(conversationInfo)) { - cachedConvos.add( - Pair.create(packageData.getPackageName(), conversationInfo)); - } - }); + packageData.forAllConversations(conversationInfo -> { + if (isEligibleForCleanUp(conversationInfo)) { + cachedConvos.add( + Pair.create(packageData.getPackageName(), conversationInfo)); + } + }); }); if (cachedConvos.size() <= targetCachedCount) { return; @@ -872,8 +867,8 @@ public class DataManager { numToUncache + 1, Comparator.comparingLong((Pair<String, ConversationInfo> pair) -> Math.max( - pair.second.getLastEventTimestamp(), - pair.second.getCreationTimestamp())).reversed()); + pair.second.getLastEventTimestamp(), + pair.second.getCreationTimestamp())).reversed()); for (Pair<String, ConversationInfo> cached : cachedConvos) { if (hasActiveNotifications(cached.first, userId, cached.second.getShortcutId())) { continue; @@ -1109,35 +1104,26 @@ public class DataManager { @Override public void onShortcutsAddedOrUpdated(@NonNull String packageName, @NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user) { - mShortcutsThrottler.scheduleDebounced( - new Pair<>(packageName, user.getIdentifier()), - () -> { - PackageData packageData = getPackage(packageName, user.getIdentifier()); - List<ShortcutInfo> queriedShortcuts = getShortcuts(packageName, - user.getIdentifier(), null); - boolean hasCachedShortcut = false; - for (ShortcutInfo shortcut : queriedShortcuts) { - if (ShortcutHelper.isConversationShortcut( - shortcut, mShortcutServiceInternal, user.getIdentifier())) { - if (shortcut.isCached()) { - ConversationInfo info = packageData != null - ? packageData.getConversationInfo(shortcut.getId()) - : null; - if (info == null - || !info.isShortcutCachedForNotification()) { - hasCachedShortcut = true; - } - } - addOrUpdateConversationInfo(shortcut); + mInjector.getBackgroundExecutor().execute(() -> { + PackageData packageData = getPackage(packageName, user.getIdentifier()); + for (ShortcutInfo shortcut : shortcuts) { + if (ShortcutHelper.isConversationShortcut( + shortcut, mShortcutServiceInternal, user.getIdentifier())) { + if (shortcut.isCached()) { + ConversationInfo conversationInfo = packageData != null + ? packageData.getConversationInfo(shortcut.getId()) : null; + if (conversationInfo == null + || !conversationInfo.isShortcutCachedForNotification()) { + // This is a newly cached shortcut. Clean up the existing cached + // shortcuts to ensure the cache size is under the limit. + cleanupCachedShortcuts(user.getIdentifier(), + MAX_CACHED_RECENT_SHORTCUTS - 1); } } - // Added at least one new conversation. Uncache older existing cached - // shortcuts to ensure the cache size is under the limit. - if (hasCachedShortcut) { - cleanupCachedShortcuts(user.getIdentifier(), - MAX_CACHED_RECENT_SHORTCUTS); - } - }); + addOrUpdateConversationInfo(shortcut); + } + } + }); } @Override diff --git a/services/people/java/com/android/server/people/data/PerPackageThrottlerImpl.java b/services/people/java/com/android/server/people/data/PerPackageThrottlerImpl.java deleted file mode 100644 index fa5a67b328b2..000000000000 --- a/services/people/java/com/android/server/people/data/PerPackageThrottlerImpl.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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.server.people.data; - -import android.os.Handler; -import android.util.Pair; - -import java.util.HashSet; - -/** - * A class that implements a per-package throttler that prevents a runnable from executing more than - * once every {@code debounceTime}. - */ -public class PerPackageThrottlerImpl implements PerPackageThrottler { - private final Handler mBackgroundHandler; - private final int mDebounceTime; - private final HashSet<Pair<String, Integer>> mPkgScheduledTasks = new HashSet<>(); - - PerPackageThrottlerImpl(Handler backgroundHandler, int debounceTime) { - mBackgroundHandler = backgroundHandler; - mDebounceTime = debounceTime; - } - - @Override - public synchronized void scheduleDebounced( - Pair<String, Integer> pkgUserId, Runnable runnable) { - if (mPkgScheduledTasks.contains(pkgUserId)) { - return; - } - mPkgScheduledTasks.add(pkgUserId); - mBackgroundHandler.postDelayed(() -> { - synchronized (this) { - mPkgScheduledTasks.remove(pkgUserId); - runnable.run(); - } - }, mDebounceTime); - } -} diff --git a/services/tests/servicestests/src/com/android/server/media/projection/OWNERS b/services/tests/servicestests/src/com/android/server/media/projection/OWNERS new file mode 100644 index 000000000000..832bcd9d70e6 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/media/projection/OWNERS @@ -0,0 +1 @@ +include /media/java/android/media/projection/OWNERS diff --git a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java index 454a23b70cb5..a27602d65118 100644 --- a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java @@ -86,7 +86,6 @@ import android.service.notification.StatusBarNotification; import android.telecom.TelecomManager; import android.telephony.TelephonyManager; import android.text.format.DateUtils; -import android.util.Pair; import android.util.Range; import com.android.internal.app.ChooserActivity; @@ -187,7 +186,6 @@ public final class DataManagerTest { private ShortcutInfo mShortcutInfo; private TestInjector mInjector; private TestLooper mLooper; - private TestPerPackageThrottler mShortcutThrottler; @Before public void setUp() throws PackageManager.NameNotFoundException { @@ -277,9 +275,7 @@ public final class DataManagerTest { mInjector = new TestInjector(); mLooper = new TestLooper(); - mShortcutThrottler = new TestPerPackageThrottler(); - mDataManager = new DataManager(mContext, mInjector, mLooper.getLooper(), - mShortcutThrottler); + mDataManager = new DataManager(mContext, mInjector, mLooper.getLooper()); mDataManager.initialize(); when(mShortcutServiceInternal.isSharingShortcut(anyInt(), anyString(), anyString(), @@ -287,7 +283,10 @@ public final class DataManagerTest { mShortcutInfo = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID, buildPerson()); - mockGetShortcuts(Collections.singletonList(mShortcutInfo)); + when(mShortcutServiceInternal.getShortcuts( + anyInt(), anyString(), anyLong(), anyString(), anyList(), any(), any(), + anyInt(), anyInt(), anyInt(), anyInt())) + .thenReturn(Collections.singletonList(mShortcutInfo)); verify(mShortcutServiceInternal).addShortcutChangeCallback( mShortcutChangeCallbackCaptor.capture()); mShortcutChangeCallback = mShortcutChangeCallbackCaptor.getValue(); @@ -973,7 +972,6 @@ public final class DataManagerTest { buildPerson()); ShortcutInfo shortcut3 = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, "sc3", buildPerson()); - mockGetShortcuts(List.of(shortcut1, shortcut2, shortcut3)); mShortcutChangeCallback.onShortcutsAddedOrUpdated(TEST_PKG_NAME, Arrays.asList(shortcut1, shortcut2, shortcut3), UserHandle.of(USER_ID_PRIMARY)); mShortcutChangeCallback.onShortcutsRemoved(TEST_PKG_NAME, @@ -1225,6 +1223,7 @@ public final class DataManagerTest { eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS)); } } + @Test public void testUncacheOldestCachedShortcut_missingNotificationEvents() { mDataManager.onUserUnlocked(USER_ID_PRIMARY); @@ -1234,7 +1233,6 @@ public final class DataManagerTest { ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, shortcutId, buildPerson()); shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS); - mockGetShortcuts(Collections.singletonList(shortcut)); mShortcutChangeCallback.onShortcutsAddedOrUpdated( TEST_PKG_NAME, Collections.singletonList(shortcut), @@ -1254,6 +1252,7 @@ public final class DataManagerTest { eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS)); } } + @Test public void testUncacheOldestCachedShortcut_legacyConversation() { mDataManager.onUserUnlocked(USER_ID_PRIMARY); @@ -1275,7 +1274,6 @@ public final class DataManagerTest { ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, shortcutId, buildPerson()); shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS); - mockGetShortcuts(Collections.singletonList(shortcut)); mShortcutChangeCallback.onShortcutsAddedOrUpdated( TEST_PKG_NAME, Collections.singletonList(shortcut), @@ -1313,8 +1311,7 @@ public final class DataManagerTest { mDataManager.reportShareTargetEvent(appTargetEvent, intentFilter); byte[] payload = mDataManager.getBackupPayload(USER_ID_PRIMARY); - DataManager dataManager = new DataManager( - mContext, mInjector, mLooper.getLooper(), mShortcutThrottler); + DataManager dataManager = new DataManager(mContext, mInjector, mLooper.getLooper()); dataManager.onUserUnlocked(USER_ID_PRIMARY); dataManager.restore(USER_ID_PRIMARY, payload); ConversationInfo conversationInfo = dataManager.getPackage(TEST_PKG_NAME, USER_ID_PRIMARY) @@ -1726,13 +1723,6 @@ public final class DataManagerTest { return (queryFlags & flag) != 0; } - private void mockGetShortcuts(List<ShortcutInfo> shortcutInfoList) { - when(mShortcutServiceInternal.getShortcuts( - anyInt(), anyString(), anyLong(), anyString(), any(), any(), any(), - anyInt(), anyInt(), anyInt(), anyInt())) - .thenReturn(shortcutInfoList); - } - // "Sends" a notification to a non-customized notification channel - the notification channel // is something generic like "messages" and the notification has a shortcut id private void sendGenericNotification() { @@ -1958,11 +1948,4 @@ public final class DataManagerTest { return mUsageStatsQueryHelper; } } - - private static class TestPerPackageThrottler implements PerPackageThrottler { - @Override - public void scheduleDebounced(Pair<String, Integer> pkgUserId, Runnable runnable) { - runnable.run(); - } - } } diff --git a/services/tests/servicestests/src/com/android/server/people/data/PerPackageThrottlerImplTest.java b/services/tests/servicestests/src/com/android/server/people/data/PerPackageThrottlerImplTest.java deleted file mode 100644 index 672cbb94e074..000000000000 --- a/services/tests/servicestests/src/com/android/server/people/data/PerPackageThrottlerImplTest.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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.server.people.data; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import android.util.Pair; - -import com.android.server.testutils.OffsettableClock; -import com.android.server.testutils.TestHandler; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -import java.util.concurrent.atomic.AtomicBoolean; - -@RunWith(JUnit4.class) -public class PerPackageThrottlerImplTest { - private static final int DEBOUNCE_INTERVAL = 500; - private static final String PKG_ONE = "pkg_one"; - private static final String PKG_TWO = "pkg_two"; - private static final int USER_ID = 10; - - private final OffsettableClock mClock = new OffsettableClock.Stopped(); - private final TestHandler mTestHandler = new TestHandler(null, mClock); - private PerPackageThrottlerImpl mThrottler; - - @Before - public void setUp() { - mThrottler = new PerPackageThrottlerImpl(mTestHandler, DEBOUNCE_INTERVAL); - } - - @Test - public void scheduleDebounced() { - AtomicBoolean pkgOneRan = new AtomicBoolean(); - AtomicBoolean pkgTwoRan = new AtomicBoolean(); - - mThrottler.scheduleDebounced(new Pair<>(PKG_ONE, USER_ID), () -> pkgOneRan.set(true)); - mThrottler.scheduleDebounced(new Pair<>(PKG_ONE, USER_ID), () -> pkgOneRan.set(true)); - mThrottler.scheduleDebounced(new Pair<>(PKG_TWO, USER_ID), () -> pkgTwoRan.set(true)); - mThrottler.scheduleDebounced(new Pair<>(PKG_TWO, USER_ID), () -> pkgTwoRan.set(true)); - - assertFalse(pkgOneRan.get()); - assertFalse(pkgTwoRan.get()); - mClock.fastForward(DEBOUNCE_INTERVAL); - mTestHandler.timeAdvance(); - assertTrue(pkgOneRan.get()); - assertTrue(pkgTwoRan.get()); - } -} diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java index 318fff275f1f..117805bf344d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java @@ -113,6 +113,8 @@ import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import java.util.List; +import java.util.function.Consumer; +import java.util.function.Function; /** * Tests for Size Compatibility mode. @@ -168,6 +170,156 @@ public class SizeCompatTests extends WindowTestsBase { } @Test + public void testHorizontalReachabilityEnabledForTranslucentActivities() { + setUpDisplaySizeWithApp(2500, 1000); + mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + final LetterboxConfiguration config = mWm.mLetterboxConfiguration; + config.setTranslucentLetterboxingOverrideEnabled(true); + config.setLetterboxHorizontalPositionMultiplier(0.5f); + config.setIsHorizontalReachabilityEnabled(true); + + // Opaque activity + prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT); + addWindowToActivity(mActivity); + mActivity.mRootWindowContainer.performSurfacePlacement(); + + // Translucent Activity + final ActivityRecord translucentActivity = new ActivityBuilder(mAtm) + .setLaunchedFromUid(mActivity.getUid()) + .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT) + .build(); + doReturn(false).when(translucentActivity).fillsParent(); + mTask.addChild(translucentActivity); + + spyOn(translucentActivity.mLetterboxUiController); + doReturn(true).when(translucentActivity.mLetterboxUiController) + .shouldShowLetterboxUi(any()); + + addWindowToActivity(translucentActivity); + translucentActivity.mRootWindowContainer.performSurfacePlacement(); + + final Function<ActivityRecord, Rect> innerBoundsOf = + (ActivityRecord a) -> { + final Rect bounds = new Rect(); + a.mLetterboxUiController.getLetterboxInnerBounds(bounds); + return bounds; + }; + final Runnable checkLetterboxPositions = () -> assertEquals(innerBoundsOf.apply(mActivity), + innerBoundsOf.apply(translucentActivity)); + final Runnable checkIsLeft = () -> assertThat( + innerBoundsOf.apply(translucentActivity).left).isEqualTo(0); + final Runnable checkIsRight = () -> assertThat( + innerBoundsOf.apply(translucentActivity).right).isEqualTo(2500); + final Runnable checkIsCentered = () -> assertThat( + innerBoundsOf.apply(translucentActivity).left > 0 + && innerBoundsOf.apply(translucentActivity).right < 2500).isTrue(); + + final Consumer<Integer> doubleClick = + (Integer x) -> { + mActivity.mLetterboxUiController.handleHorizontalDoubleTap(x); + mActivity.mRootWindowContainer.performSurfacePlacement(); + }; + + // Initial state + checkIsCentered.run(); + + // Double-click left + doubleClick.accept(/* x */ 10); + checkLetterboxPositions.run(); + checkIsLeft.run(); + + // Double-click right + doubleClick.accept(/* x */ 1990); + checkLetterboxPositions.run(); + checkIsCentered.run(); + + // Double-click right + doubleClick.accept(/* x */ 1990); + checkLetterboxPositions.run(); + checkIsRight.run(); + + // Double-click left + doubleClick.accept(/* x */ 10); + checkLetterboxPositions.run(); + checkIsCentered.run(); + } + + @Test + public void testVerticalReachabilityEnabledForTranslucentActivities() { + setUpDisplaySizeWithApp(1000, 2500); + mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + final LetterboxConfiguration config = mWm.mLetterboxConfiguration; + config.setTranslucentLetterboxingOverrideEnabled(true); + config.setLetterboxVerticalPositionMultiplier(0.5f); + config.setIsVerticalReachabilityEnabled(true); + + // Opaque activity + prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE); + addWindowToActivity(mActivity); + mActivity.mRootWindowContainer.performSurfacePlacement(); + + // Translucent Activity + final ActivityRecord translucentActivity = new ActivityBuilder(mAtm) + .setLaunchedFromUid(mActivity.getUid()) + .setScreenOrientation(SCREEN_ORIENTATION_LANDSCAPE) + .build(); + doReturn(false).when(translucentActivity).fillsParent(); + mTask.addChild(translucentActivity); + + spyOn(translucentActivity.mLetterboxUiController); + doReturn(true).when(translucentActivity.mLetterboxUiController) + .shouldShowLetterboxUi(any()); + + addWindowToActivity(translucentActivity); + translucentActivity.mRootWindowContainer.performSurfacePlacement(); + + final Function<ActivityRecord, Rect> innerBoundsOf = + (ActivityRecord a) -> { + final Rect bounds = new Rect(); + a.mLetterboxUiController.getLetterboxInnerBounds(bounds); + return bounds; + }; + final Runnable checkLetterboxPositions = () -> assertEquals(innerBoundsOf.apply(mActivity), + innerBoundsOf.apply(translucentActivity)); + final Runnable checkIsTop = () -> assertThat( + innerBoundsOf.apply(translucentActivity).top).isEqualTo(0); + final Runnable checkIsBottom = () -> assertThat( + innerBoundsOf.apply(translucentActivity).bottom).isEqualTo(2500); + final Runnable checkIsCentered = () -> assertThat( + innerBoundsOf.apply(translucentActivity).top > 0 + && innerBoundsOf.apply(translucentActivity).bottom < 2500).isTrue(); + + final Consumer<Integer> doubleClick = + (Integer y) -> { + mActivity.mLetterboxUiController.handleVerticalDoubleTap(y); + mActivity.mRootWindowContainer.performSurfacePlacement(); + }; + + // Initial state + checkIsCentered.run(); + + // Double-click top + doubleClick.accept(/* y */ 10); + checkLetterboxPositions.run(); + checkIsTop.run(); + + // Double-click bottom + doubleClick.accept(/* y */ 1990); + checkLetterboxPositions.run(); + checkIsCentered.run(); + + // Double-click bottom + doubleClick.accept(/* y */ 1990); + checkLetterboxPositions.run(); + checkIsBottom.run(); + + // Double-click top + doubleClick.accept(/* y */ 10); + checkLetterboxPositions.run(); + checkIsCentered.run(); + } + + @Test public void testApplyStrategyToTranslucentActivities() { mWm.mLetterboxConfiguration.setTranslucentLetterboxingOverrideEnabled(true); setUpDisplaySizeWithApp(2000, 1000); @@ -809,7 +961,7 @@ public class SizeCompatTests extends WindowTestsBase { .setResizeMode(ActivityInfo.RESIZE_MODE_UNRESIZEABLE) .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT) .build(); - assertFalse(activity.shouldCreateCompatDisplayInsets()); + assertTrue(activity.shouldCreateCompatDisplayInsets()); // The non-resizable activity should not be size compat because it is on a resizable task // in multi-window mode. @@ -842,7 +994,7 @@ public class SizeCompatTests extends WindowTestsBase { } @Test - public void testShouldNotCreateCompatDisplayInsetsWhenRootActivityIsResizeable() { + public void testShouldCreateCompatDisplayInsetsWhenUnresizeableAndSupportsSizeChangesFalse() { setUpDisplaySizeWithApp(1000, 2500); // Make the task root resizable. @@ -851,7 +1003,7 @@ public class SizeCompatTests extends WindowTestsBase { // Create an activity on the same task. final ActivityRecord activity = buildActivityRecord(/* supportsSizeChanges= */false, RESIZE_MODE_UNRESIZEABLE, ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); - assertFalse(activity.shouldCreateCompatDisplayInsets()); + assertTrue(activity.shouldCreateCompatDisplayInsets()); } @Test diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java index ec18c6a696b8..7a53447c1eee 100644 --- a/telecomm/java/android/telecom/PhoneAccount.java +++ b/telecomm/java/android/telecom/PhoneAccount.java @@ -555,6 +555,11 @@ public final class PhoneAccount implements Parcelable { /** * Sets the address. See {@link PhoneAccount#getAddress}. + * <p> + * Note: The entire URI value is limited to 256 characters. This check is + * enforced when registering the PhoneAccount via + * {@link TelecomManager#registerPhoneAccount(PhoneAccount)} and will cause an + * {@link IllegalArgumentException} to be thrown if URI is over 256. * * @param value The address of the phone account. * @return The builder. @@ -588,6 +593,10 @@ public final class PhoneAccount implements Parcelable { /** * Sets the icon. See {@link PhoneAccount#getIcon}. + * <p> + * Note: An {@link IllegalArgumentException} if the Icon cannot be written to memory. + * This check is enforced when registering the PhoneAccount via + * {@link TelecomManager#registerPhoneAccount(PhoneAccount)} * * @param icon The icon to set. */ @@ -621,6 +630,10 @@ public final class PhoneAccount implements Parcelable { /** * Specifies an additional URI scheme supported by the {@link PhoneAccount}. * + * <p> + * Each URI scheme is limited to 256 characters. Adding a scheme over 256 characters will + * cause an {@link IllegalArgumentException} to be thrown when the account is registered. + * * @param uriScheme The URI scheme. * @return The builder. */ @@ -634,6 +647,12 @@ public final class PhoneAccount implements Parcelable { /** * Specifies the URI schemes supported by the {@link PhoneAccount}. * + * <p> + * A max of 10 URI schemes can be added per account. Additionally, each URI scheme is + * limited to 256 characters. Adding more than 10 URI schemes or 256 characters on any + * scheme will cause an {@link IllegalArgumentException} to be thrown when the account + * is registered. + * * @param uriSchemes The URI schemes. * @return The builder. */ diff --git a/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java b/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java index 3db011683a86..fdd919412e55 100644 --- a/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java +++ b/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java @@ -86,7 +86,7 @@ public class ProtoLogImplTest { mFile = testContext.getFileStreamPath("tracing_test.dat"); //noinspection ResultOfMethodCallIgnored mFile.delete(); - mProtoLog = new ProtoLogImpl(mFile, 1024 * 1024, mReader); + mProtoLog = new ProtoLogImpl(mFile, 1024 * 1024, mReader, 1024); } @After |