diff options
550 files changed, 10594 insertions, 6836 deletions
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp index 50c8e933d25f..3f6046f01f11 100644 --- a/cmds/bootanimation/BootAnimation.cpp +++ b/cmds/bootanimation/BootAnimation.cpp @@ -132,14 +132,14 @@ static const char IMAGE_FRAG_DYNAMIC_COLORING_SHADER_SOURCE[] = R"( uniform sampler2D uTexture; uniform float uFade; uniform float uColorProgress; - uniform vec4 uStartColor0; - uniform vec4 uStartColor1; - uniform vec4 uStartColor2; - uniform vec4 uStartColor3; - uniform vec4 uEndColor0; - uniform vec4 uEndColor1; - uniform vec4 uEndColor2; - uniform vec4 uEndColor3; + uniform vec3 uStartColor0; + uniform vec3 uStartColor1; + uniform vec3 uStartColor2; + uniform vec3 uStartColor3; + uniform vec3 uEndColor0; + uniform vec3 uEndColor1; + uniform vec3 uEndColor2; + uniform vec3 uEndColor3; varying highp vec2 vUv; void main() { vec4 mask = texture2D(uTexture, vUv); @@ -152,12 +152,12 @@ static const char IMAGE_FRAG_DYNAMIC_COLORING_SHADER_SOURCE[] = R"( * step(cWhiteMaskThreshold, g) * step(cWhiteMaskThreshold, b) * step(cWhiteMaskThreshold, a); - vec4 color = r * mix(uStartColor0, uEndColor0, uColorProgress) + vec3 color = r * mix(uStartColor0, uEndColor0, uColorProgress) + g * mix(uStartColor1, uEndColor1, uColorProgress) + b * mix(uStartColor2, uEndColor2, uColorProgress) + a * mix(uStartColor3, uEndColor3, uColorProgress); - color = mix(color, vec4(vec3((r + g + b + a) * 0.25), 1.0), useWhiteMask); - gl_FragColor = vec4(color.x, color.y, color.z, (1.0 - uFade)) * color.a; + color = mix(color, vec3((r + g + b + a) * 0.25), useWhiteMask); + gl_FragColor = vec4(color.x, color.y, color.z, (1.0 - uFade)); })"; static const char IMAGE_FRAG_SHADER_SOURCE[] = R"( precision mediump float; @@ -1440,12 +1440,12 @@ void BootAnimation::initDynamicColors() { for (int i = 0; i < DYNAMIC_COLOR_COUNT; i++) { float *startColor = mAnimation->startColors[i]; float *endColor = mAnimation->endColors[i]; - glUniform4f(glGetUniformLocation(mImageShader, + glUniform3f(glGetUniformLocation(mImageShader, (U_START_COLOR_PREFIX + std::to_string(i)).c_str()), - startColor[0], startColor[1], startColor[2], 1 /* alpha */); - glUniform4f(glGetUniformLocation(mImageShader, + startColor[0], startColor[1], startColor[2]); + glUniform3f(glGetUniformLocation(mImageShader, (U_END_COLOR_PREFIX + std::to_string(i)).c_str()), - endColor[0], endColor[1], endColor[2], 1 /* alpha */); + endColor[0], endColor[1], endColor[2]); } mImageColorProgressLocation = glGetUniformLocation(mImageShader, U_COLOR_PROGRESS); } diff --git a/core/java/android/animation/AnimationHandler.java b/core/java/android/animation/AnimationHandler.java index 1403ba2744b3..dcabf57cb8a9 100644 --- a/core/java/android/animation/AnimationHandler.java +++ b/core/java/android/animation/AnimationHandler.java @@ -219,12 +219,14 @@ public class AnimationHandler { return; } for (int i = 0; i < mAnimationCallbacks.size(); ++i) { - Animator animator = ((Animator) mAnimationCallbacks.get(i)); - if (animator != null - && animator.getTotalDuration() == Animator.DURATION_INFINITE - && !animator.isPaused()) { - mPausedAnimators.add(animator); - animator.pause(); + AnimationFrameCallback callback = mAnimationCallbacks.get(i); + if (callback instanceof Animator) { + Animator animator = ((Animator) callback); + if (animator.getTotalDuration() == Animator.DURATION_INFINITE + && !animator.isPaused()) { + mPausedAnimators.add(animator); + animator.pause(); + } } } }; diff --git a/core/java/android/app/ApplicationExitInfo.java b/core/java/android/app/ApplicationExitInfo.java index a8d8c75601aa..5517c57d1f1e 100644 --- a/core/java/android/app/ApplicationExitInfo.java +++ b/core/java/android/app/ApplicationExitInfo.java @@ -1196,7 +1196,8 @@ public final class ApplicationExitInfo implements Parcelable { return sb.toString(); } - private static String reasonCodeToString(@Reason int reason) { + /** @hide */ + public static String reasonCodeToString(@Reason int reason) { switch (reason) { case REASON_EXIT_SELF: return "EXIT_SELF"; diff --git a/core/java/android/app/DisabledWallpaperManager.java b/core/java/android/app/DisabledWallpaperManager.java index ae3a9e6668ab..0d14c0bcf1c9 100644 --- a/core/java/android/app/DisabledWallpaperManager.java +++ b/core/java/android/app/DisabledWallpaperManager.java @@ -193,6 +193,16 @@ final class DisabledWallpaperManager extends WallpaperManager { } @Override + public WallpaperInfo getWallpaperInfoWithFlags(@SetWallpaperFlags int which) { + return unsupported(); + } + + @Override + public WallpaperInfo getWallpaperInfoWithFlags(@SetWallpaperFlags int which, int userId) { + return unsupported(); + } + + @Override public int getWallpaperId(int which) { return unsupportedInt(); } diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java index ff69491352ff..c99fa3d3177c 100644 --- a/core/java/android/app/WallpaperManager.java +++ b/core/java/android/app/WallpaperManager.java @@ -1320,18 +1320,16 @@ public class WallpaperManager { } /** - * Returns the information about the wallpaper if the current wallpaper is - * a live wallpaper component. Otherwise, if the wallpaper is a static image, - * this returns null. + * Returns the information about the home screen wallpaper if its current wallpaper is a live + * wallpaper component. Otherwise, if the wallpaper is a static image, this returns null. */ public WallpaperInfo getWallpaperInfo() { return getWallpaperInfo(mContext.getUserId()); } /** - * Returns the information about the wallpaper if the current wallpaper is - * a live wallpaper component. Otherwise, if the wallpaper is a static image, - * this returns null. + * Returns the information about the home screen wallpaper if its current wallpaper is a live + * wallpaper component. Otherwise, if the wallpaper is a static image, this returns null. * * @param userId Owner of the wallpaper. * @hide @@ -1350,6 +1348,29 @@ public class WallpaperManager { } /** + * Returns the information about the home screen wallpaper if its current wallpaper is a live + * wallpaper component. Otherwise, if the wallpaper is a static image, this returns null. + * + * @param which Specifies wallpaper destination (home or lock). + * @hide + */ + public WallpaperInfo getWallpaperInfoWithFlags(@SetWallpaperFlags int which) { + return getWallpaperInfo(); + } + + /** + * Returns the information about the designated wallpaper if its current wallpaper is a live + * wallpaper component. Otherwise, if the wallpaper is a static image, this returns null. + * + * @param which Specifies wallpaper destination (home or lock). + * @param userId Owner of the wallpaper. + * @hide + */ + public WallpaperInfo getWallpaperInfoWithFlags(@SetWallpaperFlags int which, int userId) { + return getWallpaperInfo(userId); + } + + /** * Get the ID of the current wallpaper of the given kind. If there is no * such wallpaper configured, returns a negative number. * diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java index 16f9a12953f8..36e0dc35cb8e 100644 --- a/core/java/android/preference/SeekBarVolumizer.java +++ b/core/java/android/preference/SeekBarVolumizer.java @@ -16,7 +16,9 @@ package android.preference; +import android.Manifest; import android.annotation.NonNull; +import android.annotation.RequiresPermission; import android.app.NotificationManager; import android.compat.annotation.UnsupportedAppUsage; import android.content.BroadcastReceiver; @@ -35,6 +37,7 @@ import android.os.Handler; import android.os.HandlerThread; import android.os.Message; import android.preference.VolumePreference.VolumeStore; +import android.provider.DeviceConfig; import android.provider.Settings; import android.provider.Settings.Global; import android.provider.Settings.System; @@ -44,6 +47,7 @@ import android.widget.SeekBar; import android.widget.SeekBar.OnSeekBarChangeListener; import com.android.internal.annotations.GuardedBy; +import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; import com.android.internal.os.SomeArgs; import java.util.concurrent.TimeUnit; @@ -115,7 +119,6 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba private final int mMaxStreamVolume; private boolean mAffectedByRingerMode; private boolean mNotificationOrRing; - private final boolean mNotifAliasRing; private final Receiver mReceiver = new Receiver(); private Handler mHandler; @@ -158,6 +161,7 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba this(context, streamType, defaultUri, callback, true /* playSample */); } + @RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG) public SeekBarVolumizer( Context context, int streamType, @@ -180,8 +184,6 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba if (mNotificationOrRing) { mRingerMode = mAudioManager.getRingerModeInternal(); } - mNotifAliasRing = mContext.getResources().getBoolean( - com.android.internal.R.bool.config_alias_ring_notif_stream_types); mZenMode = mNotificationManager.getZenMode(); if (hasAudioProductStrategies()) { @@ -288,7 +290,9 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba * so that when user attempts to slide the notification seekbar out of vibrate the * seekbar doesn't wrongly snap back to 0 when the streams aren't aliased */ - if (mNotifAliasRing || mStreamType == AudioManager.STREAM_RING + if (!DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI, + SystemUiDeviceConfigFlags.VOLUME_SEPARATE_NOTIFICATION, false) + || mStreamType == AudioManager.STREAM_RING || (mStreamType == AudioManager.STREAM_NOTIFICATION && mMuted)) { mSeekBar.setProgress(0, true); } @@ -365,7 +369,9 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba // set the time of stop volume if ((mStreamType == AudioManager.STREAM_VOICE_CALL || mStreamType == AudioManager.STREAM_RING - || (!mNotifAliasRing && mStreamType == AudioManager.STREAM_NOTIFICATION) + || (DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI, + SystemUiDeviceConfigFlags.VOLUME_SEPARATE_NOTIFICATION, false) + && mStreamType == AudioManager.STREAM_NOTIFICATION) || mStreamType == AudioManager.STREAM_ALARM)) { sStopVolumeTime = java.lang.System.currentTimeMillis(); } @@ -643,8 +649,10 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba } private void updateVolumeSlider(int streamType, int streamValue) { - final boolean streamMatch = mNotifAliasRing && mNotificationOrRing - ? isNotificationOrRing(streamType) : streamType == mStreamType; + final boolean streamMatch = !DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI, + SystemUiDeviceConfigFlags.VOLUME_SEPARATE_NOTIFICATION, false) + && mNotificationOrRing ? isNotificationOrRing(streamType) : + streamType == mStreamType; if (mSeekBar != null && streamMatch && streamValue != -1) { final boolean muted = mAudioManager.isStreamMute(mStreamType) || streamValue == 0; diff --git a/core/java/android/service/dreams/DreamManagerInternal.java b/core/java/android/service/dreams/DreamManagerInternal.java index 295171ca9bbd..cd38e8a01d62 100644 --- a/core/java/android/service/dreams/DreamManagerInternal.java +++ b/core/java/android/service/dreams/DreamManagerInternal.java @@ -16,7 +16,6 @@ package android.service.dreams; -import android.content.ComponentName; /** * Dream manager local system service interface. @@ -54,17 +53,9 @@ public abstract class DreamManagerInternal { public abstract void requestDream(); /** - * Called by the ActivityTaskManagerService to verify that the startDreamActivity - * request comes from the current active dream component. + * Whether dreaming can start given user settings and the current dock/charge state. * - * This function and its call path should not acquire the DreamManagerService lock - * to avoid deadlock with the ActivityTaskManager lock. - * - * TODO: Make this interaction push-based - the DreamManager should inform the - * ActivityTaskManager whenever the active dream component changes. - * - * @param doze If true returns the current active doze component. Otherwise, returns the - * active dream component. + * @param isScreenOn True if the screen is currently on. */ - public abstract ComponentName getActiveDreamComponent(boolean doze); + public abstract boolean canStartDreaming(boolean isScreenOn); } diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java index 1664637eac56..d067d4bc366b 100644 --- a/core/java/android/view/contentcapture/ContentCaptureManager.java +++ b/core/java/android/view/contentcapture/ContentCaptureManager.java @@ -378,7 +378,7 @@ public final class ContentCaptureManager { private final Object mLock = new Object(); @NonNull - private final Context mContext; + private final StrippedContext mContext; @NonNull private final IContentCaptureManager mService; @@ -414,9 +414,37 @@ public final class ContentCaptureManager { } /** @hide */ + static class StrippedContext { + final String mPackageName; + final String mContext; + final @UserIdInt int mUserId; + + private StrippedContext(Context context) { + mPackageName = context.getPackageName(); + mContext = context.toString(); + mUserId = context.getUserId(); + } + + @Override + public String toString() { + return mContext; + } + + public String getPackageName() { + return mPackageName; + } + + @UserIdInt + public int getUserId() { + return mUserId; + } + } + + /** @hide */ public ContentCaptureManager(@NonNull Context context, @NonNull IContentCaptureManager service, @NonNull ContentCaptureOptions options) { - mContext = Objects.requireNonNull(context, "context cannot be null"); + Objects.requireNonNull(context, "context cannot be null"); + mContext = new StrippedContext(context); mService = Objects.requireNonNull(service, "service cannot be null"); mOptions = Objects.requireNonNull(options, "options cannot be null"); diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java index 90384b520315..1f5e462d71fd 100644 --- a/core/java/android/view/contentcapture/MainContentCaptureSession.java +++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java @@ -36,7 +36,6 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UiThread; import android.content.ComponentName; -import android.content.Context; import android.content.pm.ParceledListSlice; import android.graphics.Insets; import android.graphics.Rect; @@ -103,7 +102,7 @@ public final class MainContentCaptureSession extends ContentCaptureSession { private final AtomicBoolean mDisabled = new AtomicBoolean(false); @NonNull - private final Context mContext; + private final ContentCaptureManager.StrippedContext mContext; @NonNull private final ContentCaptureManager mManager; @@ -197,7 +196,7 @@ public final class MainContentCaptureSession extends ContentCaptureSession { } } - protected MainContentCaptureSession(@NonNull Context context, + protected MainContentCaptureSession(@NonNull ContentCaptureManager.StrippedContext context, @NonNull ContentCaptureManager manager, @NonNull Handler handler, @NonNull IContentCaptureManager systemServerInterface) { mContext = context; diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index f5ba275b604b..2676396cb997 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -2096,7 +2096,8 @@ public class ChooserActivity extends ResolverActivity implements return matchingShortcuts; } - private void sendShortcutManagerShareTargetResults( + @VisibleForTesting + protected void sendShortcutManagerShareTargetResults( int shortcutType, ServiceResultInfo[] results) { final Message msg = Message.obtain(); msg.what = ChooserHandler.SHORTCUT_MANAGER_ALL_SHARE_TARGET_RESULTS; @@ -3873,7 +3874,11 @@ public class ChooserActivity extends ResolverActivity implements } } - static class ServiceResultInfo { + /** + * Shortcuts grouped by application. + */ + @VisibleForTesting + public static class ServiceResultInfo { public final DisplayResolveInfo originalTarget; public final List<ChooserTarget> resultTargets; public final UserHandle userHandle; diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java index c70e26f65829..47400deac34b 100644 --- a/core/java/com/android/internal/app/ResolverActivity.java +++ b/core/java/com/android/internal/app/ResolverActivity.java @@ -1098,6 +1098,9 @@ public class ResolverActivity extends Activity implements @Override // ResolverListCommunicator public final void onPostListReady(ResolverListAdapter listAdapter, boolean doPostProcessing, boolean rebuildCompleted) { + if (isDestroyed()) { + return; + } if (isAutolaunching()) { return; } diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java index 44997b4a9c30..0f64f6da63f7 100644 --- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java +++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java @@ -556,6 +556,11 @@ public final class SystemUiDeviceConfigFlags { "show_stop_button_for_user_allowlisted_apps"; /** + * (boolean) Whether to show notification volume control slider separate from ring. + */ + public static final String VOLUME_SEPARATE_NOTIFICATION = "volume_separate_notification"; + + /** * (boolean) Whether the clipboard overlay is enabled. */ public static final String CLIPBOARD_OVERLAY_ENABLED = "clipboard_overlay_enabled"; diff --git a/core/java/com/android/internal/infra/AbstractRemoteService.java b/core/java/com/android/internal/infra/AbstractRemoteService.java index f725b37acde7..0e1b7cb8090f 100644 --- a/core/java/com/android/internal/infra/AbstractRemoteService.java +++ b/core/java/com/android/internal/infra/AbstractRemoteService.java @@ -20,10 +20,14 @@ import static com.android.internal.util.function.pooled.PooledLambda.obtainMessa import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.ActivityManager; +import android.app.ApplicationExitInfo; +import android.app.IActivityManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; +import android.content.pm.ParceledListSlice; import android.os.Handler; import android.os.IBinder; import android.os.IBinder.DeathRecipient; @@ -39,6 +43,7 @@ import com.android.internal.annotations.GuardedBy; import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.util.ArrayList; +import java.util.List; /** * Base class representing a remote service. @@ -66,6 +71,7 @@ import java.util.ArrayList; @Deprecated public abstract class AbstractRemoteService<S extends AbstractRemoteService<S, I>, I extends IInterface> implements DeathRecipient { + private static final int SERVICE_NOT_EXIST = -1; private static final int MSG_BIND = 1; private static final int MSG_UNBIND = 2; @@ -96,6 +102,8 @@ public abstract class AbstractRemoteService<S extends AbstractRemoteService<S, I // Used just for debugging purposes (on dump) private long mNextUnbind; + private int mServiceExitReason; + private int mServiceExitSubReason; /** Requests that have been scheduled, but that are not finished yet */ private final ArrayList<BasePendingRequest<S, I>> mUnfinishedRequests = new ArrayList<>(); @@ -126,6 +134,8 @@ public abstract class AbstractRemoteService<S extends AbstractRemoteService<S, I mUserId = userId; mHandler = new Handler(handler.getLooper()); mBindingFlags = bindingFlags; + mServiceExitReason = SERVICE_NOT_EXIST; + mServiceExitSubReason = SERVICE_NOT_EXIST; } /** @@ -229,6 +239,7 @@ public abstract class AbstractRemoteService<S extends AbstractRemoteService<S, I if (mService != null) { mService.asBinder().unlinkToDeath(this, 0); } + updateServicelicationExitInfo(mComponentName, mUserId); mConnecting = true; mService = null; mServiceDied = true; @@ -239,6 +250,37 @@ public abstract class AbstractRemoteService<S extends AbstractRemoteService<S, I handleBindFailure(); } + private void updateServicelicationExitInfo(ComponentName componentName, int userId) { + IActivityManager am = ActivityManager.getService(); + String packageName = componentName.getPackageName(); + ParceledListSlice<ApplicationExitInfo> plistSlice = null; + try { + plistSlice = am.getHistoricalProcessExitReasons(packageName, 0, 1, userId); + } catch (RemoteException e) { + // do nothing. The local binder so it can not throw it. + } + if (plistSlice == null) { + mServiceExitReason = ApplicationExitInfo.REASON_UNKNOWN; + mServiceExitSubReason = ApplicationExitInfo.SUBREASON_UNKNOWN; + return; + } + List<ApplicationExitInfo> list = plistSlice.getList(); + if (list.isEmpty()) { + mServiceExitReason = ApplicationExitInfo.REASON_UNKNOWN; + mServiceExitSubReason = ApplicationExitInfo.SUBREASON_UNKNOWN; + return; + } + ApplicationExitInfo info = list.get(0); + mServiceExitReason = info.getReason(); + mServiceExitSubReason = info.getSubReason(); + if (mVerbose) { + Slog.v(mTag, "updateServicelicationExitInfo: exitReason=" + + ApplicationExitInfo.reasonCodeToString(mServiceExitReason) + + " exitSubReason= " + ApplicationExitInfo.subreasonToString( + mServiceExitSubReason)); + } + } + // Note: we are dumping without a lock held so this is a bit racy but // adding a lock to a class that offloads to a handler thread would // mean adding a lock adding overhead to normal runtime operation. @@ -272,6 +314,16 @@ public abstract class AbstractRemoteService<S extends AbstractRemoteService<S, I } } pw.println(); + if (mServiceExitReason != SERVICE_NOT_EXIST) { + pw.append(prefix).append(tab).append("serviceExistReason=") + .append(ApplicationExitInfo.reasonCodeToString(mServiceExitReason)); + pw.println(); + } + if (mServiceExitSubReason != SERVICE_NOT_EXIST) { + pw.append(prefix).append(tab).append("serviceExistSubReason=") + .append(ApplicationExitInfo.subreasonToString(mServiceExitSubReason)); + pw.println(); + } pw.append(prefix).append("mBindingFlags=").println(mBindingFlags); pw.append(prefix).append("idleTimeout=") .append(Long.toString(idleTimeout / 1000)).append("s\n"); @@ -498,6 +550,8 @@ public abstract class AbstractRemoteService<S extends AbstractRemoteService<S, I return; } mService = getServiceInterface(service); + mServiceExitReason = SERVICE_NOT_EXIST; + mServiceExitSubReason = SERVICE_NOT_EXIST; handleOnConnectedStateChangedInternal(true); mServiceDied = false; } diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java index a05062b43d60..39b9e217fce7 100644 --- a/core/java/com/android/internal/jank/InteractionJankMonitor.java +++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java @@ -27,6 +27,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_APP_LAUNCH_FROM_ICON; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_LAUNCH_FROM_RECENTS; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_LAUNCH_FROM_WIDGET; +import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_SWIPE_TO_RECENTS; 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; @@ -225,6 +226,7 @@ public class InteractionJankMonitor { public static final int CUJ_LAUNCHER_UNLOCK_ENTRANCE_ANIMATION = 63; public static final int CUJ_LOCKSCREEN_OCCLUSION = 64; public static final int CUJ_RECENTS_SCROLLING = 65; + public static final int CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS = 66; private static final int NO_STATSD_LOGGING = -1; @@ -299,6 +301,7 @@ public class InteractionJankMonitor { UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_UNLOCK_ENTRANCE_ANIMATION, UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_OCCLUSION, UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__RECENTS_SCROLLING, + UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_SWIPE_TO_RECENTS, }; private static volatile InteractionJankMonitor sInstance; @@ -384,7 +387,8 @@ public class InteractionJankMonitor { CUJ_SHADE_CLEAR_ALL, CUJ_LAUNCHER_UNLOCK_ENTRANCE_ANIMATION, CUJ_LOCKSCREEN_OCCLUSION, - CUJ_RECENTS_SCROLLING + CUJ_RECENTS_SCROLLING, + CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS }) @Retention(RetentionPolicy.SOURCE) public @interface CujType { @@ -899,6 +903,8 @@ public class InteractionJankMonitor { return "LOCKSCREEN_OCCLUSION"; case CUJ_RECENTS_SCROLLING: return "RECENTS_SCROLLING"; + case CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS: + return "LAUNCHER_APP_SWIPE_TO_RECENTS"; } return "UNKNOWN"; } diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index b04d8c9c1115..566a7bc23c0a 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -338,7 +338,7 @@ <string name="capability_title_canPerformGestures" msgid="9106545062106728987">"Udføre bevægelser"</string> <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Kan trykke, stryge, knibe sammen og udføre andre bevægelser."</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Fingeraftryksbevægelser"</string> - <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Kan registrere bevægelser, der foretages på enhedens fingeraftrykslæser."</string> + <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Kan registrere bevægelser, der foretages på enhedens fingeraftrykssensor."</string> <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Tag screenshot"</string> <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Kan tage et screenshot af skærmen."</string> <string name="permlab_statusBar" msgid="8798267849526214017">"deaktivere eller redigere statuslinje"</string> @@ -585,11 +585,11 @@ <string name="biometric_error_generic" msgid="6784371929985434439">"Der opstod fejl i forbindelse med godkendelse"</string> <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Brug skærmlås"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Angiv din skærmlås for at fortsætte"</string> - <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Hold fingeren nede på læseren"</string> + <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Hold fingeren nede på sensoren"</string> <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Fingeraftrykket kan ikke genkendes. Prøv igen."</string> - <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Rengør fingeraftrykslæseren, og prøv igen"</string> - <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Rengør læseren, og prøv igen"</string> - <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Hold fingeren nede på læseren"</string> + <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Rengør fingeraftrykssensoren, og prøv igen"</string> + <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Rengør sensoren, og prøv igen"</string> + <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Hold fingeren nede på sensoren"</string> <string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Du bevægede fingeren for langsomt. Prøv igen."</string> <string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Prøv med et andet fingeraftryk"</string> <string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Der er for lyst"</string> @@ -612,9 +612,9 @@ <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Du har brugt for mange forsøg. Brug skærmlåsen i stedet."</string> <string name="fingerprint_error_unable_to_process" msgid="2446280592818621224">"Fingeraftrykket kan ikke behandles. Prøv igen."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Der er ikke registreret nogen fingeraftryk."</string> - <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Denne enhed har ingen fingeraftrykslæser."</string> + <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Denne enhed har ingen fingeraftrykssensor."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensoren er midlertidigt deaktiveret."</string> - <string name="fingerprint_error_bad_calibration" msgid="4385512597740168120">"Fingeraftrykslæseren kan ikke bruges. Få den repareret"</string> + <string name="fingerprint_error_bad_calibration" msgid="4385512597740168120">"Fingeraftrykssensoren kan ikke bruges. Få den repareret"</string> <string name="fingerprint_error_power_pressed" msgid="5479524500542129414">"Der blev trykket på afbryderknappen"</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Fingeraftryk <xliff:g id="FINGERID">%d</xliff:g>"</string> <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Brug fingeraftryk"</string> @@ -634,7 +634,7 @@ <string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Konfigurer flere måder at låse op på"</string> <string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Tryk for at tilføje et fingeraftryk"</string> <string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Oplåsning med fingeraftryk"</string> - <string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Fingeraftrykslæseren kan ikke bruges"</string> + <string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Fingeraftrykssensoren kan ikke bruges"</string> <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Få den repareret."</string> <string name="face_acquired_insufficient" msgid="6889245852748492218">"Din ansigtsmodel kan ikke oprettes. Prøv igen."</string> <string name="face_acquired_too_bright" msgid="8070756048978079164">"Der er for lyst. Prøv en mere dæmpet belysning."</string> diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml index 681cc914383f..1576cac26212 100644 --- a/core/res/res/values-eu/strings.xml +++ b/core/res/res/values-eu/strings.xml @@ -180,7 +180,7 @@ <string name="low_memory" product="watch" msgid="3479447988234030194">"Erlojuaren memoria beteta dago. Tokia egiteko, ezabatu fitxategi batzuk."</string> <string name="low_memory" product="tv" msgid="6663680413790323318">"Android TV gailuaren memoria beteta dago. Tokia egiteko, ezabatu fitxategi batzuk."</string> <string name="low_memory" product="default" msgid="2539532364144025569">"Telefonoaren memoria beteta dago. Tokia egiteko, ezabatu fitxategi batzuk."</string> - <string name="ssl_ca_cert_warning" msgid="7233573909730048571">"{count,plural, =1{Ziurtagiri-emaile bat dago instalatuta}other{Ziurtagiri-emaile bat baino gehiago daude instalatuta}}"</string> + <string name="ssl_ca_cert_warning" msgid="7233573909730048571">"{count,plural, =1{Autoritate ziurtagiri-emaile bat dago instalatuta}other{Autoritate ziurtagiri-emaile bat baino gehiago daude instalatuta}}"</string> <string name="ssl_ca_cert_noti_by_unknown" msgid="4961102218216815242">"Hirugarren alderdi ezezagun baten arabera"</string> <string name="ssl_ca_cert_noti_by_administrator" msgid="4564941950768783879">"Laneko profilen administratzaileak"</string> <string name="ssl_ca_cert_noti_managed" msgid="217337232273211674">"<xliff:g id="MANAGING_DOMAIN">%s</xliff:g> da arduraduna"</string> @@ -1457,7 +1457,7 @@ <string name="permdesc_requestDeletePackages" msgid="6133633516423860381">"Paketeak ezabatzeko eskatzea baimentzen die aplikazioei."</string> <string name="permlab_requestIgnoreBatteryOptimizations" msgid="7646611326036631439">"eskatu bateria-optimizazioei ez ikusi egitea"</string> <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Bateriaren optimizazioei ez ikusi egiteko baimena eskatzea baimentzen die aplikazioei."</string> - <string name="permlab_queryAllPackages" msgid="2928450604653281650">"Kontsultatu pakete guztiak"</string> + <string name="permlab_queryAllPackages" msgid="2928450604653281650">"kontsultatu pakete guztiak"</string> <string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Instalatutako pakete guztiak ikusteko baimena ematen dio aplikazioari."</string> <string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Sakatu birritan zooma kontrolatzeko"</string> <string name="gadget_host_error_inflating" msgid="2449961590495198720">"Ezin izan da widgeta gehitu."</string> diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index 59408a79d8b1..c7286e577ab1 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -1253,7 +1253,7 @@ <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"מתבצעת הפעלה של אפליקציות."</string> <string name="android_upgrading_complete" msgid="409800058018374746">"תהליך האתחול בשלבי סיום."</string> <string name="fp_power_button_enrollment_message" msgid="5648173517663246140">"לחצת על לחצן ההפעלה – בדרך כלל הפעולה הזו מכבה את המסך.\n\nעליך לנסות להקיש בעדינות במהלך ההגדרה של טביעת האצבע שלך."</string> - <string name="fp_power_button_enrollment_title" msgid="6976841690455338563">"כדי לסיים את ההגדרה צריך לכבות את המסך"</string> + <string name="fp_power_button_enrollment_title" msgid="6976841690455338563">"לסיום ההגדרה, יש לכבות את המסך"</string> <string name="fp_power_button_enrollment_button_text" msgid="3199783266386029200">"השבתה"</string> <string name="fp_power_button_bp_title" msgid="5585506104526820067">"להמשיך לאמת את טביעת האצבע שלך?"</string> <string name="fp_power_button_bp_message" msgid="2983163038168903393">"לחצת על לחצן ההפעלה – בדרך כלל הפעולה הזו מכבה את המסך.\n\nעליך לנסות להקיש בעדינות כדי לאמת את טביעת האצבע שלך."</string> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index d11eca61752f..dbb7f3b15a4c 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -598,7 +598,7 @@ <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"지문을 등록할 때마다 손가락을 조금씩 이동하세요"</string> <string-array name="fingerprint_acquired_vendor"> </string-array> - <string name="fingerprint_error_not_match" msgid="4599441812893438961">"지문이 인식되지 않습니다."</string> + <string name="fingerprint_error_not_match" msgid="4599441812893438961">"지문이 인식되지 않았습니다."</string> <string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"지문을 인식할 수 없습니다."</string> <string name="fingerprint_authenticated" msgid="2024862866860283100">"지문이 인증됨"</string> <string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"얼굴이 인증되었습니다"</string> @@ -1252,7 +1252,7 @@ <string name="android_upgrading_complete" msgid="409800058018374746">"부팅 완료"</string> <string name="fp_power_button_enrollment_message" msgid="5648173517663246140">"전원 버튼을 눌렀습니다. 이러면 보통 화면이 꺼집니다.\n\n지문 설정 중에 가볍게 탭하세요."</string> <string name="fp_power_button_enrollment_title" msgid="6976841690455338563">"설정을 완료하려면 화면을 끄세요"</string> - <string name="fp_power_button_enrollment_button_text" msgid="3199783266386029200">"사용 중지"</string> + <string name="fp_power_button_enrollment_button_text" msgid="3199783266386029200">"화면 끄기"</string> <string name="fp_power_button_bp_title" msgid="5585506104526820067">"지문 인증을 계속할까요?"</string> <string name="fp_power_button_bp_message" msgid="2983163038168903393">"전원 버튼을 눌렀습니다. 이러면 보통 화면이 꺼집니다.\n\n지문을 인식하려면 화면을 가볍게 탭하세요."</string> <string name="fp_power_button_bp_positive_button" msgid="728945472408552251">"화면 끄기"</string> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index a5cd1744d4b6..f1f2c2f483be 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -1253,7 +1253,7 @@ <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"Zagon aplikacij."</string> <string name="android_upgrading_complete" msgid="409800058018374746">"Dokončevanje zagona."</string> <string name="fp_power_button_enrollment_message" msgid="5648173517663246140">"Pritisnili ste gumb za vklop, s čimer običajno izklopite zaslon.\n\nPoskusite se narahlo dotakniti med nastavljanjem prstnega odtisa."</string> - <string name="fp_power_button_enrollment_title" msgid="6976841690455338563">"Za končanje nastavitve izklopite zaslon"</string> + <string name="fp_power_button_enrollment_title" msgid="6976841690455338563">"Za končanje nastavitve izklopite zaslon."</string> <string name="fp_power_button_enrollment_button_text" msgid="3199783266386029200">"Izklopi"</string> <string name="fp_power_button_bp_title" msgid="5585506104526820067">"Želite nadaljevati preverjanje prstnega odtisa?"</string> <string name="fp_power_button_bp_message" msgid="2983163038168903393">"Pritisnili ste gumb za vklop, s čimer običajno izklopite zaslon.\n\nZa preverjanje prstnega odtisa se poskusite narahlo dotakniti."</string> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index bd8a42920af6..07e05c6a830e 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -2070,10 +2070,6 @@ STREAM_MUSIC as if it's on TV platform. --> <bool name="config_single_volume">false</bool> - <!-- Flag indicating whether notification and ringtone volumes - are controlled together (aliasing is true) or not. --> - <bool name="config_alias_ring_notif_stream_types">true</bool> - <!-- The number of volume steps for the notification stream --> <integer name="config_audio_notif_vol_steps">7</integer> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 44d84683abf9..8e7da4a5eac3 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -278,7 +278,6 @@ <java-symbol type="attr" name="autofillSaveCustomSubtitleMaxHeight"/> <java-symbol type="bool" name="action_bar_embed_tabs" /> <java-symbol type="bool" name="action_bar_expanded_action_views_exclusive" /> - <java-symbol type="bool" name="config_alias_ring_notif_stream_types" /> <java-symbol type="integer" name="config_audio_notif_vol_default" /> <java-symbol type="integer" name="config_audio_notif_vol_steps" /> <java-symbol type="integer" name="config_audio_ring_vol_default" /> diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityOverrideData.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityOverrideData.java index 499f7a55996b..875cd0bb4e16 100644 --- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityOverrideData.java +++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityOverrideData.java @@ -24,11 +24,13 @@ import android.content.res.Resources; import android.database.Cursor; import android.graphics.Bitmap; import android.os.UserHandle; +import android.util.Pair; import com.android.internal.app.chooser.TargetInfo; import com.android.internal.logging.MetricsLogger; import java.util.List; +import java.util.function.BiFunction; import java.util.function.Function; /** @@ -50,6 +52,9 @@ public class ChooserActivityOverrideData { public Function<PackageManager, PackageManager> createPackageManager; public Function<TargetInfo, Boolean> onSafelyStartCallback; public Function<ChooserListAdapter, Void> onQueryDirectShareTargets; + public BiFunction< + IChooserWrapper, ChooserListAdapter, Pair<Integer, ChooserActivity.ServiceResultInfo[]>> + directShareTargets; public ResolverListController resolverListController; public ResolverListController workResolverListController; public Boolean isVoiceInteraction; @@ -72,6 +77,7 @@ public class ChooserActivityOverrideData { public void reset() { onSafelyStartCallback = null; onQueryDirectShareTargets = null; + directShareTargets = null; isVoiceInteraction = null; createPackageManager = null; previewThumbnail = null; @@ -112,4 +118,3 @@ public class ChooserActivityOverrideData { private ChooserActivityOverrideData() {} } - diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java index e8c7ce0b312b..d656678c16ee 100644 --- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java +++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java @@ -81,6 +81,7 @@ import android.net.Uri; import android.os.UserHandle; import android.provider.DeviceConfig; import android.service.chooser.ChooserTarget; +import android.util.Pair; import android.view.View; import androidx.annotation.CallSuper; @@ -89,6 +90,7 @@ import androidx.test.platform.app.InstrumentationRegistry; import androidx.test.rule.ActivityTestRule; import com.android.internal.R; +import com.android.internal.app.ChooserActivity.ServiceResultInfo; import com.android.internal.app.ResolverActivity.ResolvedComponentInfo; import com.android.internal.app.chooser.DisplayResolveInfo; import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; @@ -2166,8 +2168,8 @@ public class ChooserActivityTest { assertThat(logger.numCalls(), is(6)); } - @Test @Ignore - public void testDirectTargetLogging() throws InterruptedException { + @Test + public void testDirectTargetLogging() { Intent sendIntent = createSendTextIntent(); // We need app targets for direct targets to get displayed List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); @@ -2187,30 +2189,35 @@ public class ChooserActivityTest { resolvedComponentInfos.get(0).getResolveInfoAt(0).activityInfo.packageName); ResolveInfo ri = ResolverDataProvider.createResolveInfo(3, 0); + ChooserActivityOverrideData + .getInstance() + .directShareTargets = (activity, adapter) -> { + DisplayResolveInfo displayInfo = activity.createTestDisplayResolveInfo( + sendIntent, + ri, + "testLabel", + "testInfo", + sendIntent, + /* resolveInfoPresentationGetter */ null); + ServiceResultInfo[] results = { + new ServiceResultInfo( + displayInfo, + serviceTargets, + adapter.getUserHandle())}; + // TODO: consider covering the other type. + // Only 2 types are expected out of the shortcut loading logic: + // - TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER, if shortcuts were loaded from + // the ShortcutManager, and; + // - TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE, if shortcuts were loaded + // from AppPredictor. + // Ideally, our tests should cover all of them. + return new Pair<>(TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER, results); + }; + // Start activity final IChooserWrapper activity = (IChooserWrapper) mActivityRule.launchActivity(Intent.createChooser(sendIntent, null)); - // Insert the direct share target - Map<ChooserTarget, ShortcutInfo> directShareToShortcutInfos = new HashMap<>(); - directShareToShortcutInfos.put(serviceTargets.get(0), null); - InstrumentationRegistry.getInstrumentation().runOnMainSync( - () -> activity.getAdapter().addServiceResults( - activity.createTestDisplayResolveInfo(sendIntent, - ri, - "testLabel", - "testInfo", - sendIntent, - /* resolveInfoPresentationGetter */ null), - serviceTargets, - TARGET_TYPE_CHOOSER_TARGET, - directShareToShortcutInfos) - ); - // Thread.sleep shouldn't be a thing in an integration test but it's - // necessary here because of the way the code is structured - // TODO: restructure the tests b/129870719 - Thread.sleep(((ChooserActivity) activity).mListViewUpdateDelayMs); - assertThat("Chooser should have 3 targets (2 apps, 1 direct)", activity.getAdapter().getCount(), is(3)); assertThat("Chooser should have exactly one selectable direct target", diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java index 7f8598217ec6..4c3235ca8ac0 100644 --- a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java +++ b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java @@ -31,6 +31,7 @@ import android.database.Cursor; import android.graphics.Bitmap; import android.net.Uri; import android.os.UserHandle; +import android.util.Pair; import android.util.Size; import com.android.internal.app.ResolverListAdapter.ResolveInfoPresentationGetter; @@ -239,6 +240,12 @@ public class ChooserWrapperActivity extends ChooserActivity implements IChooserW @Override protected void queryDirectShareTargets(ChooserListAdapter adapter, boolean skipAppPredictionService) { + if (sOverrides.directShareTargets != null) { + Pair<Integer, ServiceResultInfo[]> result = + sOverrides.directShareTargets.apply(this, adapter); + sendShortcutManagerShareTargetResults(result.first, result.second); + return; + } if (sOverrides.onQueryDirectShareTargets != null) { sOverrides.onQueryDirectShareTargets.apply(adapter); } diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index 31e2abe0bb85..a4a38c713a66 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -1327,6 +1327,12 @@ "group": "WM_DEBUG_ANIM", "at": "com\/android\/server\/wm\/WindowState.java" }, + "-787664727": { + "message": "Cannot launch dream activity due to invalid state. dream component: %s packageName: %s", + "level": "ERROR", + "group": "WM_DEBUG_DREAM", + "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" + }, "-784959154": { "message": "Attempted to add private presentation window to a non-private display. Aborting.", "level": "WARN", @@ -1921,6 +1927,12 @@ "group": "WM_DEBUG_STATES", "at": "com\/android\/server\/wm\/TaskFragment.java" }, + "-240296576": { + "message": "handleAppTransitionReady: displayId=%d appTransition={%s} openingApps=[%s] closingApps=[%s] transit=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/AppTransitionController.java" + }, "-237664290": { "message": "Pause the recording session on display %s", "level": "VERBOSE", @@ -2023,12 +2035,6 @@ "group": "WM_DEBUG_CONTENT_RECORDING", "at": "com\/android\/server\/wm\/ContentRecorder.java" }, - "-134793542": { - "message": "handleAppTransitionReady: displayId=%d appTransition={%s} excludeLauncherFromAnimation=%b openingApps=[%s] closingApps=[%s] transit=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/AppTransitionController.java" - }, "-134091882": { "message": "Screenshotting Activity %s", "level": "VERBOSE", @@ -2569,6 +2575,12 @@ "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "323235828": { + "message": "Delaying app transition for recents animation to finish", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/AppTransitionController.java" + }, "327461496": { "message": "Complete pause: %s", "level": "VERBOSE", @@ -2857,6 +2869,12 @@ "group": "WM_DEBUG_BOOT", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "601283564": { + "message": "Dream packageName does not match active dream. Package %s does not match %s", + "level": "ERROR", + "group": "WM_DEBUG_DREAM", + "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" + }, "608694300": { "message": " NEW SURFACE SESSION %s", "level": "INFO", @@ -3097,12 +3115,6 @@ "group": "WM_DEBUG_STARTING_WINDOW", "at": "com\/android\/server\/wm\/WindowStateAnimator.java" }, - "829869827": { - "message": "Cannot launch dream activity due to invalid state. dreaming: %b packageName: %s", - "level": "ERROR", - "group": "WM_DEBUG_DREAM", - "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" - }, "835814848": { "message": "%s", "level": "INFO", @@ -4135,12 +4147,6 @@ "group": "WM_DEBUG_WINDOW_ORGANIZER", "at": "com\/android\/server\/wm\/TaskOrganizerController.java" }, - "1918771553": { - "message": "Dream packageName does not match active dream. Package %s does not match %s or %s", - "level": "ERROR", - "group": "WM_DEBUG_DREAM", - "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" - }, "1921821199": { "message": "Preserving %s until the new one is added", "level": "VERBOSE", diff --git a/libs/WindowManager/Shell/res/values-af/strings.xml b/libs/WindowManager/Shell/res/values-af/strings.xml index f9d153fd7408..f328d5959b6d 100644 --- a/libs/WindowManager/Shell/res/values-af/strings.xml +++ b/libs/WindowManager/Shell/res/values-af/strings.xml @@ -86,4 +86,9 @@ <string name="close_button_text" msgid="2913281996024033299">"Maak toe"</string> <string name="back_button_text" msgid="1469718707134137085">"Terug"</string> <string name="handle_text" msgid="1766582106752184456">"Handvatsel"</string> + <string name="fullscreen_text" msgid="1162316685217676079">"Volskerm"</string> + <string name="desktop_text" msgid="1077633567027630454">"Rekenaarmodus"</string> + <string name="split_screen_text" msgid="1396336058129570886">"Verdeelde skerm"</string> + <string name="more_button_text" msgid="3655388105592893530">"Meer"</string> + <string name="float_button_text" msgid="9221657008391364581">"Sweef"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-am/strings.xml b/libs/WindowManager/Shell/res/values-am/strings.xml index 17b1d1bdbff1..f85103e819c3 100644 --- a/libs/WindowManager/Shell/res/values-am/strings.xml +++ b/libs/WindowManager/Shell/res/values-am/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"ዝጋ"</string> <string name="back_button_text" msgid="1469718707134137085">"ተመለስ"</string> <string name="handle_text" msgid="1766582106752184456">"መያዣ"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-ar/strings.xml b/libs/WindowManager/Shell/res/values-ar/strings.xml index 2babc3ea5fcd..5eda65f39532 100644 --- a/libs/WindowManager/Shell/res/values-ar/strings.xml +++ b/libs/WindowManager/Shell/res/values-ar/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"إغلاق"</string> <string name="back_button_text" msgid="1469718707134137085">"رجوع"</string> <string name="handle_text" msgid="1766582106752184456">"مقبض"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-as/strings.xml b/libs/WindowManager/Shell/res/values-as/strings.xml index fe43cd69110f..5a2e6cdd98e4 100644 --- a/libs/WindowManager/Shell/res/values-as/strings.xml +++ b/libs/WindowManager/Shell/res/values-as/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"বন্ধ কৰক"</string> <string name="back_button_text" msgid="1469718707134137085">"উভতি যাওক"</string> <string name="handle_text" msgid="1766582106752184456">"হেণ্ডেল"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-az/strings.xml b/libs/WindowManager/Shell/res/values-az/strings.xml index c22f5425048e..06539a110a1d 100644 --- a/libs/WindowManager/Shell/res/values-az/strings.xml +++ b/libs/WindowManager/Shell/res/values-az/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"Bağlayın"</string> <string name="back_button_text" msgid="1469718707134137085">"Geriyə"</string> <string name="handle_text" msgid="1766582106752184456">"Hər kəsə açıq istifadəçi adı"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml index 4dda1dbf3906..c91473e7d6d2 100644 --- a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml +++ b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"Zatvorite"</string> <string name="back_button_text" msgid="1469718707134137085">"Nazad"</string> <string name="handle_text" msgid="1766582106752184456">"Identifikator"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-be/strings.xml b/libs/WindowManager/Shell/res/values-be/strings.xml index cf5394b0ebd2..9d0cd77f9acd 100644 --- a/libs/WindowManager/Shell/res/values-be/strings.xml +++ b/libs/WindowManager/Shell/res/values-be/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"Закрыць"</string> <string name="back_button_text" msgid="1469718707134137085">"Назад"</string> <string name="handle_text" msgid="1766582106752184456">"Маркер"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-bg/strings.xml b/libs/WindowManager/Shell/res/values-bg/strings.xml index c525f521c0e3..230f71d00619 100644 --- a/libs/WindowManager/Shell/res/values-bg/strings.xml +++ b/libs/WindowManager/Shell/res/values-bg/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"Затваряне"</string> <string name="back_button_text" msgid="1469718707134137085">"Назад"</string> <string name="handle_text" msgid="1766582106752184456">"Манипулатор"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-bn/strings.xml b/libs/WindowManager/Shell/res/values-bn/strings.xml index b652d383a49a..71a2fc239bd8 100644 --- a/libs/WindowManager/Shell/res/values-bn/strings.xml +++ b/libs/WindowManager/Shell/res/values-bn/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"বন্ধ করুন"</string> <string name="back_button_text" msgid="1469718707134137085">"ফিরে যান"</string> <string name="handle_text" msgid="1766582106752184456">"হাতল"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-bs/strings.xml b/libs/WindowManager/Shell/res/values-bs/strings.xml index bec284d4dff8..29e83b40700c 100644 --- a/libs/WindowManager/Shell/res/values-bs/strings.xml +++ b/libs/WindowManager/Shell/res/values-bs/strings.xml @@ -86,4 +86,9 @@ <string name="close_button_text" msgid="2913281996024033299">"Zatvaranje"</string> <string name="back_button_text" msgid="1469718707134137085">"Nazad"</string> <string name="handle_text" msgid="1766582106752184456">"Identifikator"</string> + <string name="fullscreen_text" msgid="1162316685217676079">"Puni zaslon"</string> + <string name="desktop_text" msgid="1077633567027630454">"Stolni način rada"</string> + <string name="split_screen_text" msgid="1396336058129570886">"Razdvojeni zaslon"</string> + <string name="more_button_text" msgid="3655388105592893530">"Više"</string> + <string name="float_button_text" msgid="9221657008391364581">"Plutajući"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-ca/strings.xml b/libs/WindowManager/Shell/res/values-ca/strings.xml index c84bb4884068..29ce75e0984d 100644 --- a/libs/WindowManager/Shell/res/values-ca/strings.xml +++ b/libs/WindowManager/Shell/res/values-ca/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"Tanca"</string> <string name="back_button_text" msgid="1469718707134137085">"Enrere"</string> <string name="handle_text" msgid="1766582106752184456">"Ansa"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-cs/strings.xml b/libs/WindowManager/Shell/res/values-cs/strings.xml index 17f7374d9d00..7c7cf40a2a06 100644 --- a/libs/WindowManager/Shell/res/values-cs/strings.xml +++ b/libs/WindowManager/Shell/res/values-cs/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"Zavřít"</string> <string name="back_button_text" msgid="1469718707134137085">"Zpět"</string> <string name="handle_text" msgid="1766582106752184456">"Úchyt"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-da/strings.xml b/libs/WindowManager/Shell/res/values-da/strings.xml index 60c1f8588445..0f5b7019da42 100644 --- a/libs/WindowManager/Shell/res/values-da/strings.xml +++ b/libs/WindowManager/Shell/res/values-da/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"Luk"</string> <string name="back_button_text" msgid="1469718707134137085">"Tilbage"</string> <string name="handle_text" msgid="1766582106752184456">"Håndtag"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-de/strings.xml b/libs/WindowManager/Shell/res/values-de/strings.xml index b57f0c857d26..10f883658032 100644 --- a/libs/WindowManager/Shell/res/values-de/strings.xml +++ b/libs/WindowManager/Shell/res/values-de/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"Schließen"</string> <string name="back_button_text" msgid="1469718707134137085">"Zurück"</string> <string name="handle_text" msgid="1766582106752184456">"Ziehpunkt"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-el/strings.xml b/libs/WindowManager/Shell/res/values-el/strings.xml index 2f929466343c..9630352dba9a 100644 --- a/libs/WindowManager/Shell/res/values-el/strings.xml +++ b/libs/WindowManager/Shell/res/values-el/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"Κλείσιμο"</string> <string name="back_button_text" msgid="1469718707134137085">"Πίσω"</string> <string name="handle_text" msgid="1766582106752184456">"Λαβή"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml index 9c88e78616e7..f714ca255529 100644 --- a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml +++ b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml @@ -86,4 +86,9 @@ <string name="close_button_text" msgid="2913281996024033299">"Close"</string> <string name="back_button_text" msgid="1469718707134137085">"Back"</string> <string name="handle_text" msgid="1766582106752184456">"Handle"</string> + <string name="fullscreen_text" msgid="1162316685217676079">"Full screen"</string> + <string name="desktop_text" msgid="1077633567027630454">"Desktop mode"</string> + <string name="split_screen_text" msgid="1396336058129570886">"Split screen"</string> + <string name="more_button_text" msgid="3655388105592893530">"More"</string> + <string name="float_button_text" msgid="9221657008391364581">"Float"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml index 9c88e78616e7..f714ca255529 100644 --- a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml +++ b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml @@ -86,4 +86,9 @@ <string name="close_button_text" msgid="2913281996024033299">"Close"</string> <string name="back_button_text" msgid="1469718707134137085">"Back"</string> <string name="handle_text" msgid="1766582106752184456">"Handle"</string> + <string name="fullscreen_text" msgid="1162316685217676079">"Full screen"</string> + <string name="desktop_text" msgid="1077633567027630454">"Desktop mode"</string> + <string name="split_screen_text" msgid="1396336058129570886">"Split screen"</string> + <string name="more_button_text" msgid="3655388105592893530">"More"</string> + <string name="float_button_text" msgid="9221657008391364581">"Float"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml index 9c88e78616e7..f714ca255529 100644 --- a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml +++ b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml @@ -86,4 +86,9 @@ <string name="close_button_text" msgid="2913281996024033299">"Close"</string> <string name="back_button_text" msgid="1469718707134137085">"Back"</string> <string name="handle_text" msgid="1766582106752184456">"Handle"</string> + <string name="fullscreen_text" msgid="1162316685217676079">"Full screen"</string> + <string name="desktop_text" msgid="1077633567027630454">"Desktop mode"</string> + <string name="split_screen_text" msgid="1396336058129570886">"Split screen"</string> + <string name="more_button_text" msgid="3655388105592893530">"More"</string> + <string name="float_button_text" msgid="9221657008391364581">"Float"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml index 9c88e78616e7..f714ca255529 100644 --- a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml +++ b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml @@ -86,4 +86,9 @@ <string name="close_button_text" msgid="2913281996024033299">"Close"</string> <string name="back_button_text" msgid="1469718707134137085">"Back"</string> <string name="handle_text" msgid="1766582106752184456">"Handle"</string> + <string name="fullscreen_text" msgid="1162316685217676079">"Full screen"</string> + <string name="desktop_text" msgid="1077633567027630454">"Desktop mode"</string> + <string name="split_screen_text" msgid="1396336058129570886">"Split screen"</string> + <string name="more_button_text" msgid="3655388105592893530">"More"</string> + <string name="float_button_text" msgid="9221657008391364581">"Float"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-en-rXC/strings.xml b/libs/WindowManager/Shell/res/values-en-rXC/strings.xml index 646b3c545c00..4a9cc939b77f 100644 --- a/libs/WindowManager/Shell/res/values-en-rXC/strings.xml +++ b/libs/WindowManager/Shell/res/values-en-rXC/strings.xml @@ -86,4 +86,9 @@ <string name="close_button_text" msgid="2913281996024033299">"Close"</string> <string name="back_button_text" msgid="1469718707134137085">"Back"</string> <string name="handle_text" msgid="1766582106752184456">"Handle"</string> + <string name="fullscreen_text" msgid="1162316685217676079">"Fullscreen"</string> + <string name="desktop_text" msgid="1077633567027630454">"Desktop Mode"</string> + <string name="split_screen_text" msgid="1396336058129570886">"Split Screen"</string> + <string name="more_button_text" msgid="3655388105592893530">"More"</string> + <string name="float_button_text" msgid="9221657008391364581">"Float"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml index aed03acf026c..9a1b9e9d3337 100644 --- a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml +++ b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml @@ -86,4 +86,9 @@ <string name="close_button_text" msgid="2913281996024033299">"Cerrar"</string> <string name="back_button_text" msgid="1469718707134137085">"Atrás"</string> <string name="handle_text" msgid="1766582106752184456">"Controlador"</string> + <string name="fullscreen_text" msgid="1162316685217676079">"Pantalla completa"</string> + <string name="desktop_text" msgid="1077633567027630454">"Modo de escritorio"</string> + <string name="split_screen_text" msgid="1396336058129570886">"Pantalla dividida"</string> + <string name="more_button_text" msgid="3655388105592893530">"Más"</string> + <string name="float_button_text" msgid="9221657008391364581">"Flotante"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-es/strings.xml b/libs/WindowManager/Shell/res/values-es/strings.xml index bddc2c3e61bc..aedca54ab33d 100644 --- a/libs/WindowManager/Shell/res/values-es/strings.xml +++ b/libs/WindowManager/Shell/res/values-es/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"Cerrar"</string> <string name="back_button_text" msgid="1469718707134137085">"Atrás"</string> <string name="handle_text" msgid="1766582106752184456">"Controlador"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-et/strings.xml b/libs/WindowManager/Shell/res/values-et/strings.xml index 696a520d0b86..4cbc7334a85a 100644 --- a/libs/WindowManager/Shell/res/values-et/strings.xml +++ b/libs/WindowManager/Shell/res/values-et/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"Sule"</string> <string name="back_button_text" msgid="1469718707134137085">"Tagasi"</string> <string name="handle_text" msgid="1766582106752184456">"Käepide"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-eu/strings.xml b/libs/WindowManager/Shell/res/values-eu/strings.xml index d1fca9b6d4b9..e3da48adab7e 100644 --- a/libs/WindowManager/Shell/res/values-eu/strings.xml +++ b/libs/WindowManager/Shell/res/values-eu/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"Itxi"</string> <string name="back_button_text" msgid="1469718707134137085">"Atzera"</string> <string name="handle_text" msgid="1766582106752184456">"Kontu-izena"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-fa/strings.xml b/libs/WindowManager/Shell/res/values-fa/strings.xml index 7550a091bd79..501f3661c78e 100644 --- a/libs/WindowManager/Shell/res/values-fa/strings.xml +++ b/libs/WindowManager/Shell/res/values-fa/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"بستن"</string> <string name="back_button_text" msgid="1469718707134137085">"برگشتن"</string> <string name="handle_text" msgid="1766582106752184456">"دستگیره"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-fi/strings.xml b/libs/WindowManager/Shell/res/values-fi/strings.xml index a79adf8e686c..c9b95dc5a676 100644 --- a/libs/WindowManager/Shell/res/values-fi/strings.xml +++ b/libs/WindowManager/Shell/res/values-fi/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"Sulje"</string> <string name="back_button_text" msgid="1469718707134137085">"Takaisin"</string> <string name="handle_text" msgid="1766582106752184456">"Kahva"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml index 4c59b9999d76..79b01deabdb4 100644 --- a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml +++ b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"Fermer"</string> <string name="back_button_text" msgid="1469718707134137085">"Retour"</string> <string name="handle_text" msgid="1766582106752184456">"Identifiant"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-fr/strings.xml b/libs/WindowManager/Shell/res/values-fr/strings.xml index 865e2dcf4775..0456cfb0e5d9 100644 --- a/libs/WindowManager/Shell/res/values-fr/strings.xml +++ b/libs/WindowManager/Shell/res/values-fr/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"Fermer"</string> <string name="back_button_text" msgid="1469718707134137085">"Retour"</string> <string name="handle_text" msgid="1766582106752184456">"Poignée"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-gl/strings.xml b/libs/WindowManager/Shell/res/values-gl/strings.xml index 47e6696dfe4c..7c28e4ea6e12 100644 --- a/libs/WindowManager/Shell/res/values-gl/strings.xml +++ b/libs/WindowManager/Shell/res/values-gl/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"Pechar"</string> <string name="back_button_text" msgid="1469718707134137085">"Atrás"</string> <string name="handle_text" msgid="1766582106752184456">"Controlador"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-gu/strings.xml b/libs/WindowManager/Shell/res/values-gu/strings.xml index 5d52c58616a8..73b2e413c5ad 100644 --- a/libs/WindowManager/Shell/res/values-gu/strings.xml +++ b/libs/WindowManager/Shell/res/values-gu/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"બંધ કરો"</string> <string name="back_button_text" msgid="1469718707134137085">"પાછળ"</string> <string name="handle_text" msgid="1766582106752184456">"હૅન્ડલ"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-hi/strings.xml b/libs/WindowManager/Shell/res/values-hi/strings.xml index 2c643ded9dee..e70b15dfe474 100644 --- a/libs/WindowManager/Shell/res/values-hi/strings.xml +++ b/libs/WindowManager/Shell/res/values-hi/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"बंद करें"</string> <string name="back_button_text" msgid="1469718707134137085">"वापस जाएं"</string> <string name="handle_text" msgid="1766582106752184456">"हैंडल"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-hr/strings.xml b/libs/WindowManager/Shell/res/values-hr/strings.xml index 32ab87cfda64..1d618547620f 100644 --- a/libs/WindowManager/Shell/res/values-hr/strings.xml +++ b/libs/WindowManager/Shell/res/values-hr/strings.xml @@ -86,4 +86,9 @@ <string name="close_button_text" msgid="2913281996024033299">"Zatvori"</string> <string name="back_button_text" msgid="1469718707134137085">"Natrag"</string> <string name="handle_text" msgid="1766582106752184456">"Pokazivač"</string> + <string name="fullscreen_text" msgid="1162316685217676079">"Puni zaslon"</string> + <string name="desktop_text" msgid="1077633567027630454">"Stolni način rada"</string> + <string name="split_screen_text" msgid="1396336058129570886">"Razdvojeni zaslon"</string> + <string name="more_button_text" msgid="3655388105592893530">"Više"</string> + <string name="float_button_text" msgid="9221657008391364581">"Plutajući"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-hu/strings.xml b/libs/WindowManager/Shell/res/values-hu/strings.xml index dba7f4e37f8e..d816c50a1f95 100644 --- a/libs/WindowManager/Shell/res/values-hu/strings.xml +++ b/libs/WindowManager/Shell/res/values-hu/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"Bezárás"</string> <string name="back_button_text" msgid="1469718707134137085">"Vissza"</string> <string name="handle_text" msgid="1766582106752184456">"Fogópont"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-hy/strings.xml b/libs/WindowManager/Shell/res/values-hy/strings.xml index d3bca3374e9d..e9ab5f431c17 100644 --- a/libs/WindowManager/Shell/res/values-hy/strings.xml +++ b/libs/WindowManager/Shell/res/values-hy/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"Փակել"</string> <string name="back_button_text" msgid="1469718707134137085">"Հետ"</string> <string name="handle_text" msgid="1766582106752184456">"Նշիչ"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-in/strings.xml b/libs/WindowManager/Shell/res/values-in/strings.xml index f157fcf6dbec..cd983f56581d 100644 --- a/libs/WindowManager/Shell/res/values-in/strings.xml +++ b/libs/WindowManager/Shell/res/values-in/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"Tutup"</string> <string name="back_button_text" msgid="1469718707134137085">"Kembali"</string> <string name="handle_text" msgid="1766582106752184456">"Tuas"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-is/strings.xml b/libs/WindowManager/Shell/res/values-is/strings.xml index ead1757ed4bb..0a20007dbf67 100644 --- a/libs/WindowManager/Shell/res/values-is/strings.xml +++ b/libs/WindowManager/Shell/res/values-is/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"Loka"</string> <string name="back_button_text" msgid="1469718707134137085">"Til baka"</string> <string name="handle_text" msgid="1766582106752184456">"Handfang"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-it/strings.xml b/libs/WindowManager/Shell/res/values-it/strings.xml index 4e8ac62a6288..7e232d45372f 100644 --- a/libs/WindowManager/Shell/res/values-it/strings.xml +++ b/libs/WindowManager/Shell/res/values-it/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"Chiudi"</string> <string name="back_button_text" msgid="1469718707134137085">"Indietro"</string> <string name="handle_text" msgid="1766582106752184456">"Handle"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-iw/strings.xml b/libs/WindowManager/Shell/res/values-iw/strings.xml index 12c962d09ce1..68cf8aa15dbf 100644 --- a/libs/WindowManager/Shell/res/values-iw/strings.xml +++ b/libs/WindowManager/Shell/res/values-iw/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"סגירה"</string> <string name="back_button_text" msgid="1469718707134137085">"חזרה"</string> <string name="handle_text" msgid="1766582106752184456">"נקודת אחיזה"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-ja/strings.xml b/libs/WindowManager/Shell/res/values-ja/strings.xml index d9f514a4c312..6f22e3dc0404 100644 --- a/libs/WindowManager/Shell/res/values-ja/strings.xml +++ b/libs/WindowManager/Shell/res/values-ja/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"閉じる"</string> <string name="back_button_text" msgid="1469718707134137085">"戻る"</string> <string name="handle_text" msgid="1766582106752184456">"ハンドル"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-ka/strings.xml b/libs/WindowManager/Shell/res/values-ka/strings.xml index b28436131fe9..6989dcaf769f 100644 --- a/libs/WindowManager/Shell/res/values-ka/strings.xml +++ b/libs/WindowManager/Shell/res/values-ka/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"დახურვა"</string> <string name="back_button_text" msgid="1469718707134137085">"უკან"</string> <string name="handle_text" msgid="1766582106752184456">"იდენტიფიკატორი"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-kk/strings.xml b/libs/WindowManager/Shell/res/values-kk/strings.xml index 2d842b88996a..c83486bc2755 100644 --- a/libs/WindowManager/Shell/res/values-kk/strings.xml +++ b/libs/WindowManager/Shell/res/values-kk/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"Жабу"</string> <string name="back_button_text" msgid="1469718707134137085">"Артқа"</string> <string name="handle_text" msgid="1766582106752184456">"Идентификатор"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-km/strings.xml b/libs/WindowManager/Shell/res/values-km/strings.xml index 3243a648ac0e..dd25f205302b 100644 --- a/libs/WindowManager/Shell/res/values-km/strings.xml +++ b/libs/WindowManager/Shell/res/values-km/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"បិទ"</string> <string name="back_button_text" msgid="1469718707134137085">"ថយក្រោយ"</string> <string name="handle_text" msgid="1766582106752184456">"ឈ្មោះអ្នកប្រើប្រាស់"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-kn/strings.xml b/libs/WindowManager/Shell/res/values-kn/strings.xml index 57c7124222c9..473cbe1e7e1e 100644 --- a/libs/WindowManager/Shell/res/values-kn/strings.xml +++ b/libs/WindowManager/Shell/res/values-kn/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"ಮುಚ್ಚಿರಿ"</string> <string name="back_button_text" msgid="1469718707134137085">"ಹಿಂದಕ್ಕೆ"</string> <string name="handle_text" msgid="1766582106752184456">"ಹ್ಯಾಂಡಲ್"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-ko/strings.xml b/libs/WindowManager/Shell/res/values-ko/strings.xml index 3a655b870df3..69750958711a 100644 --- a/libs/WindowManager/Shell/res/values-ko/strings.xml +++ b/libs/WindowManager/Shell/res/values-ko/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"닫기"</string> <string name="back_button_text" msgid="1469718707134137085">"뒤로"</string> <string name="handle_text" msgid="1766582106752184456">"핸들"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-ky/strings.xml b/libs/WindowManager/Shell/res/values-ky/strings.xml index ab51ca0725b0..88d02a66c95a 100644 --- a/libs/WindowManager/Shell/res/values-ky/strings.xml +++ b/libs/WindowManager/Shell/res/values-ky/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"Жабуу"</string> <string name="back_button_text" msgid="1469718707134137085">"Артка"</string> <string name="handle_text" msgid="1766582106752184456">"Маркер"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-lo/strings.xml b/libs/WindowManager/Shell/res/values-lo/strings.xml index b800e3eb174f..91cd78d84339 100644 --- a/libs/WindowManager/Shell/res/values-lo/strings.xml +++ b/libs/WindowManager/Shell/res/values-lo/strings.xml @@ -86,4 +86,9 @@ <string name="close_button_text" msgid="2913281996024033299">"ປິດ"</string> <string name="back_button_text" msgid="1469718707134137085">"ກັບຄືນ"</string> <string name="handle_text" msgid="1766582106752184456">"ມືບັງຄັບ"</string> + <string name="fullscreen_text" msgid="1162316685217676079">"ເຕັມຈໍ"</string> + <string name="desktop_text" msgid="1077633567027630454">"ໂໝດເດັສທັອບ"</string> + <string name="split_screen_text" msgid="1396336058129570886">"ແບ່ງໜ້າຈໍ"</string> + <string name="more_button_text" msgid="3655388105592893530">"ເພີ່ມເຕີມ"</string> + <string name="float_button_text" msgid="9221657008391364581">"ລອຍ"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-lt/strings.xml b/libs/WindowManager/Shell/res/values-lt/strings.xml index 94339a46df6f..58056fade148 100644 --- a/libs/WindowManager/Shell/res/values-lt/strings.xml +++ b/libs/WindowManager/Shell/res/values-lt/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"Uždaryti"</string> <string name="back_button_text" msgid="1469718707134137085">"Atgal"</string> <string name="handle_text" msgid="1766582106752184456">"Rankenėlė"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-lv/strings.xml b/libs/WindowManager/Shell/res/values-lv/strings.xml index d28245360922..30d6ef119870 100644 --- a/libs/WindowManager/Shell/res/values-lv/strings.xml +++ b/libs/WindowManager/Shell/res/values-lv/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"Aizvērt"</string> <string name="back_button_text" msgid="1469718707134137085">"Atpakaļ"</string> <string name="handle_text" msgid="1766582106752184456">"Turis"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-mk/strings.xml b/libs/WindowManager/Shell/res/values-mk/strings.xml index 64ce3f617768..512518072f84 100644 --- a/libs/WindowManager/Shell/res/values-mk/strings.xml +++ b/libs/WindowManager/Shell/res/values-mk/strings.xml @@ -86,4 +86,9 @@ <string name="close_button_text" msgid="2913281996024033299">"Затвори"</string> <string name="back_button_text" msgid="1469718707134137085">"Назад"</string> <string name="handle_text" msgid="1766582106752184456">"Прекар"</string> + <string name="fullscreen_text" msgid="1162316685217676079">"Цел екран"</string> + <string name="desktop_text" msgid="1077633567027630454">"Режим за компјутер"</string> + <string name="split_screen_text" msgid="1396336058129570886">"Поделен екран"</string> + <string name="more_button_text" msgid="3655388105592893530">"Повеќе"</string> + <string name="float_button_text" msgid="9221657008391364581">"Лебдечко"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-ml/strings.xml b/libs/WindowManager/Shell/res/values-ml/strings.xml index 5db8d6d071f1..1367c0352557 100644 --- a/libs/WindowManager/Shell/res/values-ml/strings.xml +++ b/libs/WindowManager/Shell/res/values-ml/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"അടയ്ക്കുക"</string> <string name="back_button_text" msgid="1469718707134137085">"മടങ്ങുക"</string> <string name="handle_text" msgid="1766582106752184456">"ഹാൻഡിൽ"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-mn/strings.xml b/libs/WindowManager/Shell/res/values-mn/strings.xml index be02be111438..83cf9a972824 100644 --- a/libs/WindowManager/Shell/res/values-mn/strings.xml +++ b/libs/WindowManager/Shell/res/values-mn/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"Хаах"</string> <string name="back_button_text" msgid="1469718707134137085">"Буцах"</string> <string name="handle_text" msgid="1766582106752184456">"Бариул"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-mr/strings.xml b/libs/WindowManager/Shell/res/values-mr/strings.xml index 779cf5c870bc..380270bd60c7 100644 --- a/libs/WindowManager/Shell/res/values-mr/strings.xml +++ b/libs/WindowManager/Shell/res/values-mr/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"बंद करा"</string> <string name="back_button_text" msgid="1469718707134137085">"मागे जा"</string> <string name="handle_text" msgid="1766582106752184456">"हँडल"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-ms/strings.xml b/libs/WindowManager/Shell/res/values-ms/strings.xml index 85d380e04889..e1d4947e9013 100644 --- a/libs/WindowManager/Shell/res/values-ms/strings.xml +++ b/libs/WindowManager/Shell/res/values-ms/strings.xml @@ -86,4 +86,9 @@ <string name="close_button_text" msgid="2913281996024033299">"Tutup"</string> <string name="back_button_text" msgid="1469718707134137085">"Kembali"</string> <string name="handle_text" msgid="1766582106752184456">"Pemegang"</string> + <string name="fullscreen_text" msgid="1162316685217676079">"Skrin penuh"</string> + <string name="desktop_text" msgid="1077633567027630454">"Mod Desktop"</string> + <string name="split_screen_text" msgid="1396336058129570886">"Skrin Pisah"</string> + <string name="more_button_text" msgid="3655388105592893530">"Lagi"</string> + <string name="float_button_text" msgid="9221657008391364581">"Terapung"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-my/strings.xml b/libs/WindowManager/Shell/res/values-my/strings.xml index 517098d76d4a..c85fce56421a 100644 --- a/libs/WindowManager/Shell/res/values-my/strings.xml +++ b/libs/WindowManager/Shell/res/values-my/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"ပိတ်ရန်"</string> <string name="back_button_text" msgid="1469718707134137085">"နောက်သို့"</string> <string name="handle_text" msgid="1766582106752184456">"သုံးသူအမည်"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-nb/strings.xml b/libs/WindowManager/Shell/res/values-nb/strings.xml index 0ceee2d1c928..71608c606953 100644 --- a/libs/WindowManager/Shell/res/values-nb/strings.xml +++ b/libs/WindowManager/Shell/res/values-nb/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"Lukk"</string> <string name="back_button_text" msgid="1469718707134137085">"Tilbake"</string> <string name="handle_text" msgid="1766582106752184456">"Håndtak"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-ne/strings.xml b/libs/WindowManager/Shell/res/values-ne/strings.xml index 7ba49e57111e..28b64c2a314e 100644 --- a/libs/WindowManager/Shell/res/values-ne/strings.xml +++ b/libs/WindowManager/Shell/res/values-ne/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"बन्द गर्नुहोस्"</string> <string name="back_button_text" msgid="1469718707134137085">"पछाडि"</string> <string name="handle_text" msgid="1766582106752184456">"ह्यान्डल"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-nl/strings.xml b/libs/WindowManager/Shell/res/values-nl/strings.xml index dd3ebe415218..b0bc07ba5dda 100644 --- a/libs/WindowManager/Shell/res/values-nl/strings.xml +++ b/libs/WindowManager/Shell/res/values-nl/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"Sluiten"</string> <string name="back_button_text" msgid="1469718707134137085">"Terug"</string> <string name="handle_text" msgid="1766582106752184456">"Gebruikersnaam"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-or/strings.xml b/libs/WindowManager/Shell/res/values-or/strings.xml index 52280a1daf24..c0a2b81ef239 100644 --- a/libs/WindowManager/Shell/res/values-or/strings.xml +++ b/libs/WindowManager/Shell/res/values-or/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"ବନ୍ଦ କରନ୍ତୁ"</string> <string name="back_button_text" msgid="1469718707134137085">"ପଛକୁ ଫେରନ୍ତୁ"</string> <string name="handle_text" msgid="1766582106752184456">"ହେଣ୍ଡେଲ"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-pa/strings.xml b/libs/WindowManager/Shell/res/values-pa/strings.xml index c3056ca0a511..5cdaeaf6ed88 100644 --- a/libs/WindowManager/Shell/res/values-pa/strings.xml +++ b/libs/WindowManager/Shell/res/values-pa/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"ਬੰਦ ਕਰੋ"</string> <string name="back_button_text" msgid="1469718707134137085">"ਪਿੱਛੇ"</string> <string name="handle_text" msgid="1766582106752184456">"ਹੈਂਡਲ"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-pl/strings.xml b/libs/WindowManager/Shell/res/values-pl/strings.xml index 56a6fb1664c1..af65b766fd6a 100644 --- a/libs/WindowManager/Shell/res/values-pl/strings.xml +++ b/libs/WindowManager/Shell/res/values-pl/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"Zamknij"</string> <string name="back_button_text" msgid="1469718707134137085">"Wstecz"</string> <string name="handle_text" msgid="1766582106752184456">"Uchwyt"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml index 3cb708dda567..cb4395397a69 100644 --- a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml +++ b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml @@ -86,4 +86,9 @@ <string name="close_button_text" msgid="2913281996024033299">"Fechar"</string> <string name="back_button_text" msgid="1469718707134137085">"Voltar"</string> <string name="handle_text" msgid="1766582106752184456">"Alça"</string> + <string name="fullscreen_text" msgid="1162316685217676079">"Tela cheia"</string> + <string name="desktop_text" msgid="1077633567027630454">"Modo área de trabalho"</string> + <string name="split_screen_text" msgid="1396336058129570886">"Tela dividida"</string> + <string name="more_button_text" msgid="3655388105592893530">"Mais"</string> + <string name="float_button_text" msgid="9221657008391364581">"Ponto flutuante"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml index e5be57848957..19b1771db6e6 100644 --- a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml +++ b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml @@ -86,4 +86,9 @@ <string name="close_button_text" msgid="2913281996024033299">"Fechar"</string> <string name="back_button_text" msgid="1469718707134137085">"Anterior"</string> <string name="handle_text" msgid="1766582106752184456">"Indicador"</string> + <string name="fullscreen_text" msgid="1162316685217676079">"Ecrã inteiro"</string> + <string name="desktop_text" msgid="1077633567027630454">"Modo de ambiente de trabalho"</string> + <string name="split_screen_text" msgid="1396336058129570886">"Ecrã dividido"</string> + <string name="more_button_text" msgid="3655388105592893530">"Mais"</string> + <string name="float_button_text" msgid="9221657008391364581">"Flutuar"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-pt/strings.xml b/libs/WindowManager/Shell/res/values-pt/strings.xml index 3cb708dda567..cb4395397a69 100644 --- a/libs/WindowManager/Shell/res/values-pt/strings.xml +++ b/libs/WindowManager/Shell/res/values-pt/strings.xml @@ -86,4 +86,9 @@ <string name="close_button_text" msgid="2913281996024033299">"Fechar"</string> <string name="back_button_text" msgid="1469718707134137085">"Voltar"</string> <string name="handle_text" msgid="1766582106752184456">"Alça"</string> + <string name="fullscreen_text" msgid="1162316685217676079">"Tela cheia"</string> + <string name="desktop_text" msgid="1077633567027630454">"Modo área de trabalho"</string> + <string name="split_screen_text" msgid="1396336058129570886">"Tela dividida"</string> + <string name="more_button_text" msgid="3655388105592893530">"Mais"</string> + <string name="float_button_text" msgid="9221657008391364581">"Ponto flutuante"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-ro/strings.xml b/libs/WindowManager/Shell/res/values-ro/strings.xml index c03e043ee6f0..68bfda4bf821 100644 --- a/libs/WindowManager/Shell/res/values-ro/strings.xml +++ b/libs/WindowManager/Shell/res/values-ro/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"Închide"</string> <string name="back_button_text" msgid="1469718707134137085">"Înapoi"</string> <string name="handle_text" msgid="1766582106752184456">"Ghidaj"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-ru/strings.xml b/libs/WindowManager/Shell/res/values-ru/strings.xml index b96caf23a0a7..a0512b83579a 100644 --- a/libs/WindowManager/Shell/res/values-ru/strings.xml +++ b/libs/WindowManager/Shell/res/values-ru/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"Закрыть"</string> <string name="back_button_text" msgid="1469718707134137085">"Назад"</string> <string name="handle_text" msgid="1766582106752184456">"Маркер"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-si/strings.xml b/libs/WindowManager/Shell/res/values-si/strings.xml index a1ec3b5d5bb2..a8d4fe5b35e7 100644 --- a/libs/WindowManager/Shell/res/values-si/strings.xml +++ b/libs/WindowManager/Shell/res/values-si/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"වසන්න"</string> <string name="back_button_text" msgid="1469718707134137085">"ආපසු"</string> <string name="handle_text" msgid="1766582106752184456">"හැඬලය"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-sk/strings.xml b/libs/WindowManager/Shell/res/values-sk/strings.xml index e3dafb6c88e9..f597113b3bef 100644 --- a/libs/WindowManager/Shell/res/values-sk/strings.xml +++ b/libs/WindowManager/Shell/res/values-sk/strings.xml @@ -86,4 +86,9 @@ <string name="close_button_text" msgid="2913281996024033299">"Zavrieť"</string> <string name="back_button_text" msgid="1469718707134137085">"Späť"</string> <string name="handle_text" msgid="1766582106752184456">"Rukoväť"</string> + <string name="fullscreen_text" msgid="1162316685217676079">"Celá obrazovka"</string> + <string name="desktop_text" msgid="1077633567027630454">"Režim počítača"</string> + <string name="split_screen_text" msgid="1396336058129570886">"Rozdelená obrazovka"</string> + <string name="more_button_text" msgid="3655388105592893530">"Viac"</string> + <string name="float_button_text" msgid="9221657008391364581">"Plávajúce"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-sl/strings.xml b/libs/WindowManager/Shell/res/values-sl/strings.xml index 2f995e5076f3..3716f3537919 100644 --- a/libs/WindowManager/Shell/res/values-sl/strings.xml +++ b/libs/WindowManager/Shell/res/values-sl/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"Zapri"</string> <string name="back_button_text" msgid="1469718707134137085">"Nazaj"</string> <string name="handle_text" msgid="1766582106752184456">"Ročica"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-sq/strings.xml b/libs/WindowManager/Shell/res/values-sq/strings.xml index 3d9bde4f8066..b5203fd524c4 100644 --- a/libs/WindowManager/Shell/res/values-sq/strings.xml +++ b/libs/WindowManager/Shell/res/values-sq/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"Mbyll"</string> <string name="back_button_text" msgid="1469718707134137085">"Pas"</string> <string name="handle_text" msgid="1766582106752184456">"Emërtimi"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-sr/strings.xml b/libs/WindowManager/Shell/res/values-sr/strings.xml index b00c4f49f649..20bb38031866 100644 --- a/libs/WindowManager/Shell/res/values-sr/strings.xml +++ b/libs/WindowManager/Shell/res/values-sr/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"Затворите"</string> <string name="back_button_text" msgid="1469718707134137085">"Назад"</string> <string name="handle_text" msgid="1766582106752184456">"Идентификатор"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-sv/strings.xml b/libs/WindowManager/Shell/res/values-sv/strings.xml index b39fd04ebf3d..9e31581646d2 100644 --- a/libs/WindowManager/Shell/res/values-sv/strings.xml +++ b/libs/WindowManager/Shell/res/values-sv/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"Stäng"</string> <string name="back_button_text" msgid="1469718707134137085">"Tillbaka"</string> <string name="handle_text" msgid="1766582106752184456">"Handtag"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-sw/strings.xml b/libs/WindowManager/Shell/res/values-sw/strings.xml index f4d4ceec5a1f..1b7c651a7df8 100644 --- a/libs/WindowManager/Shell/res/values-sw/strings.xml +++ b/libs/WindowManager/Shell/res/values-sw/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"Funga"</string> <string name="back_button_text" msgid="1469718707134137085">"Rudi nyuma"</string> <string name="handle_text" msgid="1766582106752184456">"Ncha"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-ta/strings.xml b/libs/WindowManager/Shell/res/values-ta/strings.xml index 6d050c2ba26e..4db168efeb74 100644 --- a/libs/WindowManager/Shell/res/values-ta/strings.xml +++ b/libs/WindowManager/Shell/res/values-ta/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"மூடும்"</string> <string name="back_button_text" msgid="1469718707134137085">"பின்செல்லும்"</string> <string name="handle_text" msgid="1766582106752184456">"ஹேண்டில்"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-te/strings.xml b/libs/WindowManager/Shell/res/values-te/strings.xml index 91c411f0d49c..e677268b1ba0 100644 --- a/libs/WindowManager/Shell/res/values-te/strings.xml +++ b/libs/WindowManager/Shell/res/values-te/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"మూసివేయండి"</string> <string name="back_button_text" msgid="1469718707134137085">"వెనుకకు"</string> <string name="handle_text" msgid="1766582106752184456">"హ్యాండిల్"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-th/strings.xml b/libs/WindowManager/Shell/res/values-th/strings.xml index ee362dcedd0a..d1d0d9f25017 100644 --- a/libs/WindowManager/Shell/res/values-th/strings.xml +++ b/libs/WindowManager/Shell/res/values-th/strings.xml @@ -86,4 +86,9 @@ <string name="close_button_text" msgid="2913281996024033299">"ปิด"</string> <string name="back_button_text" msgid="1469718707134137085">"กลับ"</string> <string name="handle_text" msgid="1766582106752184456">"แฮนเดิล"</string> + <string name="fullscreen_text" msgid="1162316685217676079">"เต็มหน้าจอ"</string> + <string name="desktop_text" msgid="1077633567027630454">"โหมดเดสก์ท็อป"</string> + <string name="split_screen_text" msgid="1396336058129570886">"แยกหน้าจอ"</string> + <string name="more_button_text" msgid="3655388105592893530">"เพิ่มเติม"</string> + <string name="float_button_text" msgid="9221657008391364581">"ล่องลอย"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-tl/strings.xml b/libs/WindowManager/Shell/res/values-tl/strings.xml index d82036568499..8395e2aa76f7 100644 --- a/libs/WindowManager/Shell/res/values-tl/strings.xml +++ b/libs/WindowManager/Shell/res/values-tl/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"Isara"</string> <string name="back_button_text" msgid="1469718707134137085">"Bumalik"</string> <string name="handle_text" msgid="1766582106752184456">"Handle"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-tr/strings.xml b/libs/WindowManager/Shell/res/values-tr/strings.xml index 025e2e6215e7..5516a73d812c 100644 --- a/libs/WindowManager/Shell/res/values-tr/strings.xml +++ b/libs/WindowManager/Shell/res/values-tr/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"Kapat"</string> <string name="back_button_text" msgid="1469718707134137085">"Geri"</string> <string name="handle_text" msgid="1766582106752184456">"Herkese açık kullanıcı adı"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-uk/strings.xml b/libs/WindowManager/Shell/res/values-uk/strings.xml index 97bb68080117..73cb70da368a 100644 --- a/libs/WindowManager/Shell/res/values-uk/strings.xml +++ b/libs/WindowManager/Shell/res/values-uk/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"Закрити"</string> <string name="back_button_text" msgid="1469718707134137085">"Назад"</string> <string name="handle_text" msgid="1766582106752184456">"Маркер"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-ur/strings.xml b/libs/WindowManager/Shell/res/values-ur/strings.xml index 883026a437a5..842a25513d34 100644 --- a/libs/WindowManager/Shell/res/values-ur/strings.xml +++ b/libs/WindowManager/Shell/res/values-ur/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"بند کریں"</string> <string name="back_button_text" msgid="1469718707134137085">"پیچھے"</string> <string name="handle_text" msgid="1766582106752184456">"ہینڈل"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-uz/strings.xml b/libs/WindowManager/Shell/res/values-uz/strings.xml index ce73bd586c71..7f8ec01d238f 100644 --- a/libs/WindowManager/Shell/res/values-uz/strings.xml +++ b/libs/WindowManager/Shell/res/values-uz/strings.xml @@ -86,4 +86,9 @@ <string name="close_button_text" msgid="2913281996024033299">"Yopish"</string> <string name="back_button_text" msgid="1469718707134137085">"Orqaga"</string> <string name="handle_text" msgid="1766582106752184456">"Identifikator"</string> + <string name="fullscreen_text" msgid="1162316685217676079">"Butun ekran"</string> + <string name="desktop_text" msgid="1077633567027630454">"Desktop rejimi"</string> + <string name="split_screen_text" msgid="1396336058129570886">"Ekranni ikkiga ajratish"</string> + <string name="more_button_text" msgid="3655388105592893530">"Yana"</string> + <string name="float_button_text" msgid="9221657008391364581">"Pufakli"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-vi/strings.xml b/libs/WindowManager/Shell/res/values-vi/strings.xml index 511db6fbc116..9f8b686842d4 100644 --- a/libs/WindowManager/Shell/res/values-vi/strings.xml +++ b/libs/WindowManager/Shell/res/values-vi/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"Đóng"</string> <string name="back_button_text" msgid="1469718707134137085">"Quay lại"</string> <string name="handle_text" msgid="1766582106752184456">"Xử lý"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml index 16cbf126eff8..c8e3b99aa4e6 100644 --- a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml +++ b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"关闭"</string> <string name="back_button_text" msgid="1469718707134137085">"返回"</string> <string name="handle_text" msgid="1766582106752184456">"处理"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml index 5a497d090f54..8e5fd7f3b335 100644 --- a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml +++ b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"關閉"</string> <string name="back_button_text" msgid="1469718707134137085">"返去"</string> <string name="handle_text" msgid="1766582106752184456">"控點"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml index 2c2ce33f58ab..17557f987b51 100644 --- a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml +++ b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"關閉"</string> <string name="back_button_text" msgid="1469718707134137085">"返回"</string> <string name="handle_text" msgid="1766582106752184456">"控點"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/res/values-zu/strings.xml b/libs/WindowManager/Shell/res/values-zu/strings.xml index 59d87a0a9371..01af7b813da7 100644 --- a/libs/WindowManager/Shell/res/values-zu/strings.xml +++ b/libs/WindowManager/Shell/res/values-zu/strings.xml @@ -86,4 +86,14 @@ <string name="close_button_text" msgid="2913281996024033299">"Vala"</string> <string name="back_button_text" msgid="1469718707134137085">"Emuva"</string> <string name="handle_text" msgid="1766582106752184456">"Isibambo"</string> + <!-- no translation found for fullscreen_text (1162316685217676079) --> + <skip /> + <!-- no translation found for desktop_text (1077633567027630454) --> + <skip /> + <!-- no translation found for split_screen_text (1396336058129570886) --> + <skip /> + <!-- no translation found for more_button_text (3655388105592893530) --> + <skip /> + <!-- no translation found for float_button_text (9221657008391364581) --> + <skip /> </resources> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/back/OWNERS new file mode 100644 index 000000000000..1e0f9bc6322f --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/OWNERS @@ -0,0 +1,5 @@ +# WM shell sub-module back navigation owners +# Bug component: 1152663 +shanh@google.com +arthurhung@google.com +wilsonshih@google.com 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 725b20525bf7..bec6844ae863 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 @@ -24,6 +24,7 @@ import static android.view.View.INVISIBLE; import static android.view.View.VISIBLE; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; +import static com.android.wm.shell.bubbles.Bubble.KEY_APP_BUBBLE; import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_CONTROLLER; import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_GESTURE; import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES; @@ -37,7 +38,6 @@ import static com.android.wm.shell.bubbles.Bubbles.DISMISS_NO_LONGER_BUBBLE; import static com.android.wm.shell.bubbles.Bubbles.DISMISS_PACKAGE_REMOVED; import static com.android.wm.shell.bubbles.Bubbles.DISMISS_SHORTCUT_REMOVED; import static com.android.wm.shell.bubbles.Bubbles.DISMISS_USER_CHANGED; -import static com.android.wm.shell.floating.FloatingTasksController.SHOW_FLOATING_TASKS_AS_BUBBLES; import android.annotation.NonNull; import android.annotation.UserIdInt; @@ -150,6 +150,9 @@ 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; @@ -210,7 +213,6 @@ public class BubbleController implements ConfigurationChangeListener { /** Drag and drop controller to register listener for onDragStarted. */ private DragAndDropController mDragAndDropController; - public BubbleController(Context context, ShellInit shellInit, ShellCommandHandler shellCommandHandler, @@ -526,6 +528,12 @@ 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 this userId belongs to the current user. */ private boolean isCurrentProfile(int userId) { return userId == UserHandle.USER_ALL @@ -591,7 +599,8 @@ public class BubbleController implements ConfigurationChangeListener { } mStackView.setUnbubbleConversationCallback(mSysuiProxy::onUnbubbleConversation); } - if (SHOW_FLOATING_TASKS_AS_BUBBLES && mBubblePositioner.isLargeScreen()) { + + if (mIsBubbleBarEnabled && mBubblePositioner.isLargeScreen()) { mBubblePositioner.setUsePinnedLocation(true); } else { mBubblePositioner.setUsePinnedLocation(false); @@ -959,14 +968,18 @@ public class BubbleController implements ConfigurationChangeListener { } /** - * Adds a bubble for a specific intent. These bubbles are <b>not</b> backed by a notification - * and remain until the user dismisses the bubble or bubble stack. Only one intent bubble - * is supported at a time. + * Adds and expands bubble for a specific intent. These bubbles are <b>not</b> backed by a n + * otification and remain until the user dismisses the bubble or bubble stack. Only one intent + * bubble is supported at a time. * * @param intent the intent to display in the bubble expanded view. */ - public void addAppBubble(Intent intent) { + public void showAppBubble(Intent intent) { if (intent == null || intent.getPackage() == null) return; + + PackageManager packageManager = getPackageManagerForUser(mContext, mCurrentUserId); + if (!isResizableActivity(intent, packageManager, KEY_APP_BUBBLE)) return; + Bubble b = new Bubble(intent, UserHandle.of(mCurrentUserId), mMainExecutor); b.setShouldAutoExpand(true); inflateAndAdd(b, /* suppressFlyout= */ true, /* showInShade= */ false); @@ -1489,18 +1502,23 @@ public class BubbleController implements ConfigurationChangeListener { } PackageManager packageManager = getPackageManagerForUser( context, entry.getStatusBarNotification().getUser().getIdentifier()); - ActivityInfo info = - intent.getIntent().resolveActivityInfo(packageManager, 0); + return isResizableActivity(intent.getIntent(), packageManager, entry.getKey()); + } + + static boolean isResizableActivity(Intent intent, PackageManager packageManager, String key) { + if (intent == null) { + Log.w(TAG, "Unable to send as bubble: " + key + " null intent"); + return false; + } + ActivityInfo info = intent.resolveActivityInfo(packageManager, 0); if (info == null) { - Log.w(TAG, "Unable to send as bubble, " - + entry.getKey() + " couldn't find activity info for intent: " - + intent); + Log.w(TAG, "Unable to send as bubble: " + key + + " couldn't find activity info for intent: " + intent); return false; } if (!ActivityInfo.isResizeableMode(info.resizeMode)) { - Log.w(TAG, "Unable to send as bubble, " - + entry.getKey() + " activity is not resizable for intent: " - + intent); + Log.w(TAG, "Unable to send as bubble: " + key + + " activity is not resizable for intent: " + intent); return false; } return true; @@ -1674,6 +1692,13 @@ public class BubbleController implements ConfigurationChangeListener { } @Override + public void showAppBubble(Intent intent) { + mMainExecutor.execute(() -> { + BubbleController.this.showAppBubble(intent); + }); + } + + @Override public boolean handleDismissalInterception(BubbleEntry entry, @Nullable List<BubbleEntry> children, IntConsumer removeCallback, Executor callbackExecutor) { @@ -1784,6 +1809,13 @@ 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/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java index 6efad097e3cc..609ee084f23f 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 @@ -83,7 +83,6 @@ import com.android.wm.shell.bubbles.animation.AnimatableScaleMatrix; import com.android.wm.shell.bubbles.animation.ExpandedAnimationController; import com.android.wm.shell.bubbles.animation.ExpandedViewAnimationController; import com.android.wm.shell.bubbles.animation.ExpandedViewAnimationControllerImpl; -import com.android.wm.shell.bubbles.animation.ExpandedViewAnimationControllerStub; import com.android.wm.shell.bubbles.animation.PhysicsAnimationLayout; import com.android.wm.shell.bubbles.animation.StackAnimationController; import com.android.wm.shell.common.FloatingContentCoordinator; @@ -105,11 +104,6 @@ import java.util.stream.Collectors; */ public class BubbleStackView extends FrameLayout implements ViewTreeObserver.OnComputeInternalInsetsListener { - /** - * Set to {@code true} to enable home gesture handling in bubbles - */ - public static final boolean HOME_GESTURE_ENABLED = - SystemProperties.getBoolean("persist.wm.debug.bubbles_home_gesture", true); public static final boolean ENABLE_FLING_TO_DISMISS_BUBBLE = SystemProperties.getBoolean("persist.wm.debug.fling_to_dismiss_bubble", true); @@ -898,12 +892,8 @@ public class BubbleStackView extends FrameLayout mExpandedAnimationController = new ExpandedAnimationController(mPositioner, onBubbleAnimatedOut, this); - if (HOME_GESTURE_ENABLED) { - mExpandedViewAnimationController = - new ExpandedViewAnimationControllerImpl(context, mPositioner); - } else { - mExpandedViewAnimationController = new ExpandedViewAnimationControllerStub(); - } + mExpandedViewAnimationController = + new ExpandedViewAnimationControllerImpl(context, mPositioner); mSurfaceSynchronizer = synchronizer != null ? synchronizer : DEFAULT_SURFACE_SYNCHRONIZER; @@ -1965,11 +1955,7 @@ public class BubbleStackView extends FrameLayout if (wasExpanded) { stopMonitoringSwipeUpGesture(); - if (HOME_GESTURE_ENABLED) { - animateCollapse(); - } else { - animateCollapseWithScale(); - } + animateCollapse(); logBubbleEvent(mExpandedBubble, FrameworkStatsLog.BUBBLE_UICHANGED__ACTION__COLLAPSED); } else { animateExpansion(); @@ -1977,13 +1963,11 @@ public class BubbleStackView extends FrameLayout logBubbleEvent(mExpandedBubble, FrameworkStatsLog.BUBBLE_UICHANGED__ACTION__EXPANDED); logBubbleEvent(mExpandedBubble, FrameworkStatsLog.BUBBLE_UICHANGED__ACTION__STACK_EXPANDED); - if (HOME_GESTURE_ENABLED) { - mBubbleController.isNotificationPanelExpanded(notifPanelExpanded -> { - if (!notifPanelExpanded && mIsExpanded) { - startMonitoringSwipeUpGesture(); - } - }); - } + mBubbleController.isNotificationPanelExpanded(notifPanelExpanded -> { + if (!notifPanelExpanded && mIsExpanded) { + startMonitoringSwipeUpGesture(); + } + }); } notifyExpansionChanged(mExpandedBubble, mIsExpanded); } @@ -2299,106 +2283,6 @@ public class BubbleStackView extends FrameLayout mMainExecutor.executeDelayed(mDelayedAnimation, startDelay); } - private void animateCollapseWithScale() { - cancelDelayedExpandCollapseSwitchAnimations(); - - if (mManageEduView != null && mManageEduView.getVisibility() == VISIBLE) { - mManageEduView.hide(); - } - // Hide the menu if it's visible. - showManageMenu(false); - - mIsExpanded = false; - mIsExpansionAnimating = true; - - showScrim(false); - - mBubbleContainer.cancelAllAnimations(); - - // If we were in the middle of swapping, the animating-out surface would have been scaling - // to zero - finish it off. - PhysicsAnimator.getInstance(mAnimatingOutSurfaceContainer).cancel(); - mAnimatingOutSurfaceContainer.setScaleX(0f); - mAnimatingOutSurfaceContainer.setScaleY(0f); - - // Let the expanded animation controller know that it shouldn't animate child adds/reorders - // since we're about to animate collapsed. - mExpandedAnimationController.notifyPreparingToCollapse(); - - mExpandedAnimationController.collapseBackToStack( - mStackAnimationController.getStackPositionAlongNearestHorizontalEdge() - /* collapseTo */, - () -> mBubbleContainer.setActiveController(mStackAnimationController)); - - int index; - if (mExpandedBubble != null && BubbleOverflow.KEY.equals(mExpandedBubble.getKey())) { - index = mBubbleData.getBubbles().size(); - } else { - index = mBubbleData.getBubbles().indexOf(mExpandedBubble); - } - // Value the bubble is animating from (back into the stack). - final PointF p = mPositioner.getExpandedBubbleXY(index, getState()); - if (mPositioner.showBubblesVertically()) { - float pivotX; - float pivotY = p.y + mBubbleSize / 2f; - if (mStackOnLeftOrWillBe) { - pivotX = mPositioner.getAvailableRect().left + mBubbleSize + mExpandedViewPadding; - } else { - pivotX = mPositioner.getAvailableRect().right - mBubbleSize - mExpandedViewPadding; - } - mExpandedViewContainerMatrix.setScale( - 1f, 1f, - pivotX, pivotY); - } else { - mExpandedViewContainerMatrix.setScale( - 1f, 1f, - p.x + mBubbleSize / 2f, - p.y + mBubbleSize + mExpandedViewPadding); - } - - mExpandedViewAlphaAnimator.reverse(); - - // When the animation completes, we should no longer be showing the content. - if (mExpandedBubble.getExpandedView() != null) { - mExpandedBubble.getExpandedView().setContentVisibility(false); - } - - PhysicsAnimator.getInstance(mExpandedViewContainerMatrix).cancel(); - PhysicsAnimator.getInstance(mExpandedViewContainerMatrix) - .spring(AnimatableScaleMatrix.SCALE_X, - AnimatableScaleMatrix.getAnimatableValueForScaleFactor( - 1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT), - mScaleOutSpringConfig) - .spring(AnimatableScaleMatrix.SCALE_Y, - AnimatableScaleMatrix.getAnimatableValueForScaleFactor( - 1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT), - mScaleOutSpringConfig) - .addUpdateListener((target, values) -> { - mExpandedViewContainer.setAnimationMatrix(mExpandedViewContainerMatrix); - }) - .withEndActions(() -> { - final BubbleViewProvider previouslySelected = mExpandedBubble; - beforeExpandedViewAnimation(); - if (mManageEduView != null) { - mManageEduView.hide(); - } - - if (DEBUG_BUBBLE_STACK_VIEW) { - Log.d(TAG, "animateCollapse"); - Log.d(TAG, BubbleDebugConfig.formatBubblesString(getBubblesOnScreen(), - mExpandedBubble)); - } - updateOverflowVisibility(); - updateZOrder(); - updateBadges(true /* setBadgeForCollapsedStack */); - afterExpandedViewAnimation(); - if (previouslySelected != null) { - previouslySelected.setTaskViewVisibility(false); - } - }) - .start(); - } - private void animateCollapse() { cancelDelayedExpandCollapseSwitchAnimations(); @@ -2580,65 +2464,6 @@ public class BubbleStackView extends FrameLayout * and clip the expanded view. */ public void setImeVisible(boolean visible) { - if (HOME_GESTURE_ENABLED) { - setImeVisibleInternal(visible); - } else { - setImeVisibleWithoutClipping(visible); - } - } - - private void setImeVisibleWithoutClipping(boolean visible) { - if ((mIsExpansionAnimating || mIsBubbleSwitchAnimating) && mIsExpanded) { - // This will update the animation so the bubbles move to position for the IME - mExpandedAnimationController.expandFromStack(() -> { - updatePointerPosition(false /* forIme */); - afterExpandedViewAnimation(); - } /* after */); - return; - } - - if (!mIsExpanded && getBubbleCount() > 0) { - final float stackDestinationY = - mStackAnimationController.animateForImeVisibility(visible); - - // How far the stack is animating due to IME, we'll just animate the flyout by that - // much too. - final float stackDy = - stackDestinationY - mStackAnimationController.getStackPosition().y; - - // If the flyout is visible, translate it along with the bubble stack. - if (mFlyout.getVisibility() == VISIBLE) { - PhysicsAnimator.getInstance(mFlyout) - .spring(DynamicAnimation.TRANSLATION_Y, - mFlyout.getTranslationY() + stackDy, - FLYOUT_IME_ANIMATION_SPRING_CONFIG) - .start(); - } - } else if (mPositioner.showBubblesVertically() && mIsExpanded - && mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) { - float selectedY = mPositioner.getExpandedBubbleXY(getState().selectedIndex, - getState()).y; - float newExpandedViewTop = mPositioner.getExpandedViewY(mExpandedBubble, selectedY); - mExpandedBubble.getExpandedView().setImeVisible(visible); - if (!mExpandedBubble.getExpandedView().isUsingMaxHeight()) { - mExpandedViewContainer.animate().translationY(newExpandedViewTop); - } - - List<Animator> animList = new ArrayList(); - for (int i = 0; i < mBubbleContainer.getChildCount(); i++) { - View child = mBubbleContainer.getChildAt(i); - float transY = mPositioner.getExpandedBubbleXY(i, getState()).y; - ObjectAnimator anim = ObjectAnimator.ofFloat(child, TRANSLATION_Y, transY); - animList.add(anim); - } - updatePointerPosition(true /* forIme */); - AnimatorSet set = new AnimatorSet(); - set.playTogether(animList); - set.start(); - } - } - - private void setImeVisibleInternal(boolean visible) { if ((mIsExpansionAnimating || mIsBubbleSwitchAnimating) && mIsExpanded) { // This will update the animation so the bubbles move to position for the IME mExpandedAnimationController.expandFromStack(() -> { 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 7f891ec6d215..465d1abe0a3d 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 @@ -22,6 +22,7 @@ import static java.lang.annotation.ElementType.PARAMETER; import static java.lang.annotation.RetentionPolicy.SOURCE; import android.app.NotificationChannel; +import android.content.Intent; import android.content.pm.UserInfo; import android.os.UserHandle; import android.service.notification.NotificationListenerService; @@ -108,6 +109,15 @@ public interface Bubbles { void expandStackAndSelectBubble(Bubble bubble); /** + * Adds and expands bubble that is not notification based, but instead based on an intent from + * the app. The intent must be explicit (i.e. include a package name or fully qualified + * component class name) and the activity for it should be resizable. + * + * @param intent the intent to populate the bubble. + */ + void showAppBubble(Intent intent); + + /** * @return a bubble that matches the provided shortcutId, if one exists. */ @Nullable @@ -232,6 +242,11 @@ 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/ExpandedAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java index b91062f891e8..33629f9f4622 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java @@ -20,7 +20,6 @@ import static android.view.View.LAYOUT_DIRECTION_RTL; import static com.android.wm.shell.bubbles.BubblePositioner.NUM_VISIBLE_WHEN_RESTING; import static com.android.wm.shell.bubbles.BubbleStackView.ENABLE_FLING_TO_DISMISS_BUBBLE; -import static com.android.wm.shell.bubbles.BubbleStackView.HOME_GESTURE_ENABLED; import android.content.res.Resources; import android.graphics.Path; @@ -81,11 +80,6 @@ public class ExpandedAnimationController new PhysicsAnimator.SpringConfig( EXPAND_COLLAPSE_ANIM_STIFFNESS, SpringForce.DAMPING_RATIO_NO_BOUNCY); - private final PhysicsAnimator.SpringConfig mAnimateOutSpringConfigWithoutHomeGesture = - new PhysicsAnimator.SpringConfig( - EXPAND_COLLAPSE_ANIM_STIFFNESS_WITHOUT_HOME_GESTURE, - SpringForce.DAMPING_RATIO_NO_BOUNCY); - /** Horizontal offset between bubbles, which we need to know to re-stack them. */ private float mStackOffsetPx; /** Size of each bubble. */ @@ -307,14 +301,8 @@ public class ExpandedAnimationController (firstBubbleLeads && index == 0) || (!firstBubbleLeads && index == mLayout.getChildCount() - 1); - Interpolator interpolator; - if (HOME_GESTURE_ENABLED) { - // When home gesture is enabled, we use a different animation timing for collapse - interpolator = expanding - ? Interpolators.EMPHASIZED_ACCELERATE : Interpolators.EMPHASIZED_DECELERATE; - } else { - interpolator = Interpolators.LINEAR; - } + Interpolator interpolator = expanding + ? Interpolators.EMPHASIZED_ACCELERATE : Interpolators.EMPHASIZED_DECELERATE; animation .followAnimatedTargetAlongPath( @@ -564,16 +552,10 @@ public class ExpandedAnimationController finishRemoval.run(); mOnBubbleAnimatedOutAction.run(); } else { - PhysicsAnimator.SpringConfig springConfig; - if (HOME_GESTURE_ENABLED) { - springConfig = mAnimateOutSpringConfig; - } else { - springConfig = mAnimateOutSpringConfigWithoutHomeGesture; - } PhysicsAnimator.getInstance(child) .spring(DynamicAnimation.ALPHA, 0f) - .spring(DynamicAnimation.SCALE_X, 0f, springConfig) - .spring(DynamicAnimation.SCALE_Y, 0f, springConfig) + .spring(DynamicAnimation.SCALE_X, 0f, mAnimateOutSpringConfig) + .spring(DynamicAnimation.SCALE_Y, 0f, mAnimateOutSpringConfig) .withEndActions(finishRemoval, mOnBubbleAnimatedOutAction) .start(); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedViewAnimationControllerStub.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedViewAnimationControllerStub.java deleted file mode 100644 index bb8a3aaaf551..000000000000 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedViewAnimationControllerStub.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.wm.shell.bubbles.animation; - -import com.android.wm.shell.bubbles.BubbleExpandedView; - -/** - * Stub implementation {@link ExpandedViewAnimationController} that does not animate the - * {@link BubbleExpandedView} - */ -public class ExpandedViewAnimationControllerStub implements ExpandedViewAnimationController { - @Override - public void setExpandedView(BubbleExpandedView expandedView) { - } - - @Override - public void updateDrag(float distance) { - } - - @Override - public void setSwipeVelocity(float velocity) { - } - - @Override - public boolean shouldCollapse() { - return false; - } - - @Override - public void animateCollapse(Runnable startStackCollapse, Runnable after) { - } - - @Override - public void animateBackToExpanded() { - } - - @Override - public void animateForImeVisibilityChange(boolean visible) { - } - - @Override - public void reset() { - } -} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java index 8bc16bcc9d9d..1474754fc7f7 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java @@ -46,8 +46,10 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.internal.policy.DividerSnapAlgorithm; +import com.android.internal.protolog.common.ProtoLog; import com.android.wm.shell.R; import com.android.wm.shell.animation.Interpolators; +import com.android.wm.shell.protolog.ShellProtoLogGroup; /** * Divider for multi window splits. @@ -364,8 +366,11 @@ public class DividerView extends FrameLayout implements View.OnTouchListener { mViewHost.relayout(lp); } - void setInteractive(boolean interactive) { + void setInteractive(boolean interactive, String from) { if (interactive == mInteractive) return; + ProtoLog.d(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, + "Set divider bar %s from %s", interactive ? "interactive" : "non-interactive", + from); mInteractive = interactive; releaseTouching(); mHandle.setVisibility(mInteractive ? View.VISIBLE : View.INVISIBLE); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java index 74f8bf9ac863..5b7ed278e843 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java @@ -48,6 +48,7 @@ import androidx.annotation.NonNull; import com.android.launcher3.icons.IconProvider; import com.android.wm.shell.R; +import com.android.wm.shell.common.ScreenshotUtils; import com.android.wm.shell.common.SurfaceUtils; import java.util.function.Consumer; @@ -74,10 +75,14 @@ public class SplitDecorManager extends WindowlessWindowManager { private boolean mShown; private boolean mIsResizing; - private Rect mBounds = new Rect(); + private final Rect mBounds = new Rect(); + private final Rect mResizingBounds = new Rect(); + private final Rect mTempRect = new Rect(); private ValueAnimator mFadeAnimator; private int mIconSize; + private int mOffsetX; + private int mOffsetY; public SplitDecorManager(Configuration configuration, IconProvider iconProvider, SurfaceSession surfaceSession) { @@ -158,7 +163,7 @@ public class SplitDecorManager extends WindowlessWindowManager { /** Showing resizing hint. */ public void onResizing(ActivityManager.RunningTaskInfo resizingTask, Rect newBounds, - Rect sideBounds, SurfaceControl.Transaction t) { + Rect sideBounds, SurfaceControl.Transaction t, int offsetX, int offsetY) { if (mResizingIconView == null) { return; } @@ -167,6 +172,9 @@ public class SplitDecorManager extends WindowlessWindowManager { mIsResizing = true; mBounds.set(newBounds); } + mResizingBounds.set(newBounds); + mOffsetX = offsetX; + mOffsetY = offsetY; final boolean show = newBounds.width() > mBounds.width() || newBounds.height() > mBounds.height(); @@ -221,11 +229,37 @@ public class SplitDecorManager extends WindowlessWindowManager { /** Stops showing resizing hint. */ public void onResized(SurfaceControl.Transaction t) { + if (!mShown && mIsResizing) { + mTempRect.set(mResizingBounds); + mTempRect.offsetTo(-mOffsetX, -mOffsetY); + final SurfaceControl screenshot = ScreenshotUtils.takeScreenshot(t, + mHostLeash, mTempRect, Integer.MAX_VALUE - 1); + + final SurfaceControl.Transaction animT = new SurfaceControl.Transaction(); + final ValueAnimator va = ValueAnimator.ofFloat(1, 0); + va.addUpdateListener(valueAnimator -> { + final float progress = (float) valueAnimator.getAnimatedValue(); + animT.setAlpha(screenshot, progress); + animT.apply(); + }); + va.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(@androidx.annotation.NonNull Animator animation) { + animT.remove(screenshot); + animT.apply(); + animT.close(); + } + }); + va.start(); + } + if (mResizingIconView == null) { return; } mIsResizing = false; + mOffsetX = 0; + mOffsetY = 0; if (mFadeAnimator != null && mFadeAnimator.isRunning()) { if (!mShown) { // If fade-out animation is running, just add release callback to it. 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 295a2e3c4244..839edc8c174a 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 @@ -448,7 +448,8 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange */ void updateDivideBounds(int position) { updateBounds(position); - mSplitLayoutHandler.onLayoutSizeChanging(this); + mSplitLayoutHandler.onLayoutSizeChanging(this, mSurfaceEffectPolicy.mParallaxOffset.x, + mSurfaceEffectPolicy.mParallaxOffset.y); } void setDividePosition(int position, boolean applyLayoutChange) { @@ -811,7 +812,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange * @see #applySurfaceChanges(SurfaceControl.Transaction, SurfaceControl, SurfaceControl, * SurfaceControl, SurfaceControl, boolean) */ - void onLayoutSizeChanging(SplitLayout layout); + void onLayoutSizeChanging(SplitLayout layout, int offsetX, int offsetY); /** * Calls when finish resizing the split bounds. @@ -1092,7 +1093,8 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange // ImePositionProcessor#onImeVisibilityChanged directly in DividerView is not enough // because DividerView won't receive onImeVisibilityChanged callback after it being // re-inflated. - mSplitWindowManager.setInteractive(!mImeShown || !mHasImeFocus); + mSplitWindowManager.setInteractive(!mImeShown || !mHasImeFocus, + "onImeStartPositioning"); return needOffset ? IME_ANIMATION_NO_ALPHA : 0; } @@ -1118,7 +1120,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange // Restore the split layout when wm-shell is not controlling IME insets anymore. if (!controlling && mImeShown) { reset(); - mSplitWindowManager.setInteractive(true); + mSplitWindowManager.setInteractive(true, "onImeControlTargetChanged"); mSplitLayoutHandler.setLayoutOffsetTarget(0, 0, SplitLayout.this); mSplitLayoutHandler.onLayoutPositionChanging(SplitLayout.this); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java index 864b9a7528b0..060ac56cae96 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java @@ -166,9 +166,9 @@ public final class SplitWindowManager extends WindowlessWindowManager { } } - void setInteractive(boolean interactive) { + void setInteractive(boolean interactive, String from) { if (mDividerView == null) return; - mDividerView.setInteractive(interactive); + mDividerView.setInteractive(interactive, from); } View getDividerView() { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java index 625d8a83736d..962be9da2111 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java @@ -24,7 +24,6 @@ import android.content.pm.PackageManager; import android.os.Handler; import android.os.SystemProperties; import android.view.IWindowManager; -import android.view.WindowManager; import com.android.internal.logging.UiEventLogger; import com.android.launcher3.icons.IconProvider; @@ -65,8 +64,6 @@ import com.android.wm.shell.desktopmode.DesktopModeTaskRepository; import com.android.wm.shell.displayareahelper.DisplayAreaHelper; import com.android.wm.shell.displayareahelper.DisplayAreaHelperController; import com.android.wm.shell.draganddrop.DragAndDropController; -import com.android.wm.shell.floating.FloatingTasks; -import com.android.wm.shell.floating.FloatingTasksController; import com.android.wm.shell.freeform.FreeformComponents; import com.android.wm.shell.fullscreen.FullscreenTaskListener; import com.android.wm.shell.hidedisplaycutout.HideDisplayCutoutController; @@ -575,47 +572,6 @@ public abstract class WMShellBaseModule { } // - // Floating tasks - // - - @WMSingleton - @Provides - static Optional<FloatingTasks> provideFloatingTasks( - Optional<FloatingTasksController> floatingTaskController) { - return floatingTaskController.map((controller) -> controller.asFloatingTasks()); - } - - @WMSingleton - @Provides - static Optional<FloatingTasksController> provideFloatingTasksController(Context context, - ShellInit shellInit, - ShellController shellController, - ShellCommandHandler shellCommandHandler, - Optional<BubbleController> bubbleController, - WindowManager windowManager, - ShellTaskOrganizer organizer, - TaskViewTransitions taskViewTransitions, - @ShellMainThread ShellExecutor mainExecutor, - @ShellBackgroundThread ShellExecutor bgExecutor, - SyncTransactionQueue syncQueue) { - if (FloatingTasksController.FLOATING_TASKS_ENABLED) { - return Optional.of(new FloatingTasksController(context, - shellInit, - shellController, - shellCommandHandler, - bubbleController, - windowManager, - organizer, - taskViewTransitions, - mainExecutor, - bgExecutor, - syncQueue)); - } else { - return Optional.empty(); - } - } - - // // Starting window // diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java index 497a6f696df8..55378a826385 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java @@ -311,7 +311,7 @@ public class DragLayout extends LinearLayout { animateSplitContainers(true, null /* animCompleteCallback */); animateHighlight(target); } - } else { + } else if (mCurrentTarget.type != target.type) { // Switching between targets mDropZoneView1.animateSwitch(); mDropZoneView2.animateSwitch(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/floating/FloatingDismissController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/floating/FloatingDismissController.java deleted file mode 100644 index 83a1734dc71a..000000000000 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/floating/FloatingDismissController.java +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.wm.shell.floating; - -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.ValueAnimator; -import android.content.Context; -import android.content.res.Resources; -import android.view.MotionEvent; -import android.view.View; - -import androidx.annotation.NonNull; -import androidx.dynamicanimation.animation.DynamicAnimation; - -import com.android.wm.shell.R; -import com.android.wm.shell.bubbles.DismissView; -import com.android.wm.shell.common.magnetictarget.MagnetizedObject; -import com.android.wm.shell.floating.views.FloatingTaskLayer; -import com.android.wm.shell.floating.views.FloatingTaskView; - -import java.util.Objects; - -/** - * Controls a floating dismiss circle that has a 'magnetic' field around it, causing views moved - * close to the target to be stuck to it unless moved out again. - */ -public class FloatingDismissController { - - /** Velocity required to dismiss the view without dragging it into the dismiss target. */ - private static final float FLING_TO_DISMISS_MIN_VELOCITY = 4000f; - /** - * Max velocity that the view can be moving through the target with to stick (i.e. if it's - * more than this velocity, it will pass through the target. - */ - private static final float STICK_TO_TARGET_MAX_X_VELOCITY = 2000f; - /** - * Percentage of the target width to use to determine if an object flung towards the target - * should dismiss (e.g. if target is 100px and this is set ot 2f, anything flung within a - * 200px-wide area around the target will be considered 'near' enough get dismissed). - */ - private static final float FLING_TO_TARGET_WIDTH_PERCENT = 2f; - /** Minimum alpha to apply to the view being dismissed when it is in the target. */ - private static final float DISMISS_VIEW_MIN_ALPHA = 0.6f; - /** Amount to scale down the view being dismissed when it is in the target. */ - private static final float DISMISS_VIEW_SCALE_DOWN_PERCENT = 0.15f; - - private Context mContext; - private FloatingTasksController mController; - private FloatingTaskLayer mParent; - - private DismissView mDismissView; - private ValueAnimator mDismissAnimator; - private View mViewBeingDismissed; - private float mDismissSizePercent; - private float mDismissSize; - - /** - * The currently magnetized object, which is being dragged and will be attracted to the magnetic - * dismiss target. - */ - private MagnetizedObject<View> mMagnetizedObject; - /** - * The MagneticTarget instance for our circular dismiss view. This is added to the - * MagnetizedObject instances for the view being dragged. - */ - private MagnetizedObject.MagneticTarget mMagneticTarget; - /** Magnet listener that handles animating and dismissing the view. */ - private MagnetizedObject.MagnetListener mFloatingViewMagnetListener; - - public FloatingDismissController(Context context, FloatingTasksController controller, - FloatingTaskLayer parent) { - mContext = context; - mController = controller; - mParent = parent; - updateSizes(); - createAndAddDismissView(); - - mDismissAnimator = ValueAnimator.ofFloat(1f, 0f); - mDismissAnimator.addUpdateListener(animation -> { - final float value = (float) animation.getAnimatedValue(); - if (mDismissView != null) { - mDismissView.setPivotX((mDismissView.getRight() - mDismissView.getLeft()) / 2f); - mDismissView.setPivotY((mDismissView.getBottom() - mDismissView.getTop()) / 2f); - final float scaleValue = Math.max(value, mDismissSizePercent); - mDismissView.getCircle().setScaleX(scaleValue); - mDismissView.getCircle().setScaleY(scaleValue); - } - if (mViewBeingDismissed != null) { - // TODO: alpha doesn't actually apply to taskView currently. - mViewBeingDismissed.setAlpha(Math.max(value, DISMISS_VIEW_MIN_ALPHA)); - mViewBeingDismissed.setScaleX(Math.max(value, DISMISS_VIEW_SCALE_DOWN_PERCENT)); - mViewBeingDismissed.setScaleY(Math.max(value, DISMISS_VIEW_SCALE_DOWN_PERCENT)); - } - }); - - mFloatingViewMagnetListener = new MagnetizedObject.MagnetListener() { - @Override - public void onStuckToTarget( - @NonNull MagnetizedObject.MagneticTarget target) { - animateDismissing(/* dismissing= */ true); - } - - @Override - public void onUnstuckFromTarget(@NonNull MagnetizedObject.MagneticTarget target, - float velX, float velY, boolean wasFlungOut) { - animateDismissing(/* dismissing= */ false); - mParent.onUnstuckFromTarget((FloatingTaskView) mViewBeingDismissed, velX, velY, - wasFlungOut); - } - - @Override - public void onReleasedInTarget(@NonNull MagnetizedObject.MagneticTarget target) { - doDismiss(); - } - }; - } - - /** Updates all the sizes used and applies them to the {@link DismissView}. */ - public void updateSizes() { - Resources res = mContext.getResources(); - mDismissSize = res.getDimensionPixelSize( - R.dimen.floating_task_dismiss_circle_size); - final float minDismissSize = res.getDimensionPixelSize( - R.dimen.floating_dismiss_circle_small); - mDismissSizePercent = minDismissSize / mDismissSize; - - if (mDismissView != null) { - mDismissView.updateResources(); - } - } - - /** Prepares the view being dragged to be magnetic. */ - public void setUpMagneticObject(View viewBeingDragged) { - mViewBeingDismissed = viewBeingDragged; - mMagnetizedObject = getMagnetizedView(viewBeingDragged); - mMagnetizedObject.clearAllTargets(); - mMagnetizedObject.addTarget(mMagneticTarget); - mMagnetizedObject.setMagnetListener(mFloatingViewMagnetListener); - } - - /** Shows or hides the dismiss target. */ - public void showDismiss(boolean show) { - if (show) { - mDismissView.show(); - } else { - mDismissView.hide(); - } - } - - /** Passes the MotionEvent to the magnetized object and returns true if it was consumed. */ - public boolean passEventToMagnetizedObject(MotionEvent event) { - return mMagnetizedObject != null && mMagnetizedObject.maybeConsumeMotionEvent(event); - } - - private void createAndAddDismissView() { - if (mDismissView != null) { - mParent.removeView(mDismissView); - } - mDismissView = new DismissView(mContext); - mDismissView.setTargetSizeResId(R.dimen.floating_task_dismiss_circle_size); - mDismissView.updateResources(); - mParent.addView(mDismissView); - - final float dismissRadius = mDismissSize; - // Save the MagneticTarget instance for the newly set up view - we'll add this to the - // MagnetizedObjects when the dismiss view gets shown. - mMagneticTarget = new MagnetizedObject.MagneticTarget( - mDismissView.getCircle(), (int) dismissRadius); - } - - private MagnetizedObject<View> getMagnetizedView(View v) { - if (mMagnetizedObject != null - && Objects.equals(mMagnetizedObject.getUnderlyingObject(), v)) { - // Same view being dragged, we can reuse the magnetic object. - return mMagnetizedObject; - } - MagnetizedObject<View> magnetizedView = new MagnetizedObject<View>( - mContext, - v, - DynamicAnimation.TRANSLATION_X, DynamicAnimation.TRANSLATION_Y - ) { - @Override - public float getWidth(@NonNull View underlyingObject) { - return underlyingObject.getWidth(); - } - - @Override - public float getHeight(@NonNull View underlyingObject) { - return underlyingObject.getHeight(); - } - - @Override - public void getLocationOnScreen(@NonNull View underlyingObject, - @NonNull int[] loc) { - loc[0] = (int) underlyingObject.getTranslationX(); - loc[1] = (int) underlyingObject.getTranslationY(); - } - }; - magnetizedView.setHapticsEnabled(true); - magnetizedView.setFlingToTargetMinVelocity(FLING_TO_DISMISS_MIN_VELOCITY); - magnetizedView.setStickToTargetMaxXVelocity(STICK_TO_TARGET_MAX_X_VELOCITY); - magnetizedView.setFlingToTargetWidthPercent(FLING_TO_TARGET_WIDTH_PERCENT); - return magnetizedView; - } - - /** Animates the dismiss treatment on the view being dismissed. */ - private void animateDismissing(boolean shouldDismiss) { - if (mViewBeingDismissed == null) { - return; - } - if (shouldDismiss) { - mDismissAnimator.removeAllListeners(); - mDismissAnimator.start(); - } else { - mDismissAnimator.removeAllListeners(); - mDismissAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - super.onAnimationEnd(animation); - resetDismissAnimator(); - } - }); - mDismissAnimator.reverse(); - } - } - - /** Actually dismisses the view. */ - private void doDismiss() { - mDismissView.hide(); - mController.removeTask(); - resetDismissAnimator(); - mViewBeingDismissed = null; - } - - private void resetDismissAnimator() { - mDismissAnimator.removeAllListeners(); - mDismissAnimator.cancel(); - if (mDismissView != null) { - mDismissView.cancelAnimators(); - mDismissView.getCircle().setScaleX(1f); - mDismissView.getCircle().setScaleY(1f); - } - } -} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/floating/FloatingTasks.java b/libs/WindowManager/Shell/src/com/android/wm/shell/floating/FloatingTasks.java deleted file mode 100644 index f86d467360f9..000000000000 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/floating/FloatingTasks.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.wm.shell.floating; - -import android.content.Intent; - -import com.android.wm.shell.common.annotations.ExternalThread; - -/** - * Interface to interact with floating tasks. - */ -@ExternalThread -public interface FloatingTasks { - - /** - * Shows, stashes, or un-stashes the floating task depending on state: - * - If there is no floating task for this intent, it shows the task for the provided intent. - * - If there is a floating task for this intent, but it's stashed, this un-stashes it. - * - If there is a floating task for this intent, and it's not stashed, this stashes it. - */ - void showOrSetStashed(Intent intent); -} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/floating/FloatingTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/floating/FloatingTasksController.java deleted file mode 100644 index b3c09d32055b..000000000000 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/floating/FloatingTasksController.java +++ /dev/null @@ -1,454 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.wm.shell.floating; - -import static android.app.ActivityTaskManager.INVALID_TASK_ID; -import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; - -import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission; -import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_FLOATING_APPS; -import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_FLOATING_TASKS; - -import android.annotation.Nullable; -import android.content.Context; -import android.content.Intent; -import android.content.pm.ShortcutInfo; -import android.content.res.Configuration; -import android.graphics.PixelFormat; -import android.graphics.Point; -import android.os.SystemProperties; -import android.view.ViewGroup; -import android.view.WindowManager; - -import androidx.annotation.BinderThread; -import androidx.annotation.VisibleForTesting; - -import com.android.internal.protolog.common.ProtoLog; -import com.android.wm.shell.ShellTaskOrganizer; -import com.android.wm.shell.TaskViewTransitions; -import com.android.wm.shell.bubbles.BubbleController; -import com.android.wm.shell.common.ExternalInterfaceBinder; -import com.android.wm.shell.common.RemoteCallable; -import com.android.wm.shell.common.ShellExecutor; -import com.android.wm.shell.common.SyncTransactionQueue; -import com.android.wm.shell.common.annotations.ExternalThread; -import com.android.wm.shell.common.annotations.ShellBackgroundThread; -import com.android.wm.shell.common.annotations.ShellMainThread; -import com.android.wm.shell.floating.views.FloatingTaskLayer; -import com.android.wm.shell.floating.views.FloatingTaskView; -import com.android.wm.shell.sysui.ConfigurationChangeListener; -import com.android.wm.shell.sysui.ShellCommandHandler; -import com.android.wm.shell.sysui.ShellController; -import com.android.wm.shell.sysui.ShellInit; - -import java.io.PrintWriter; -import java.util.Objects; -import java.util.Optional; - -/** - * Entry point for creating and managing floating tasks. - * - * A single window layer is added and the task(s) are displayed using a {@link FloatingTaskView} - * within that window. - * - * Currently optimized for a single task. Multiple tasks are not supported. - */ -public class FloatingTasksController implements RemoteCallable<FloatingTasksController>, - ConfigurationChangeListener { - - private static final String TAG = FloatingTasksController.class.getSimpleName(); - - public static final boolean FLOATING_TASKS_ENABLED = - SystemProperties.getBoolean("persist.wm.debug.floating_tasks", false); - public static final boolean SHOW_FLOATING_TASKS_AS_BUBBLES = - SystemProperties.getBoolean("persist.wm.debug.floating_tasks_as_bubbles", false); - - @VisibleForTesting - static final int SMALLEST_SCREEN_WIDTH_DP_TO_BE_TABLET = 600; - - // Only used for testing - private Configuration mConfig; - private boolean mFloatingTasksEnabledForTests; - - private FloatingTaskImpl mImpl = new FloatingTaskImpl(); - private Context mContext; - private ShellController mShellController; - private ShellCommandHandler mShellCommandHandler; - private @Nullable BubbleController mBubbleController; - private WindowManager mWindowManager; - private ShellTaskOrganizer mTaskOrganizer; - private TaskViewTransitions mTaskViewTransitions; - private @ShellMainThread ShellExecutor mMainExecutor; - // TODO: mBackgroundThread is not used but we'll probs need it eventually? - private @ShellBackgroundThread ShellExecutor mBackgroundThread; - private SyncTransactionQueue mSyncQueue; - - private boolean mIsFloatingLayerAdded; - private FloatingTaskLayer mFloatingTaskLayer; - private final Point mLastPosition = new Point(-1, -1); - - private Task mTask; - - // Simple class to hold onto info for intent or shortcut based tasks. - public static class Task { - public int taskId = INVALID_TASK_ID; - @Nullable - public Intent intent; - @Nullable - public ShortcutInfo info; - @Nullable - public FloatingTaskView floatingView; - } - - public FloatingTasksController(Context context, - ShellInit shellInit, - ShellController shellController, - ShellCommandHandler shellCommandHandler, - Optional<BubbleController> bubbleController, - WindowManager windowManager, - ShellTaskOrganizer organizer, - TaskViewTransitions transitions, - @ShellMainThread ShellExecutor mainExecutor, - @ShellBackgroundThread ShellExecutor bgExceutor, - SyncTransactionQueue syncTransactionQueue) { - mContext = context; - mShellController = shellController; - mShellCommandHandler = shellCommandHandler; - mBubbleController = bubbleController.get(); - mWindowManager = windowManager; - mTaskOrganizer = organizer; - mTaskViewTransitions = transitions; - mMainExecutor = mainExecutor; - mBackgroundThread = bgExceutor; - mSyncQueue = syncTransactionQueue; - if (isFloatingTasksEnabled()) { - shellInit.addInitCallback(this::onInit, this); - } - } - - protected void onInit() { - mShellController.addConfigurationChangeListener(this); - mShellController.addExternalInterface(KEY_EXTRA_SHELL_FLOATING_TASKS, - this::createExternalInterface, this); - mShellCommandHandler.addDumpCallback(this::dump, this); - } - - /** Only used for testing. */ - @VisibleForTesting - void setConfig(Configuration config) { - mConfig = config; - } - - /** Only used for testing. */ - @VisibleForTesting - void setFloatingTasksEnabled(boolean enabled) { - mFloatingTasksEnabledForTests = enabled; - } - - /** Whether the floating layer is available. */ - boolean isFloatingLayerAvailable() { - Configuration config = mConfig == null - ? mContext.getResources().getConfiguration() - : mConfig; - return config.smallestScreenWidthDp >= SMALLEST_SCREEN_WIDTH_DP_TO_BE_TABLET; - } - - /** Whether floating tasks are enabled. */ - boolean isFloatingTasksEnabled() { - return FLOATING_TASKS_ENABLED || mFloatingTasksEnabledForTests; - } - - private ExternalInterfaceBinder createExternalInterface() { - return new IFloatingTasksImpl(this); - } - - @Override - public void onThemeChanged() { - if (mIsFloatingLayerAdded) { - mFloatingTaskLayer.updateSizes(); - } - } - - @Override - public void onConfigurationChanged(Configuration newConfig) { - // TODO: probably other stuff here to do (e.g. handle rotation) - if (mIsFloatingLayerAdded) { - mFloatingTaskLayer.updateSizes(); - } - } - - /** Returns false if the task shouldn't be shown. */ - private boolean canShowTask(Intent intent) { - ProtoLog.d(WM_SHELL_FLOATING_APPS, "canShowTask -- %s", intent); - if (!isFloatingTasksEnabled() || !isFloatingLayerAvailable()) return false; - if (intent == null) { - ProtoLog.e(WM_SHELL_FLOATING_APPS, "canShowTask given null intent, doing nothing"); - return false; - } - return true; - } - - /** Returns true if the task was or should be shown as a bubble. */ - private boolean maybeShowTaskAsBubble(Intent intent) { - if (SHOW_FLOATING_TASKS_AS_BUBBLES && mBubbleController != null) { - removeFloatingLayer(); - if (intent.getPackage() != null) { - mBubbleController.addAppBubble(intent); - ProtoLog.d(WM_SHELL_FLOATING_APPS, "showing floating task as bubble: %s", intent); - } else { - ProtoLog.d(WM_SHELL_FLOATING_APPS, - "failed to show floating task as bubble: %s; unknown package", intent); - } - return true; - } - return false; - } - - /** - * Shows, stashes, or un-stashes the floating task depending on state: - * - If there is no floating task for this intent, it shows this the provided task. - * - If there is a floating task for this intent, but it's stashed, this un-stashes it. - * - If there is a floating task for this intent, and it's not stashed, this stashes it. - */ - public void showOrSetStashed(Intent intent) { - if (!canShowTask(intent)) return; - if (maybeShowTaskAsBubble(intent)) return; - - addFloatingLayer(); - - if (isTaskAttached(mTask) && intent.filterEquals(mTask.intent)) { - // The task is already added, toggle the stash state. - mFloatingTaskLayer.setStashed(mTask, !mTask.floatingView.isStashed()); - return; - } - - // If we're here it's either a new or different task - showNewTask(intent); - } - - /** - * Shows a floating task with the provided intent. - * If the same task is present it will un-stash it or do nothing if it is already un-stashed. - * Removes any other floating tasks that might exist. - */ - public void showTask(Intent intent) { - if (!canShowTask(intent)) return; - if (maybeShowTaskAsBubble(intent)) return; - - addFloatingLayer(); - - if (isTaskAttached(mTask) && intent.filterEquals(mTask.intent)) { - // The task is already added, show it if it's stashed. - if (mTask.floatingView.isStashed()) { - mFloatingTaskLayer.setStashed(mTask, false); - } - return; - } - showNewTask(intent); - } - - private void showNewTask(Intent intent) { - if (mTask != null && !intent.filterEquals(mTask.intent)) { - mFloatingTaskLayer.removeAllTaskViews(); - mTask.floatingView.cleanUpTaskView(); - mTask = null; - } - - FloatingTaskView ftv = new FloatingTaskView(mContext, this); - ftv.createTaskView(mContext, mTaskOrganizer, mTaskViewTransitions, mSyncQueue); - - mTask = new Task(); - mTask.floatingView = ftv; - mTask.intent = intent; - - // Add & start the task. - mFloatingTaskLayer.addTask(mTask); - ProtoLog.d(WM_SHELL_FLOATING_APPS, "showNewTask, startingIntent: %s", intent); - mTask.floatingView.startTask(mMainExecutor, mTask); - } - - /** - * Removes the task and cleans up the view. - */ - public void removeTask() { - if (mTask != null) { - ProtoLog.d(WM_SHELL_FLOATING_APPS, "Removing task with id=%d", mTask.taskId); - - if (mTask.floatingView != null) { - // TODO: animate it - mFloatingTaskLayer.removeView(mTask.floatingView); - mTask.floatingView.cleanUpTaskView(); - } - removeFloatingLayer(); - } - } - - /** - * Whether there is a floating task and if it is stashed. - */ - public boolean isStashed() { - return isTaskAttached(mTask) && mTask.floatingView.isStashed(); - } - - /** - * If a floating task exists, this sets whether it is stashed and animates if needed. - */ - public void setStashed(boolean shouldStash) { - if (mTask != null && mTask.floatingView != null && mIsFloatingLayerAdded) { - mFloatingTaskLayer.setStashed(mTask, shouldStash); - } - } - - /** - * Saves the last position the floating task was in so that it can be put there again. - */ - public void setLastPosition(int x, int y) { - mLastPosition.set(x, y); - } - - /** - * Returns the last position the floating task was in. - */ - public Point getLastPosition() { - return mLastPosition; - } - - /** - * Whether the provided task has a view that's attached to the floating layer. - */ - private boolean isTaskAttached(Task t) { - return t != null && t.floatingView != null - && mIsFloatingLayerAdded - && mFloatingTaskLayer.getTaskViewCount() > 0 - && Objects.equals(mFloatingTaskLayer.getFirstTaskView(), t.floatingView); - } - - // TODO: when this is added, if there are bubbles, they get hidden? Is only one layer of this - // type allowed? Bubbles & floating tasks should probably be in the same layer to reduce - // # of windows. - private void addFloatingLayer() { - if (mIsFloatingLayerAdded) { - return; - } - - mFloatingTaskLayer = new FloatingTaskLayer(mContext, this, mWindowManager); - - WindowManager.LayoutParams params = new WindowManager.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT, - WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY, - WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE - | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL - | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED, - PixelFormat.TRANSLUCENT - ); - params.setTrustedOverlay(); - params.setFitInsetsTypes(0); - params.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; - params.setTitle("FloatingTaskLayer"); - params.packageName = mContext.getPackageName(); - params.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; - params.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS; - - try { - mIsFloatingLayerAdded = true; - mWindowManager.addView(mFloatingTaskLayer, params); - } catch (IllegalStateException e) { - // This means the floating layer has already been added which shouldn't happen. - e.printStackTrace(); - } - } - - private void removeFloatingLayer() { - if (!mIsFloatingLayerAdded) { - return; - } - try { - mIsFloatingLayerAdded = false; - if (mFloatingTaskLayer != null) { - mWindowManager.removeView(mFloatingTaskLayer); - } - } catch (IllegalArgumentException e) { - // This means the floating layer has already been removed which shouldn't happen. - e.printStackTrace(); - } - } - - /** - * Description of current floating task state. - */ - private void dump(PrintWriter pw, String prefix) { - pw.println("FloatingTaskController state:"); - pw.print(" isFloatingLayerAvailable= "); pw.println(isFloatingLayerAvailable()); - pw.print(" isFloatingTasksEnabled= "); pw.println(isFloatingTasksEnabled()); - pw.print(" mIsFloatingLayerAdded= "); pw.println(mIsFloatingLayerAdded); - pw.print(" mLastPosition= "); pw.println(mLastPosition); - pw.println(); - } - - /** Returns the {@link FloatingTasks} implementation. */ - public FloatingTasks asFloatingTasks() { - return mImpl; - } - - @Override - public Context getContext() { - return mContext; - } - - @Override - public ShellExecutor getRemoteCallExecutor() { - return mMainExecutor; - } - - /** - * The interface for calls from outside the shell, within the host process. - */ - @ExternalThread - private class FloatingTaskImpl implements FloatingTasks { - @Override - public void showOrSetStashed(Intent intent) { - mMainExecutor.execute(() -> FloatingTasksController.this.showOrSetStashed(intent)); - } - } - - /** - * The interface for calls from outside the host process. - */ - @BinderThread - private static class IFloatingTasksImpl extends IFloatingTasks.Stub - implements ExternalInterfaceBinder { - private FloatingTasksController mController; - - IFloatingTasksImpl(FloatingTasksController controller) { - mController = controller; - } - - /** - * Invalidates this instance, preventing future calls from updating the controller. - */ - @Override - public void invalidate() { - mController = null; - } - - public void showTask(Intent intent) { - executeRemoteCallWithTaskPermission(mController, "showTask", - (controller) -> controller.showTask(intent)); - } - } -} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/floating/views/FloatingMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/floating/views/FloatingMenuView.java deleted file mode 100644 index c922109751ba..000000000000 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/floating/views/FloatingMenuView.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.wm.shell.floating.views; - -import android.annotation.Nullable; -import android.content.Context; -import android.graphics.drawable.Drawable; -import android.view.Gravity; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.LinearLayout; - -import com.android.wm.shell.R; - -/** - * Displays the menu items for a floating task view (e.g. close). - */ -public class FloatingMenuView extends LinearLayout { - - private int mItemSize; - private int mItemMargin; - - public FloatingMenuView(Context context) { - super(context); - setOrientation(LinearLayout.HORIZONTAL); - setGravity(Gravity.CENTER); - - mItemSize = context.getResources().getDimensionPixelSize( - R.dimen.floating_task_menu_item_size); - mItemMargin = context.getResources().getDimensionPixelSize( - R.dimen.floating_task_menu_item_padding); - } - - /** Adds a clickable item to the menu bar. Items are ordered as added. */ - public void addMenuItem(@Nullable Drawable drawable, View.OnClickListener listener) { - ImageView itemView = new ImageView(getContext()); - itemView.setScaleType(ImageView.ScaleType.CENTER); - if (drawable != null) { - itemView.setImageDrawable(drawable); - } - LinearLayout.LayoutParams lp = new LayoutParams(mItemSize, - ViewGroup.LayoutParams.MATCH_PARENT); - lp.setMarginStart(mItemMargin); - lp.setMarginEnd(mItemMargin); - addView(itemView, lp); - - itemView.setOnClickListener(listener); - } - - /** - * The menu extends past the top of the TaskView because of the rounded corners. This means - * to center content in the menu we must subtract the radius (i.e. the amount of space covered - * by TaskView). - */ - public void setCornerRadius(float radius) { - setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), (int) radius); - } -} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/floating/views/FloatingTaskLayer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/floating/views/FloatingTaskLayer.java deleted file mode 100644 index 16dab2415bf2..000000000000 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/floating/views/FloatingTaskLayer.java +++ /dev/null @@ -1,687 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.wm.shell.floating.views; - -import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_FLOATING_APPS; - -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.annotation.Nullable; -import android.content.Context; -import android.graphics.Color; -import android.graphics.Insets; -import android.graphics.Point; -import android.graphics.Rect; -import android.graphics.Region; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewPropertyAnimator; -import android.view.ViewTreeObserver; -import android.view.WindowInsets; -import android.view.WindowManager; -import android.view.WindowMetrics; -import android.widget.FrameLayout; - -import androidx.annotation.NonNull; -import androidx.dynamicanimation.animation.DynamicAnimation; -import androidx.dynamicanimation.animation.FlingAnimation; - -import com.android.internal.protolog.common.ProtoLog; -import com.android.wm.shell.R; -import com.android.wm.shell.floating.FloatingDismissController; -import com.android.wm.shell.floating.FloatingTasksController; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * This is the layout that {@link FloatingTaskView}s are contained in. It handles input and - * movement of the task views. - */ -public class FloatingTaskLayer extends FrameLayout - implements ViewTreeObserver.OnComputeInternalInsetsListener { - - private static final String TAG = FloatingTaskLayer.class.getSimpleName(); - - /** How big to make the task view based on screen width of the largest size. */ - private static final float START_SIZE_WIDTH_PERCENT = 0.33f; - /** Min fling velocity required to move the view from one side of the screen to the other. */ - private static final float ESCAPE_VELOCITY = 750f; - /** Amount of friction to apply to fling animations. */ - private static final float FLING_FRICTION = 1.9f; - - private final FloatingTasksController mController; - private final FloatingDismissController mDismissController; - private final WindowManager mWindowManager; - private final TouchHandlerImpl mTouchHandler; - - private final Region mTouchableRegion = new Region(); - private final Rect mPositionRect = new Rect(); - private final Point mDefaultStartPosition = new Point(); - private final Point mTaskViewSize = new Point(); - private WindowInsets mWindowInsets; - private int mVerticalPadding; - private int mOverhangWhenStashed; - - private final List<Rect> mSystemGestureExclusionRects = Collections.singletonList(new Rect()); - private ViewTreeObserver.OnDrawListener mSystemGestureExclusionListener = - this::updateSystemGestureExclusion; - - /** Interface allowing something to handle the touch events going to a task. */ - interface FloatingTaskTouchHandler { - void onDown(@NonNull FloatingTaskView v, @NonNull MotionEvent ev, - float viewInitialX, float viewInitialY); - - void onMove(@NonNull FloatingTaskView v, @NonNull MotionEvent ev, - float dx, float dy); - - void onUp(@NonNull FloatingTaskView v, @NonNull MotionEvent ev, - float dx, float dy, float velX, float velY); - - void onClick(@NonNull FloatingTaskView v); - } - - public FloatingTaskLayer(Context context, - FloatingTasksController controller, - WindowManager windowManager) { - super(context); - // TODO: Why is this necessary? Without it FloatingTaskView does not render correctly. - setBackgroundColor(Color.argb(0, 0, 0, 0)); - - mController = controller; - mWindowManager = windowManager; - updateSizes(); - - // TODO: Might make sense to put dismiss controller in the touch handler since that's the - // main user of dismiss controller. - mDismissController = new FloatingDismissController(context, mController, this); - mTouchHandler = new TouchHandlerImpl(); - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - getViewTreeObserver().addOnComputeInternalInsetsListener(this); - getViewTreeObserver().addOnDrawListener(mSystemGestureExclusionListener); - setOnApplyWindowInsetsListener((view, windowInsets) -> { - if (!windowInsets.equals(mWindowInsets)) { - mWindowInsets = windowInsets; - updateSizes(); - } - return windowInsets; - }); - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - getViewTreeObserver().removeOnComputeInternalInsetsListener(this); - getViewTreeObserver().removeOnDrawListener(mSystemGestureExclusionListener); - } - - @Override - public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo inoutInfo) { - inoutInfo.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION); - mTouchableRegion.setEmpty(); - getTouchableRegion(mTouchableRegion); - inoutInfo.touchableRegion.set(mTouchableRegion); - } - - /** Adds a floating task to the layout. */ - public void addTask(FloatingTasksController.Task task) { - if (task.floatingView == null) return; - - task.floatingView.setTouchHandler(mTouchHandler); - addView(task.floatingView, new LayoutParams(mTaskViewSize.x, mTaskViewSize.y)); - updateTaskViewPosition(task.floatingView); - } - - /** Animates the stashed state of the provided task, if it's part of the floating layer. */ - public void setStashed(FloatingTasksController.Task task, boolean shouldStash) { - if (task.floatingView != null && task.floatingView.getParent() == this) { - mTouchHandler.stashTaskView(task.floatingView, shouldStash); - } - } - - /** Removes all {@link FloatingTaskView} from the layout. */ - public void removeAllTaskViews() { - int childCount = getChildCount(); - ArrayList<View> viewsToRemove = new ArrayList<>(); - for (int i = 0; i < childCount; i++) { - if (getChildAt(i) instanceof FloatingTaskView) { - viewsToRemove.add(getChildAt(i)); - } - } - for (View v : viewsToRemove) { - removeView(v); - } - } - - /** Returns the number of task views in the layout. */ - public int getTaskViewCount() { - int taskViewCount = 0; - int childCount = getChildCount(); - for (int i = 0; i < childCount; i++) { - if (getChildAt(i) instanceof FloatingTaskView) { - taskViewCount++; - } - } - return taskViewCount; - } - - /** - * Called when the task view is un-stuck from the dismiss target. - * @param v the task view being moved. - * @param velX the x velocity of the motion event. - * @param velY the y velocity of the motion event. - * @param wasFlungOut true if the user flung the task view out of the dismiss target (i.e. there - * was an 'up' event), otherwise the user is still dragging. - */ - public void onUnstuckFromTarget(FloatingTaskView v, float velX, float velY, - boolean wasFlungOut) { - mTouchHandler.onUnstuckFromTarget(v, velX, velY, wasFlungOut); - } - - /** - * Updates dimensions and applies them to any task views. - */ - public void updateSizes() { - if (mDismissController != null) { - mDismissController.updateSizes(); - } - - mOverhangWhenStashed = getResources().getDimensionPixelSize( - R.dimen.floating_task_stash_offset); - mVerticalPadding = getResources().getDimensionPixelSize( - R.dimen.floating_task_vertical_padding); - - WindowMetrics windowMetrics = mWindowManager.getCurrentWindowMetrics(); - WindowInsets windowInsets = windowMetrics.getWindowInsets(); - Insets insets = windowInsets.getInsetsIgnoringVisibility(WindowInsets.Type.navigationBars() - | WindowInsets.Type.statusBars() - | WindowInsets.Type.displayCutout()); - Rect bounds = windowMetrics.getBounds(); - mPositionRect.set(bounds.left + insets.left, - bounds.top + insets.top + mVerticalPadding, - bounds.right - insets.right, - bounds.bottom - insets.bottom - mVerticalPadding); - - int taskViewWidth = Math.max(bounds.height(), bounds.width()); - int taskViewHeight = Math.min(bounds.height(), bounds.width()); - taskViewHeight = taskViewHeight - (insets.top + insets.bottom + (mVerticalPadding * 2)); - mTaskViewSize.set((int) (taskViewWidth * START_SIZE_WIDTH_PERCENT), taskViewHeight); - mDefaultStartPosition.set(mPositionRect.left, mPositionRect.top); - - // Update existing views - int childCount = getChildCount(); - for (int i = 0; i < childCount; i++) { - if (getChildAt(i) instanceof FloatingTaskView) { - FloatingTaskView child = (FloatingTaskView) getChildAt(i); - LayoutParams lp = (LayoutParams) child.getLayoutParams(); - lp.width = mTaskViewSize.x; - lp.height = mTaskViewSize.y; - child.setLayoutParams(lp); - updateTaskViewPosition(child); - } - } - } - - /** Returns the first floating task view in the layout. (Currently only ever 1 view). */ - @Nullable - public FloatingTaskView getFirstTaskView() { - int childCount = getChildCount(); - for (int i = 0; i < childCount; i++) { - View child = getChildAt(i); - if (child instanceof FloatingTaskView) { - return (FloatingTaskView) child; - } - } - return null; - } - - private void updateTaskViewPosition(FloatingTaskView floatingView) { - Point lastPosition = mController.getLastPosition(); - if (lastPosition.x == -1 && lastPosition.y == -1) { - floatingView.setX(mDefaultStartPosition.x); - floatingView.setY(mDefaultStartPosition.y); - } else { - floatingView.setX(lastPosition.x); - floatingView.setY(lastPosition.y); - } - if (mTouchHandler.isStashedPosition(floatingView)) { - floatingView.setStashed(true); - } - floatingView.updateLocation(); - } - - /** - * Updates the area of the screen that shouldn't allow the back gesture due to the placement - * of task view (i.e. when task view is stashed on an edge, tapping or swiping that edge would - * un-stash the task view instead of performing the back gesture). - */ - private void updateSystemGestureExclusion() { - Rect excludeZone = mSystemGestureExclusionRects.get(0); - FloatingTaskView floatingTaskView = getFirstTaskView(); - if (floatingTaskView != null && floatingTaskView.isStashed()) { - excludeZone.set(floatingTaskView.getLeft(), - floatingTaskView.getTop(), - floatingTaskView.getRight(), - floatingTaskView.getBottom()); - excludeZone.offset((int) (floatingTaskView.getTranslationX()), - (int) (floatingTaskView.getTranslationY())); - setSystemGestureExclusionRects(mSystemGestureExclusionRects); - } else { - excludeZone.setEmpty(); - setSystemGestureExclusionRects(Collections.emptyList()); - } - } - - /** - * Fills in the touchable region for floating windows. This is used by WindowManager to - * decide which touch events go to the floating windows. - */ - private void getTouchableRegion(Region outRegion) { - int childCount = getChildCount(); - Rect temp = new Rect(); - for (int i = 0; i < childCount; i++) { - View child = getChildAt(i); - if (child instanceof FloatingTaskView) { - child.getBoundsOnScreen(temp); - outRegion.op(temp, Region.Op.UNION); - } - } - } - - /** - * Implementation of the touch handler. Animates the task view based on touch events. - */ - private class TouchHandlerImpl implements FloatingTaskTouchHandler { - /** - * The view can be stashed by swiping it towards the current edge or moving it there. If - * the view gets moved in a way that is not one of these gestures, this is flipped to false. - */ - private boolean mCanStash = true; - /** - * This is used to indicate that the view has been un-stuck from the dismiss target and - * needs to spring to the current touch location. - */ - // TODO: implement this behavior - private boolean mSpringToTouchOnNextMotionEvent = false; - - private ArrayList<FlingAnimation> mFlingAnimations; - private ViewPropertyAnimator mViewPropertyAnimation; - - private float mViewInitialX; - private float mViewInitialY; - - private float[] mMinMax = new float[2]; - - @Override - public void onDown(@NonNull FloatingTaskView v, @NonNull MotionEvent ev, float viewInitialX, - float viewInitialY) { - mCanStash = true; - mViewInitialX = viewInitialX; - mViewInitialY = viewInitialY; - mDismissController.setUpMagneticObject(v); - mDismissController.passEventToMagnetizedObject(ev); - } - - @Override - public void onMove(@NonNull FloatingTaskView v, @NonNull MotionEvent ev, - float dx, float dy) { - // Shows the magnetic dismiss target if needed. - mDismissController.showDismiss(/* show= */ true); - - // Send it to magnetic target first. - if (mDismissController.passEventToMagnetizedObject(ev)) { - v.setStashed(false); - mCanStash = true; - - return; - } - - // If we're here magnetic target didn't want it so move as per normal. - - v.setTranslationX(capX(v, mViewInitialX + dx, /* isMoving= */ true)); - v.setTranslationY(capY(v, mViewInitialY + dy)); - if (v.isStashed()) { - // Check if we've moved far enough to be not stashed. - final float centerX = mPositionRect.centerX() - (v.getWidth() / 2f); - final boolean viewInitiallyOnLeftSide = mViewInitialX < centerX; - if (viewInitiallyOnLeftSide) { - if (v.getTranslationX() > mPositionRect.left) { - v.setStashed(false); - mCanStash = true; - } - } else if (v.getTranslationX() + v.getWidth() < mPositionRect.right) { - v.setStashed(false); - mCanStash = true; - } - } - } - - // Reference for math / values: StackAnimationController#flingStackThenSpringToEdge. - // TODO clean up the code here, pretty hard to comprehend - // TODO code here doesn't work the best when in portrait (e.g. can't fling up/down on edges) - @Override - public void onUp(@NonNull FloatingTaskView v, @NonNull MotionEvent ev, - float dx, float dy, float velX, float velY) { - - // Send it to magnetic target first. - if (mDismissController.passEventToMagnetizedObject(ev)) { - v.setStashed(false); - return; - } - mDismissController.showDismiss(/* show= */ false); - - // If we're here magnetic target didn't want it so handle up as per normal. - - final float x = capX(v, mViewInitialX + dx, /* isMoving= */ false); - final float centerX = mPositionRect.centerX(); - final boolean viewInitiallyOnLeftSide = mViewInitialX + v.getWidth() < centerX; - final boolean viewOnLeftSide = x + v.getWidth() < centerX; - final boolean isFling = Math.abs(velX) > ESCAPE_VELOCITY; - final boolean isFlingLeft = isFling && velX < ESCAPE_VELOCITY; - // TODO: check velX here sometimes it doesn't stash on move when I think it should - final boolean shouldStashFromMove = - (velX < 0 && v.getTranslationX() < mPositionRect.left) - || (velX > 0 - && v.getTranslationX() + v.getWidth() > mPositionRect.right); - final boolean shouldStashFromFling = viewInitiallyOnLeftSide == viewOnLeftSide - && isFling - && ((viewOnLeftSide && velX < ESCAPE_VELOCITY) - || (!viewOnLeftSide && velX > ESCAPE_VELOCITY)); - final boolean shouldStash = mCanStash && (shouldStashFromFling || shouldStashFromMove); - - ProtoLog.d(WM_SHELL_FLOATING_APPS, - "shouldStash=%s shouldStashFromFling=%s shouldStashFromMove=%s" - + " viewInitiallyOnLeftSide=%s viewOnLeftSide=%s isFling=%s velX=%f" - + " isStashed=%s", shouldStash, shouldStashFromFling, shouldStashFromMove, - viewInitiallyOnLeftSide, viewOnLeftSide, isFling, velX, v.isStashed()); - - if (v.isStashed()) { - mMinMax[0] = viewOnLeftSide - ? mPositionRect.left - v.getWidth() + mOverhangWhenStashed - : mPositionRect.right - v.getWidth(); - mMinMax[1] = viewOnLeftSide - ? mPositionRect.left - : mPositionRect.right - mOverhangWhenStashed; - } else { - populateMinMax(v, viewOnLeftSide, shouldStash, mMinMax); - } - - boolean movingLeft = isFling ? isFlingLeft : viewOnLeftSide; - float destinationRelativeX = movingLeft - ? mMinMax[0] - : mMinMax[1]; - - // TODO: why is this necessary / when does this happen? - if (mMinMax[1] < v.getTranslationX()) { - mMinMax[1] = v.getTranslationX(); - } - if (v.getTranslationX() < mMinMax[0]) { - mMinMax[0] = v.getTranslationX(); - } - - // Use the touch event's velocity if it's sufficient, otherwise use the minimum velocity - // so that it'll make it all the way to the side of the screen. - final float minimumVelocityToReachEdge = - getMinimumVelocityToReachEdge(v, destinationRelativeX); - final float startXVelocity = movingLeft - ? Math.min(minimumVelocityToReachEdge, velX) - : Math.max(minimumVelocityToReachEdge, velX); - - cancelAnyAnimations(v); - - mFlingAnimations = getAnimationForUpEvent(v, shouldStash, - startXVelocity, mMinMax[0], mMinMax[1], destinationRelativeX); - for (int i = 0; i < mFlingAnimations.size(); i++) { - mFlingAnimations.get(i).start(); - } - } - - @Override - public void onClick(@NonNull FloatingTaskView v) { - if (v.isStashed()) { - final float centerX = mPositionRect.centerX() - (v.getWidth() / 2f); - final boolean viewOnLeftSide = v.getTranslationX() < centerX; - final float destinationRelativeX = viewOnLeftSide - ? mPositionRect.left - : mPositionRect.right - v.getWidth(); - final float minimumVelocityToReachEdge = - getMinimumVelocityToReachEdge(v, destinationRelativeX); - populateMinMax(v, viewOnLeftSide, /* stashed= */ true, mMinMax); - - cancelAnyAnimations(v); - - FlingAnimation flingAnimation = new FlingAnimation(v, - DynamicAnimation.TRANSLATION_X); - flingAnimation.setFriction(FLING_FRICTION) - .setStartVelocity(minimumVelocityToReachEdge) - .setMinValue(mMinMax[0]) - .setMaxValue(mMinMax[1]) - .addEndListener((animation, canceled, value, velocity) -> { - if (canceled) return; - mController.setLastPosition((int) v.getTranslationX(), - (int) v.getTranslationY()); - v.setStashed(false); - v.updateLocation(); - }); - mFlingAnimations = new ArrayList<>(); - mFlingAnimations.add(flingAnimation); - flingAnimation.start(); - } - } - - public void onUnstuckFromTarget(FloatingTaskView v, float velX, float velY, - boolean wasFlungOut) { - if (wasFlungOut) { - snapTaskViewToEdge(v, velX, /* shouldStash= */ false); - } else { - // TODO: use this for something / to spring the view to the touch location - mSpringToTouchOnNextMotionEvent = true; - } - } - - public void stashTaskView(FloatingTaskView v, boolean shouldStash) { - if (v.isStashed() == shouldStash) { - return; - } - final float centerX = mPositionRect.centerX() - (v.getWidth() / 2f); - final boolean viewOnLeftSide = v.getTranslationX() < centerX; - snapTaskViewToEdge(v, viewOnLeftSide ? -ESCAPE_VELOCITY : ESCAPE_VELOCITY, shouldStash); - } - - public boolean isStashedPosition(View v) { - return v.getTranslationX() < mPositionRect.left - || v.getTranslationX() + v.getWidth() > mPositionRect.right; - } - - // TODO: a lot of this is duplicated in onUp -- can it be unified? - private void snapTaskViewToEdge(FloatingTaskView v, float velX, boolean shouldStash) { - final boolean movingLeft = velX < ESCAPE_VELOCITY; - populateMinMax(v, movingLeft, shouldStash, mMinMax); - float destinationRelativeX = movingLeft - ? mMinMax[0] - : mMinMax[1]; - - // TODO: why is this necessary / when does this happen? - if (mMinMax[1] < v.getTranslationX()) { - mMinMax[1] = v.getTranslationX(); - } - if (v.getTranslationX() < mMinMax[0]) { - mMinMax[0] = v.getTranslationX(); - } - - // Use the touch event's velocity if it's sufficient, otherwise use the minimum velocity - // so that it'll make it all the way to the side of the screen. - final float minimumVelocityToReachEdge = - getMinimumVelocityToReachEdge(v, destinationRelativeX); - final float startXVelocity = movingLeft - ? Math.min(minimumVelocityToReachEdge, velX) - : Math.max(minimumVelocityToReachEdge, velX); - - cancelAnyAnimations(v); - - mFlingAnimations = getAnimationForUpEvent(v, - shouldStash, startXVelocity, mMinMax[0], mMinMax[1], - destinationRelativeX); - for (int i = 0; i < mFlingAnimations.size(); i++) { - mFlingAnimations.get(i).start(); - } - } - - private void cancelAnyAnimations(FloatingTaskView v) { - if (mFlingAnimations != null) { - for (int i = 0; i < mFlingAnimations.size(); i++) { - if (mFlingAnimations.get(i).isRunning()) { - mFlingAnimations.get(i).cancel(); - } - } - } - if (mViewPropertyAnimation != null) { - mViewPropertyAnimation.cancel(); - mViewPropertyAnimation = null; - } - } - - private ArrayList<FlingAnimation> getAnimationForUpEvent(FloatingTaskView v, - boolean shouldStash, float startVelX, float minValue, float maxValue, - float destinationRelativeX) { - final float ty = v.getTranslationY(); - final ArrayList<FlingAnimation> animations = new ArrayList<>(); - if (ty != capY(v, ty)) { - // The view was being dismissed so the Y is out of bounds, need to animate that. - FlingAnimation yFlingAnimation = new FlingAnimation(v, - DynamicAnimation.TRANSLATION_Y); - yFlingAnimation.setFriction(FLING_FRICTION) - .setStartVelocity(startVelX) - .setMinValue(mPositionRect.top) - .setMaxValue(mPositionRect.bottom - mTaskViewSize.y); - animations.add(yFlingAnimation); - } - FlingAnimation flingAnimation = new FlingAnimation(v, DynamicAnimation.TRANSLATION_X); - flingAnimation.setFriction(FLING_FRICTION) - .setStartVelocity(startVelX) - .setMinValue(minValue) - .setMaxValue(maxValue) - .addEndListener((animation, canceled, value, velocity) -> { - if (canceled) return; - Runnable endAction = () -> { - v.setStashed(shouldStash); - v.updateLocation(); - if (!v.isStashed()) { - mController.setLastPosition((int) v.getTranslationX(), - (int) v.getTranslationY()); - } - }; - if (!shouldStash) { - final int xTranslation = (int) v.getTranslationX(); - if (xTranslation != destinationRelativeX) { - // TODO: this animation doesn't feel great, should figure out - // a better way to do this or remove the need for it all together. - mViewPropertyAnimation = v.animate() - .translationX(destinationRelativeX) - .setListener(getAnimationListener(endAction)); - mViewPropertyAnimation.start(); - } else { - endAction.run(); - } - } else { - endAction.run(); - } - }); - animations.add(flingAnimation); - return animations; - } - - private AnimatorListenerAdapter getAnimationListener(Runnable endAction) { - return new AnimatorListenerAdapter() { - boolean translationCanceled = false; - @Override - public void onAnimationCancel(Animator animation) { - super.onAnimationCancel(animation); - translationCanceled = true; - } - - @Override - public void onAnimationEnd(Animator animation) { - super.onAnimationEnd(animation); - if (!translationCanceled) { - endAction.run(); - } - } - }; - } - - private void populateMinMax(FloatingTaskView v, boolean onLeft, boolean shouldStash, - float[] out) { - if (shouldStash) { - out[0] = onLeft - ? mPositionRect.left - v.getWidth() + mOverhangWhenStashed - : mPositionRect.right - v.getWidth(); - out[1] = onLeft - ? mPositionRect.left - : mPositionRect.right - mOverhangWhenStashed; - } else { - out[0] = mPositionRect.left; - out[1] = mPositionRect.right - mTaskViewSize.x; - } - } - - private float getMinimumVelocityToReachEdge(FloatingTaskView v, - float destinationRelativeX) { - // Minimum velocity required for the view to make it to the targeted side of the screen, - // taking friction into account (4.2f is the number that friction scalars are multiplied - // by in DynamicAnimation.DragForce). This is an estimate and could be slightly off, the - // animation at the end will ensure that it reaches the destination X regardless. - return (destinationRelativeX - v.getTranslationX()) * (FLING_FRICTION * 4.2f); - } - - private float capX(FloatingTaskView v, float x, boolean isMoving) { - final int width = v.getWidth(); - if (v.isStashed() || isMoving) { - if (x < mPositionRect.left - v.getWidth() + mOverhangWhenStashed) { - return mPositionRect.left - v.getWidth() + mOverhangWhenStashed; - } - if (x > mPositionRect.right - mOverhangWhenStashed) { - return mPositionRect.right - mOverhangWhenStashed; - } - } else { - if (x < mPositionRect.left) { - return mPositionRect.left; - } - if (x > mPositionRect.right - width) { - return mPositionRect.right - width; - } - } - return x; - } - - private float capY(FloatingTaskView v, float y) { - final int height = v.getHeight(); - if (y < mPositionRect.top) { - return mPositionRect.top; - } - if (y > mPositionRect.bottom - height) { - return mPositionRect.bottom - height; - } - return y; - } - } -} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/floating/views/FloatingTaskView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/floating/views/FloatingTaskView.java deleted file mode 100644 index 581204a82ec7..000000000000 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/floating/views/FloatingTaskView.java +++ /dev/null @@ -1,385 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.wm.shell.floating.views; - -import static android.app.ActivityTaskManager.INVALID_TASK_ID; -import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK; -import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT; - -import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_FLOATING_APPS; - -import android.app.ActivityManager; -import android.app.ActivityOptions; -import android.app.ActivityTaskManager; -import android.app.PendingIntent; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.res.TypedArray; -import android.graphics.Color; -import android.graphics.Outline; -import android.graphics.Rect; -import android.os.RemoteException; -import android.util.Log; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewOutlineProvider; -import android.widget.FrameLayout; - -import androidx.annotation.NonNull; - -import com.android.internal.policy.ScreenDecorationsUtils; -import com.android.internal.protolog.common.ProtoLog; -import com.android.wm.shell.R; -import com.android.wm.shell.ShellTaskOrganizer; -import com.android.wm.shell.TaskView; -import com.android.wm.shell.TaskViewTransitions; -import com.android.wm.shell.bubbles.RelativeTouchListener; -import com.android.wm.shell.common.ShellExecutor; -import com.android.wm.shell.common.SyncTransactionQueue; -import com.android.wm.shell.common.annotations.ShellMainThread; -import com.android.wm.shell.floating.FloatingTasksController; - -/** - * A view that holds a floating task using {@link TaskView} along with additional UI to manage - * the task. - */ -public class FloatingTaskView extends FrameLayout { - - private static final String TAG = FloatingTaskView.class.getSimpleName(); - - private FloatingTasksController mController; - - private FloatingMenuView mMenuView; - private int mMenuHeight; - private TaskView mTaskView; - - private float mCornerRadius = 0f; - private int mBackgroundColor; - - private FloatingTasksController.Task mTask; - - private boolean mIsStashed; - - /** - * Creates a floating task view. - * - * @param context the context to use. - * @param controller the controller to notify about changes in the floating task (e.g. removal). - */ - public FloatingTaskView(Context context, FloatingTasksController controller) { - super(context); - mController = controller; - setElevation(getResources().getDimensionPixelSize(R.dimen.floating_task_elevation)); - mMenuHeight = context.getResources().getDimensionPixelSize(R.dimen.floating_task_menu_size); - mMenuView = new FloatingMenuView(context); - addView(mMenuView); - - applyThemeAttrs(); - - setClipToOutline(true); - setOutlineProvider(new ViewOutlineProvider() { - @Override - public void getOutline(View view, Outline outline) { - outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), mCornerRadius); - } - }); - } - - // TODO: call this when theme/config changes - void applyThemeAttrs() { - boolean supportsRoundedCorners = ScreenDecorationsUtils.supportsRoundedCornersOnWindows( - mContext.getResources()); - final TypedArray ta = mContext.obtainStyledAttributes(new int[] { - android.R.attr.dialogCornerRadius, - android.R.attr.colorBackgroundFloating}); - mCornerRadius = supportsRoundedCorners ? ta.getDimensionPixelSize(0, 0) : 0; - mCornerRadius = mCornerRadius / 2f; - mBackgroundColor = ta.getColor(1, Color.WHITE); - - ta.recycle(); - - mMenuView.setCornerRadius(mCornerRadius); - mMenuHeight = getResources().getDimensionPixelSize( - R.dimen.floating_task_menu_size); - - if (mTaskView != null) { - mTaskView.setCornerRadius(mCornerRadius); - } - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - int height = MeasureSpec.getSize(heightMeasureSpec); - - // Add corner radius here so that the menu extends behind the rounded corners of TaskView. - int menuViewHeight = Math.min((int) (mMenuHeight + mCornerRadius), height); - measureChild(mMenuView, widthMeasureSpec, MeasureSpec.makeMeasureSpec(menuViewHeight, - MeasureSpec.getMode(heightMeasureSpec))); - - if (mTaskView != null) { - int taskViewHeight = height - menuViewHeight; - measureChild(mTaskView, widthMeasureSpec, MeasureSpec.makeMeasureSpec(taskViewHeight, - MeasureSpec.getMode(heightMeasureSpec))); - } - } - - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - // Drag handle above - final int dragHandleBottom = t + mMenuView.getMeasuredHeight(); - mMenuView.layout(l, t, r, dragHandleBottom); - if (mTaskView != null) { - // Subtract radius so that the menu extends behind the rounded corners of TaskView. - mTaskView.layout(l, (int) (dragHandleBottom - mCornerRadius), r, - dragHandleBottom + mTaskView.getMeasuredHeight()); - } - } - - /** - * Constructs the TaskView to display the task. Must be called for {@link #startTask} to work. - */ - public void createTaskView(Context context, ShellTaskOrganizer organizer, - TaskViewTransitions transitions, SyncTransactionQueue syncQueue) { - mTaskView = new TaskView(context, organizer, transitions, syncQueue); - addView(mTaskView); - mTaskView.setEnableSurfaceClipping(true); - mTaskView.setCornerRadius(mCornerRadius); - } - - /** - * Starts the provided task in the TaskView, if the TaskView exists. This should be called after - * {@link #createTaskView}. - */ - public void startTask(@ShellMainThread ShellExecutor executor, - FloatingTasksController.Task task) { - if (mTaskView == null) { - Log.e(TAG, "starting task before creating the view!"); - return; - } - mTask = task; - mTaskView.setListener(executor, mTaskViewListener); - } - - /** - * Sets the touch handler for the view. - * - * @param handler the touch handler for the view. - */ - public void setTouchHandler(FloatingTaskLayer.FloatingTaskTouchHandler handler) { - setOnTouchListener(new RelativeTouchListener() { - @Override - public boolean onDown(@NonNull View v, @NonNull MotionEvent ev) { - handler.onDown(FloatingTaskView.this, ev, v.getTranslationX(), v.getTranslationY()); - return true; - } - - @Override - public void onMove(@NonNull View v, @NonNull MotionEvent ev, float viewInitialX, - float viewInitialY, float dx, float dy) { - handler.onMove(FloatingTaskView.this, ev, dx, dy); - } - - @Override - public void onUp(@NonNull View v, @NonNull MotionEvent ev, float viewInitialX, - float viewInitialY, float dx, float dy, float velX, float velY) { - handler.onUp(FloatingTaskView.this, ev, dx, dy, velX, velY); - } - }); - setOnClickListener(view -> { - handler.onClick(FloatingTaskView.this); - }); - - mMenuView.addMenuItem(null, view -> { - if (mIsStashed) { - // If we're stashed all clicks un-stash. - handler.onClick(FloatingTaskView.this); - } - }); - } - - private void setContentVisibility(boolean visible) { - if (mTaskView == null) return; - mTaskView.setAlpha(visible ? 1f : 0f); - } - - /** - * Sets the alpha of both this view and the TaskView. - */ - public void setTaskViewAlpha(float alpha) { - if (mTaskView != null) { - mTaskView.setAlpha(alpha); - } - setAlpha(alpha); - } - - /** - * Call when the location or size of the view has changed to update TaskView. - */ - public void updateLocation() { - if (mTaskView == null) return; - mTaskView.onLocationChanged(); - } - - private void updateMenuColor() { - ActivityManager.RunningTaskInfo info = mTaskView.getTaskInfo(); - int color = info != null ? info.taskDescription.getBackgroundColor() : -1; - if (color != -1) { - mMenuView.setBackgroundColor(color); - } else { - mMenuView.setBackgroundColor(mBackgroundColor); - } - } - - /** - * Sets whether the view is stashed or not. - * - * Also updates the touchable area based on this. If the view is stashed we don't direct taps - * on the activity to the activity, instead a tap will un-stash the view. - */ - public void setStashed(boolean isStashed) { - if (mIsStashed != isStashed) { - mIsStashed = isStashed; - if (mTaskView == null) { - return; - } - updateObscuredTouchRect(); - } - } - - /** Whether the view is stashed at the edge of the screen or not. **/ - public boolean isStashed() { - return mIsStashed; - } - - private void updateObscuredTouchRect() { - if (mIsStashed) { - Rect tmpRect = new Rect(); - getBoundsOnScreen(tmpRect); - mTaskView.setObscuredTouchRect(tmpRect); - } else { - mTaskView.setObscuredTouchRect(null); - } - } - - /** - * Whether the task needs to be restarted, this can happen when {@link #cleanUpTaskView()} has - * been called on this view or if - * {@link #startTask(ShellExecutor, FloatingTasksController.Task)} was never called. - */ - public boolean needsTaskStarted() { - // If the task needs to be restarted then TaskView would have been cleaned up. - return mTaskView == null; - } - - /** Call this when the floating task activity is no longer in use. */ - public void cleanUpTaskView() { - if (mTask != null && mTask.taskId != INVALID_TASK_ID) { - try { - ActivityTaskManager.getService().removeTask(mTask.taskId); - } catch (RemoteException e) { - Log.e(TAG, e.getMessage()); - } - } - if (mTaskView != null) { - mTaskView.release(); - removeView(mTaskView); - mTaskView = null; - } - } - - // TODO: use task background colour / how to get the taskInfo ? - private static int getDragBarColor(ActivityManager.RunningTaskInfo taskInfo) { - final int taskBgColor = taskInfo.taskDescription.getStatusBarColor(); - return Color.valueOf(taskBgColor == -1 ? Color.WHITE : taskBgColor).toArgb(); - } - - private final TaskView.Listener mTaskViewListener = new TaskView.Listener() { - private boolean mInitialized = false; - private boolean mDestroyed = false; - - @Override - public void onInitialized() { - if (mDestroyed || mInitialized) { - return; - } - // Custom options so there is no activity transition animation - ActivityOptions options = ActivityOptions.makeCustomAnimation(getContext(), - /* enterResId= */ 0, /* exitResId= */ 0); - - Rect launchBounds = new Rect(); - mTaskView.getBoundsOnScreen(launchBounds); - - try { - options.setTaskAlwaysOnTop(true); - if (mTask.intent != null) { - Intent fillInIntent = new Intent(); - // Apply flags to make behaviour match documentLaunchMode=always. - fillInIntent.addFlags(FLAG_ACTIVITY_NEW_DOCUMENT); - fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK); - - PendingIntent pi = PendingIntent.getActivity(mContext, 0, mTask.intent, - PendingIntent.FLAG_MUTABLE, - null); - mTaskView.startActivity(pi, fillInIntent, options, launchBounds); - } else { - ProtoLog.e(WM_SHELL_FLOATING_APPS, "Tried to start a task with null intent"); - } - } catch (RuntimeException e) { - ProtoLog.e(WM_SHELL_FLOATING_APPS, "Exception while starting task: %s", - e.getMessage()); - mController.removeTask(); - } - mInitialized = true; - } - - @Override - public void onReleased() { - mDestroyed = true; - } - - @Override - public void onTaskCreated(int taskId, ComponentName name) { - mTask.taskId = taskId; - updateMenuColor(); - setContentVisibility(true); - } - - @Override - public void onTaskVisibilityChanged(int taskId, boolean visible) { - setContentVisibility(visible); - } - - @Override - public void onTaskRemovalStarted(int taskId) { - // Must post because this is called from a binder thread. - post(() -> { - mController.removeTask(); - cleanUpTaskView(); - }); - } - - @Override - public void onBackPressedOnTaskRoot(int taskId) { - if (mTask.taskId == taskId && !mIsStashed) { - // TODO: is removing the window the desired behavior? - post(() -> mController.removeTask()); - } - } - }; -} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java index f4888fbb2bb9..168f6d79a390 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java @@ -98,9 +98,11 @@ public class FreeformTaskTransitionObserver implements Transitions.TransitionObs switch (change.getMode()) { case WindowManager.TRANSIT_OPEN: - case WindowManager.TRANSIT_TO_FRONT: onOpenTransitionReady(change, startT, finishT); break; + case WindowManager.TRANSIT_TO_FRONT: + onToFrontTransitionReady(change, startT, finishT); + break; case WindowManager.TRANSIT_CLOSE: { taskInfoList.add(change.getTaskInfo()); onCloseTransitionReady(change, startT, finishT); @@ -138,6 +140,21 @@ public class FreeformTaskTransitionObserver implements Transitions.TransitionObs change.getTaskInfo(), startT, finishT); } + private void onToFrontTransitionReady( + TransitionInfo.Change change, + SurfaceControl.Transaction startT, + SurfaceControl.Transaction finishT) { + boolean exists = mWindowDecorViewModel.setupWindowDecorationForTransition( + change.getTaskInfo(), + startT, + finishT); + if (!exists) { + // Window caption does not exist, create it + mWindowDecorViewModel.createWindowDecoration( + change.getTaskInfo(), change.getLeash(), startT, finishT); + } + } + @Override public void onTransitionStarting(@NonNull IBinder transition) {} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMenuController.java index f81c9f80830a..16f1d1c2944c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMenuController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMenuController.java @@ -23,7 +23,6 @@ import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; -import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager.RunningTaskInfo; import android.app.RemoteAction; @@ -71,11 +70,6 @@ public interface PipMenuController { void setAppActions(List<RemoteAction> appActions, RemoteAction closeAction); /** - * Wait until the next frame to run the given Runnable. - */ - void runWithNextFrame(@NonNull Runnable runnable); - - /** * Resize the PiP menu with the given bounds. The PiP SurfaceControl is given if there is a * need to synchronize the movements on the same frame as PiP. */ 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 2d7c5ce6feb5..f170e774739f 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 @@ -179,10 +179,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, // This is necessary in case there was a resize animation ongoing when exit PIP // started, in which case the first resize will be skipped to let the exit // operation handle the final resize out of PIP mode. See b/185306679. - finishResizeDelayedIfNeeded(() -> { - finishResize(tx, destinationBounds, direction, animationType); - sendOnPipTransitionFinished(direction); - }); + finishResize(tx, destinationBounds, direction, animationType); + sendOnPipTransitionFinished(direction); } } @@ -198,34 +196,6 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, } }; - /** - * Finishes resizing the PiP, delaying the operation if it has to be synced with the PiP menu. - * - * This is done to avoid a race condition between the last transaction applied in - * onAnimationUpdate and the finishResize in onAnimationEnd. finishResize creates a - * WindowContainerTransaction, which is to be applied by WmCore later. It may happen that it - * gets applied before the transaction created by the last onAnimationUpdate. As a result of - * this, the PiP surface may get scaled after the new bounds are applied by WmCore, which - * makes the PiP surface have unexpected bounds. To avoid this, we delay the finishResize - * operation until the next frame. This aligns the last onAnimationUpdate transaction with the - * WCT application. - * - * The race only happens when the PiP surface transaction has to be synced with the PiP menu - * due to the necessity for a delay when syncing the PiP surface, the PiP menu surface and - * the PiP menu contents. - */ - private void finishResizeDelayedIfNeeded(Runnable finishResizeRunnable) { - if (!shouldSyncPipTransactionWithMenu()) { - finishResizeRunnable.run(); - return; - } - mPipMenuController.runWithNextFrame(finishResizeRunnable); - } - - private boolean shouldSyncPipTransactionWithMenu() { - return mPipMenuController.isMenuVisible(); - } - @VisibleForTesting final PipTransitionController.PipTransitionCallback mPipTransitionCallback = new PipTransitionController.PipTransitionCallback() { @@ -251,7 +221,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, @Override public boolean handlePipTransaction(SurfaceControl leash, SurfaceControl.Transaction tx, Rect destinationBounds) { - if (shouldSyncPipTransactionWithMenu()) { + if (mPipMenuController.isMenuVisible()) { mPipMenuController.movePipMenu(leash, tx, destinationBounds); return true; } @@ -1253,7 +1223,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, mSurfaceTransactionHelper .crop(tx, mLeash, toBounds) .round(tx, mLeash, mPipTransitionState.isInPip()); - if (shouldSyncPipTransactionWithMenu()) { + if (mPipMenuController.isMenuVisible()) { mPipMenuController.resizePipMenu(mLeash, tx, toBounds); } else { tx.apply(); @@ -1295,7 +1265,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, mSurfaceTransactionHelper .scale(tx, mLeash, startBounds, toBounds, degrees) .round(tx, mLeash, startBounds, toBounds); - if (shouldSyncPipTransactionWithMenu()) { + if (mPipMenuController.isMenuVisible()) { mPipMenuController.movePipMenu(mLeash, tx, toBounds); } else { tx.apply(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java index 27902b2231ba..281ea530e9e1 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java @@ -305,18 +305,6 @@ public class PhonePipMenuController implements PipMenuController { showResizeHandle); } - @Override - public void runWithNextFrame(Runnable runnable) { - if (mPipMenuView == null || mPipMenuView.getViewRootImpl() == null) { - runnable.run(); - } - - mPipMenuView.getViewRootImpl().registerRtFrameCallback(frame -> { - mMainHandler.post(runnable); - }); - mPipMenuView.invalidate(); - } - /** * Move the PiP menu, which does a translation and possibly a scale transformation. */ diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java index 7d4b43be4f73..4ce45e142c64 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java @@ -466,18 +466,6 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis } @Override - public void runWithNextFrame(Runnable runnable) { - if (mPipMenuView == null || mPipMenuView.getViewRootImpl() == null) { - runnable.run(); - } - - mPipMenuView.getViewRootImpl().registerRtFrameCallback(frame -> { - mMainHandler.post(runnable); - }); - mPipMenuView.invalidate(); - } - - @Override public void movePipMenu(SurfaceControl pipLeash, SurfaceControl.Transaction transaction, Rect pipDestBounds) { if (DEBUG) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java index c52ed249c2ca..75f9a4c33af9 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java @@ -42,8 +42,8 @@ public enum ShellProtoLogGroup implements IProtoLogGroup { Consts.TAG_WM_SHELL), WM_SHELL_PICTURE_IN_PICTURE(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, Consts.TAG_WM_SHELL), - WM_SHELL_SPLIT_SCREEN(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, - Consts.TAG_WM_SHELL), + WM_SHELL_SPLIT_SCREEN(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true, + Consts.TAG_WM_SPLIT_SCREEN), WM_SHELL_SYSUI_EVENTS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, Consts.TAG_WM_SHELL), WM_SHELL_DESKTOP_MODE(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, @@ -110,6 +110,7 @@ public enum ShellProtoLogGroup implements IProtoLogGroup { private static class Consts { private static final String TAG_WM_SHELL = "WindowManagerShell"; private static final String TAG_WM_STARTING_WINDOW = "ShellStartingWindow"; + private static final String TAG_WM_SPLIT_SCREEN = "ShellSplitScreen"; private static final boolean ENABLE_DEBUG = true; private static final boolean ENABLE_LOG_TO_PROTO_DEBUG = true; 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 15a11334307b..e888c6f8b0f9 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 @@ -1097,7 +1097,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, activityTaskManagerService.setFocusedTask(getTaskId(stageToFocus)); } catch (RemoteException | NullPointerException e) { ProtoLog.e(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, - "%s: Unable to update focus on the chosen stage, %s", TAG, e); + "Unable to update focus on the chosen stage: %s", e.getMessage()); } } @@ -1434,14 +1434,14 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, } ProtoLog.d(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, - "%s: Request to %s divider bar from %s.", TAG, + "Request to %s divider bar from %s.", (visible ? "show" : "hide"), Debug.getCaller()); // Defer showing divider bar after keyguard dismissed, so it won't interfere with keyguard // dismissing animation. if (visible && mKeyguardShowing) { ProtoLog.d(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, - "%s: Defer showing divider bar due to keyguard showing.", TAG); + " Defer showing divider bar due to keyguard showing."); return; } @@ -1450,7 +1450,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, if (mIsDividerRemoteAnimating) { ProtoLog.d(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, - "%s: Skip animating divider bar due to it's remote animating.", TAG); + " Skip animating divider bar due to it's remote animating."); return; } @@ -1465,12 +1465,12 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, final SurfaceControl dividerLeash = mSplitLayout.getDividerLeash(); if (dividerLeash == null) { ProtoLog.d(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, - "%s: Skip animating divider bar due to divider leash not ready.", TAG); + " Skip animating divider bar due to divider leash not ready."); return; } if (mIsDividerRemoteAnimating) { ProtoLog.d(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, - "%s: Skip animating divider bar due to it's remote animating.", TAG); + " Skip animating divider bar due to it's remote animating."); return; } @@ -1633,14 +1633,14 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, } @Override - public void onLayoutSizeChanging(SplitLayout layout) { + public void onLayoutSizeChanging(SplitLayout layout, int offsetX, int offsetY) { final SurfaceControl.Transaction t = mTransactionPool.acquire(); t.setFrameTimelineVsync(Choreographer.getInstance().getVsyncId()); updateSurfaceBounds(layout, t, true /* applyResizingOffset */); getMainStageBounds(mTempRect1); getSideStageBounds(mTempRect2); - mMainStage.onResizing(mTempRect1, mTempRect2, t); - mSideStage.onResizing(mTempRect2, mTempRect1, t); + mMainStage.onResizing(mTempRect1, mTempRect2, t, offsetX, offsetY); + mSideStage.onResizing(mTempRect2, mTempRect1, t, offsetX, offsetY); t.apply(); mTransactionPool.release(t); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java index 6b90eabe3bd2..acad5d93eab4 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java @@ -288,9 +288,11 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener { } } - void onResizing(Rect newBounds, Rect sideBounds, SurfaceControl.Transaction t) { + void onResizing(Rect newBounds, Rect sideBounds, SurfaceControl.Transaction t, int offsetX, + int offsetY) { if (mSplitDecorManager != null && mRootTaskInfo != null) { - mSplitDecorManager.onResizing(mRootTaskInfo, newBounds, sideBounds, t); + mSplitDecorManager.onResizing(mRootTaskInfo, newBounds, sideBounds, t, offsetX, + offsetY); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java index 2830fa967011..857decf65567 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java @@ -24,7 +24,6 @@ import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_TO_BACK; import static android.view.WindowManager.TRANSIT_TO_FRONT; import static android.view.WindowManager.fixScale; -import static android.window.TransitionInfo.FLAG_IS_INPUT_METHOD; import static android.window.TransitionInfo.FLAG_IS_OCCLUDED; import static android.window.TransitionInfo.FLAG_IS_WALLPAPER; import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT; @@ -333,9 +332,12 @@ public class Transitions implements RemoteCallable<Transitions> { boolean isOpening = isOpeningType(info.getType()); for (int i = info.getChanges().size() - 1; i >= 0; --i) { final TransitionInfo.Change change = info.getChanges().get(i); - if ((change.getFlags() & TransitionInfo.FLAG_IS_SYSTEM_WINDOW) != 0) { + if (change.hasFlags(TransitionInfo.FLAGS_IS_NON_APP_WINDOW)) { // Currently system windows are controlled by WindowState, so don't change their - // surfaces. Otherwise their window tokens could be hidden unexpectedly. + // surfaces. Otherwise their surfaces could be hidden or cropped unexpectedly. + // This includes Wallpaper (always z-ordered at bottom) and IME (associated with + // app), because there may not be a transition associated with their visibility + // changes, and currently they don't need transition animation. continue; } final SurfaceControl leash = change.getLeash(); @@ -372,16 +374,7 @@ public class Transitions implements RemoteCallable<Transitions> { finishT.setAlpha(leash, 1.f); } } else if (mode == TRANSIT_CLOSE || mode == TRANSIT_TO_BACK) { - // Wallpaper/IME are anomalies: their visibility is tied to other WindowStates. - // As a result, we actually can't hide their WindowTokens because there may not be a - // transition associated with them becoming visible again. Fortunately, since - // wallpapers are always z-ordered to the back, we don't have to worry about it - // flickering to the front during reparenting. Similarly, the IME is reparented to - // the associated app, so its visibility is coupled. So, an explicit hide is not - // needed visually anyways. - if ((change.getFlags() & (FLAG_IS_WALLPAPER | FLAG_IS_INPUT_METHOD)) == 0) { - finishT.hide(leash); - } + finishT.hide(leash); } } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java index 36dd8edaa8b7..ca15f0002fac 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java @@ -105,6 +105,11 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT) { if (!shouldShowWindowDecor(taskInfo)) return false; + CaptionWindowDecoration oldDecoration = mWindowDecorByTaskId.get(taskInfo.taskId); + if (oldDecoration != null) { + // close the old decoration if it exists to avoid two window decorations being added + oldDecoration.close(); + } final CaptionWindowDecoration windowDecoration = new CaptionWindowDecoration( mContext, mDisplayController, @@ -141,23 +146,25 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { } @Override - public void setupWindowDecorationForTransition( + public boolean setupWindowDecorationForTransition( RunningTaskInfo taskInfo, SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT) { final CaptionWindowDecoration decoration = mWindowDecorByTaskId.get(taskInfo.taskId); - if (decoration == null) return; + if (decoration == null) return false; decoration.relayout(taskInfo, startT, finishT); + return true; } @Override - public void destroyWindowDecoration(RunningTaskInfo taskInfo) { + public boolean destroyWindowDecoration(RunningTaskInfo taskInfo) { final CaptionWindowDecoration decoration = mWindowDecorByTaskId.removeReturnOld(taskInfo.taskId); - if (decoration == null) return; + if (decoration == null) return false; decoration.close(); + return true; } private class CaptionTouchEventListener implements diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecorViewModel.java index d7f71c8235f1..2ce4d04377a1 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecorViewModel.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecorViewModel.java @@ -44,7 +44,7 @@ public interface WindowDecorViewModel { * @param taskSurface the surface of the task * @param startT the start transaction to be applied before the transition * @param finishT the finish transaction to restore states after the transition - * @return the window decoration object + * @return {@code true} if window decoration was created, {@code false} otherwise */ boolean createWindowDecoration( ActivityManager.RunningTaskInfo taskInfo, @@ -66,8 +66,9 @@ public interface WindowDecorViewModel { * * @param startT the start transaction to be applied before the transition * @param finishT the finish transaction to restore states after the transition + * @return {@code true} if window decoration exists, {@code false} otherwise */ - void setupWindowDecorationForTransition( + boolean setupWindowDecorationForTransition( ActivityManager.RunningTaskInfo taskInfo, SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT); @@ -76,6 +77,7 @@ public interface WindowDecorViewModel { * Destroys the window decoration of the give task. * * @param taskInfo the info of the task + * @return {@code true} if window decoration was destroyed, {@code false} otherwise */ - void destroyWindowDecoration(ActivityManager.RunningTaskInfo taskInfo); + boolean destroyWindowDecoration(ActivityManager.RunningTaskInfo taskInfo); } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/OWNERS b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/OWNERS new file mode 100644 index 000000000000..1e0f9bc6322f --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/OWNERS @@ -0,0 +1,5 @@ +# WM shell sub-module back navigation owners +# Bug component: 1152663 +shanh@google.com +arthurhung@google.com +wilsonshih@google.com diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java index f6d6c03bc2ee..3d779481d361 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java @@ -105,7 +105,8 @@ public class SplitLayoutTests extends ShellTestCase { @Test public void testUpdateDivideBounds() { mSplitLayout.updateDivideBounds(anyInt()); - verify(mSplitLayoutHandler).onLayoutSizeChanging(any(SplitLayout.class)); + verify(mSplitLayoutHandler).onLayoutSizeChanging(any(SplitLayout.class), anyInt(), + anyInt()); } @Test @@ -140,7 +141,7 @@ public class SplitLayoutTests extends ShellTestCase { DividerSnapAlgorithm.SnapTarget snapTarget = getSnapTarget(0 /* position */, DividerSnapAlgorithm.SnapTarget.FLAG_DISMISS_START); - mSplitLayout.snapToTarget(0 /* currentPosition */, snapTarget); + mSplitLayout.snapToTarget(mSplitLayout.getDividePosition(), snapTarget); waitDividerFlingFinished(); verify(mSplitLayoutHandler).onSnappedToDismiss(eq(false), anyInt()); } @@ -152,7 +153,7 @@ public class SplitLayoutTests extends ShellTestCase { DividerSnapAlgorithm.SnapTarget snapTarget = getSnapTarget(0 /* position */, DividerSnapAlgorithm.SnapTarget.FLAG_DISMISS_END); - mSplitLayout.snapToTarget(0 /* currentPosition */, snapTarget); + mSplitLayout.snapToTarget(mSplitLayout.getDividePosition(), snapTarget); waitDividerFlingFinished(); verify(mSplitLayoutHandler).onSnappedToDismiss(eq(true), anyInt()); } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/floating/FloatingTasksControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/floating/FloatingTasksControllerTest.java deleted file mode 100644 index d378a177650a..000000000000 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/floating/FloatingTasksControllerTest.java +++ /dev/null @@ -1,261 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.wm.shell.floating; - -import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; -import static com.android.wm.shell.floating.FloatingTasksController.SMALLEST_SCREEN_WIDTH_DP_TO_BE_TABLET; - -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.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.content.Intent; -import android.content.res.Configuration; -import android.graphics.Insets; -import android.graphics.Rect; -import android.os.RemoteException; -import android.os.SystemProperties; -import android.view.WindowInsets; -import android.view.WindowManager; -import android.view.WindowMetrics; - -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - -import com.android.wm.shell.ShellTaskOrganizer; -import com.android.wm.shell.ShellTestCase; -import com.android.wm.shell.TaskViewTransitions; -import com.android.wm.shell.TestShellExecutor; -import com.android.wm.shell.common.ShellExecutor; -import com.android.wm.shell.common.SyncTransactionQueue; -import com.android.wm.shell.floating.views.FloatingTaskLayer; -import com.android.wm.shell.sysui.ShellCommandHandler; -import com.android.wm.shell.sysui.ShellController; -import com.android.wm.shell.sysui.ShellInit; -import com.android.wm.shell.sysui.ShellSharedConstants; - -import org.junit.After; -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; - -import java.util.Optional; - -/** - * Tests for the floating tasks controller. - */ -@SmallTest -@RunWith(AndroidJUnit4.class) -public class FloatingTasksControllerTest extends ShellTestCase { - // Some behavior in the controller constructor is dependent on this so we can only - // validate if it's working for the real value for those things. - private static final boolean FLOATING_TASKS_ACTUALLY_ENABLED = - SystemProperties.getBoolean("persist.wm.debug.floating_tasks", false); - - @Mock private ShellInit mShellInit; - @Mock private ShellController mShellController; - @Mock private WindowManager mWindowManager; - @Mock private ShellTaskOrganizer mTaskOrganizer; - @Captor private ArgumentCaptor<FloatingTaskLayer> mFloatingTaskLayerCaptor; - - private FloatingTasksController mController; - - @Before - public void setUp() throws RemoteException { - MockitoAnnotations.initMocks(this); - - WindowMetrics windowMetrics = mock(WindowMetrics.class); - WindowInsets windowInsets = mock(WindowInsets.class); - Insets insets = Insets.of(0, 0, 0, 0); - when(mWindowManager.getCurrentWindowMetrics()).thenReturn(windowMetrics); - when(windowMetrics.getWindowInsets()).thenReturn(windowInsets); - when(windowMetrics.getBounds()).thenReturn(new Rect(0, 0, 1000, 1000)); - when(windowInsets.getInsetsIgnoringVisibility(anyInt())).thenReturn(insets); - - // For the purposes of this test, just run everything synchronously - ShellExecutor shellExecutor = new TestShellExecutor(); - when(mTaskOrganizer.getExecutor()).thenReturn(shellExecutor); - } - - @After - public void tearDown() { - if (mController != null) { - mController.removeTask(); - mController = null; - } - } - - private void setUpTabletConfig() { - Configuration config = mock(Configuration.class); - config.smallestScreenWidthDp = SMALLEST_SCREEN_WIDTH_DP_TO_BE_TABLET; - mController.setConfig(config); - } - - private void setUpPhoneConfig() { - Configuration config = mock(Configuration.class); - config.smallestScreenWidthDp = SMALLEST_SCREEN_WIDTH_DP_TO_BE_TABLET - 1; - mController.setConfig(config); - } - - private void createController() { - mController = new FloatingTasksController(mContext, - mShellInit, - mShellController, - mock(ShellCommandHandler.class), - Optional.empty(), - mWindowManager, - mTaskOrganizer, - mock(TaskViewTransitions.class), - mock(ShellExecutor.class), - mock(ShellExecutor.class), - mock(SyncTransactionQueue.class)); - spyOn(mController); - } - - // - // Shell specific - // - @Test - public void instantiateController_addInitCallback() { - if (FLOATING_TASKS_ACTUALLY_ENABLED) { - createController(); - setUpTabletConfig(); - - verify(mShellInit, times(1)).addInitCallback(any(), any()); - } - } - - @Test - public void instantiateController_doesntAddInitCallback() { - if (!FLOATING_TASKS_ACTUALLY_ENABLED) { - createController(); - - verify(mShellInit, never()).addInitCallback(any(), any()); - } - } - - @Test - public void onInit_registerConfigChangeListener() { - if (FLOATING_TASKS_ACTUALLY_ENABLED) { - createController(); - setUpTabletConfig(); - mController.onInit(); - - verify(mShellController, times(1)).addConfigurationChangeListener(any()); - } - } - - @Test - public void onInit_addExternalInterface() { - if (FLOATING_TASKS_ACTUALLY_ENABLED) { - createController(); - setUpTabletConfig(); - mController.onInit(); - - verify(mShellController, times(1)).addExternalInterface( - ShellSharedConstants.KEY_EXTRA_SHELL_FLOATING_TASKS, any(), any()); - } - } - - // - // Tests for floating layer, which is only available for tablets. - // - - @Test - public void testIsFloatingLayerAvailable_true() { - createController(); - setUpTabletConfig(); - assertThat(mController.isFloatingLayerAvailable()).isTrue(); - } - - @Test - public void testIsFloatingLayerAvailable_false() { - createController(); - setUpPhoneConfig(); - assertThat(mController.isFloatingLayerAvailable()).isFalse(); - } - - // - // Tests for floating tasks being enabled, guarded by sysprop flag. - // - - @Test - public void testIsFloatingTasksEnabled_true() { - createController(); - mController.setFloatingTasksEnabled(true); - setUpTabletConfig(); - assertThat(mController.isFloatingTasksEnabled()).isTrue(); - } - - @Test - public void testIsFloatingTasksEnabled_false() { - createController(); - mController.setFloatingTasksEnabled(false); - setUpTabletConfig(); - assertThat(mController.isFloatingTasksEnabled()).isFalse(); - } - - // - // Tests for behavior depending on flags - // - - @Test - public void testShowTaskIntent_enabled() { - createController(); - mController.setFloatingTasksEnabled(true); - setUpTabletConfig(); - - mController.showTask(mock(Intent.class)); - verify(mWindowManager).addView(mFloatingTaskLayerCaptor.capture(), any()); - assertThat(mFloatingTaskLayerCaptor.getValue().getTaskViewCount()).isEqualTo(1); - } - - @Test - public void testShowTaskIntent_notEnabled() { - createController(); - mController.setFloatingTasksEnabled(false); - setUpTabletConfig(); - - mController.showTask(mock(Intent.class)); - verify(mWindowManager, never()).addView(any(), any()); - } - - @Test - public void testRemoveTask() { - createController(); - mController.setFloatingTasksEnabled(true); - setUpTabletConfig(); - - mController.showTask(mock(Intent.class)); - verify(mWindowManager).addView(mFloatingTaskLayerCaptor.capture(), any()); - assertThat(mFloatingTaskLayerCaptor.getValue().getTaskViewCount()).isEqualTo(1); - - mController.removeTask(); - verify(mWindowManager).removeView(mFloatingTaskLayerCaptor.capture()); - assertThat(mFloatingTaskLayerCaptor.getValue().getTaskViewCount()).isEqualTo(0); - } -} diff --git a/packages/PackageInstaller/res/values-te/strings.xml b/packages/PackageInstaller/res/values-te/strings.xml index c016bfc1f8bb..3344d4d90c24 100644 --- a/packages/PackageInstaller/res/values-te/strings.xml +++ b/packages/PackageInstaller/res/values-te/strings.xml @@ -73,8 +73,8 @@ <string name="uninstall_all_blocked_profile_owner" msgid="2009393666026751501">"ఈ యాప్ కొందరు వినియోగదారులకు లేదా కొన్ని ప్రొఫైళ్లకు అవసరం, ఇతరులకు అన్ఇన్స్టాల్ చేయబడింది"</string> <string name="uninstall_blocked_profile_owner" msgid="6373897407002404848">"మీ ప్రొఫైల్ కోసం ఈ యాప్ అవసరం, అందువల్ల దీన్ని అన్ఇన్స్టాల్ చేయడం కుదరదు."</string> <string name="uninstall_blocked_device_owner" msgid="6724602931761073901">"మీ పరికర నిర్వాహకులకు ఈ యాప్ అవసరం, అందువల్ల దీన్ని అన్ఇన్స్టాల్ చేయడం కుదరదు."</string> - <string name="manage_device_administrators" msgid="3092696419363842816">"పరికర నిర్వాహక యాప్లను నిర్వహించు"</string> - <string name="manage_users" msgid="1243995386982560813">"వినియోగదారులను నిర్వహించు"</string> + <string name="manage_device_administrators" msgid="3092696419363842816">"పరికర నిర్వాహక యాప్లను మేనేజ్ చేయండి"</string> + <string name="manage_users" msgid="1243995386982560813">"వినియోగదారులను మేనేజ్ చేయండి"</string> <string name="uninstall_failed_msg" msgid="2176744834786696012">"<xliff:g id="APP_NAME">%1$s</xliff:g>ని అన్ఇన్స్టాల్ చేయడం సాధ్యపడలేదు."</string> <string name="Parse_error_dlg_text" msgid="1661404001063076789">"ప్యాకేజీని అన్వయించడంలో సమస్య ఏర్పడింది."</string> <string name="wear_not_allowed_dlg_title" msgid="8664785993465117517">"Android Wear"</string> diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml index 3750254f6788..e4a635c4a486 100644 --- a/packages/SettingsLib/res/values-eu/strings.xml +++ b/packages/SettingsLib/res/values-eu/strings.xml @@ -620,7 +620,7 @@ <string name="user_image_photo_selector" msgid="433658323306627093">"Hautatu argazki bat"</string> <string name="failed_attempts_now_wiping_device" msgid="4016329172216428897">"Saiakera oker gehiegi egin dituzu. Gailu honetako datuak ezabatu egingo dira."</string> <string name="failed_attempts_now_wiping_user" msgid="469060411789668050">"Saiakera oker gehiegi egin dituzu. Erabiltzailea ezabatu egingo da."</string> - <string name="failed_attempts_now_wiping_profile" msgid="7626589520888963129">"Saiakera oker gehiegi egin dituzu. Laneko profila eta bertako datuak ezabatu egingo dira."</string> + <string name="failed_attempts_now_wiping_profile" msgid="7626589520888963129">"Saiakera oker gehiegi egin dituzu. Laneko profila eta bertako datuak ezabatuko dira."</string> <string name="failed_attempts_now_wiping_dialog_dismiss" msgid="2749889771223578925">"Baztertu"</string> <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Gailuaren balio lehenetsia"</string> <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Desgaituta"</string> diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp index 2f5b5f456d0b..9d7a9e7aac8a 100644 --- a/packages/SystemUI/Android.bp +++ b/packages/SystemUI/Android.bp @@ -114,6 +114,7 @@ android_library { "androidx.dynamicanimation_dynamicanimation", "androidx-constraintlayout_constraintlayout", "androidx.exifinterface_exifinterface", + "androidx.test.ext.junit", "com.google.android.material_material", "kotlinx_coroutines_android", "kotlinx_coroutines", @@ -125,6 +126,7 @@ android_library { "jsr330", "lottie", "LowLightDreamLib", + "motion_tool_lib", ], manifest: "AndroidManifest.xml", @@ -222,6 +224,7 @@ android_library { "androidx.test.rules", "androidx.test.uiautomator", "mockito-target-extended-minus-junit4", + "androidx.test.ext.junit", "testables", "truth-prebuilt", "monet", @@ -229,6 +232,7 @@ android_library { "jsr330", "WindowManager-Shell", "LowLightDreamLib", + "motion_tool_lib", ], libs: [ "android.test.runner", diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java index c50340cfd247..e52a57f761c7 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java @@ -82,6 +82,18 @@ public interface FalsingManager { boolean isFalseTap(@Penalty int penalty); /** + * Returns true if the FalsingManager thinks the last gesture was not a valid long tap. + * + * Use this method to validate a long tap for launching an action, like long press on a UMO + * + * The only parameter, penalty, indicates how much this should affect future gesture + * classifications if this long tap looks like a false. + * As long taps are hard to confirm as false or otherwise, + * a low penalty value is encouraged unless context indicates otherwise. + */ + boolean isFalseLongTap(@Penalty int penalty); + + /** * Returns true if the last two gestures do not look like a double tap. * * Only works on data that has already been reported to the FalsingManager. Be sure that diff --git a/packages/SystemUI/res/drawable/brightness_progress_drawable.xml b/packages/SystemUI/res/drawable/brightness_progress_drawable.xml index 88d8f78fa610..569ee76586c2 100644 --- a/packages/SystemUI/res/drawable/brightness_progress_drawable.xml +++ b/packages/SystemUI/res/drawable/brightness_progress_drawable.xml @@ -30,7 +30,7 @@ </item> <item android:id="@android:id/progress" android:gravity="center_vertical|fill_horizontal"> - <com.android.systemui.util.RoundedCornerProgressDrawable + <com.android.systemui.util.BrightnessProgressDrawable android:drawable="@drawable/brightness_progress_full_drawable" /> </item> diff --git a/packages/SystemUI/res/drawable/udfps_enroll_checkmark.xml b/packages/SystemUI/res/drawable/udfps_enroll_checkmark.xml index f8169d377f12..a3ed3d1f6b79 100644 --- a/packages/SystemUI/res/drawable/udfps_enroll_checkmark.xml +++ b/packages/SystemUI/res/drawable/udfps_enroll_checkmark.xml @@ -26,10 +26,10 @@ android:fillType="evenOdd"/> <path android:pathData="M27,0C12.088,0 0,12.088 0,27C0,41.912 12.088,54 27,54C41.912,54 54,41.912 54,27C54,12.088 41.912,0 27,0ZM27,3.962C39.703,3.962 50.037,14.297 50.037,27C50.037,39.703 39.703,50.038 27,50.038C14.297,50.038 3.963,39.703 3.963,27C3.963,14.297 14.297,3.962 27,3.962Z" - android:fillColor="@color/udfps_enroll_progress" + android:fillColor="?attr/biometricsEnrollProgress" android:fillType="evenOdd"/> <path android:pathData="M23.0899,38.8534L10.4199,26.1824L13.2479,23.3544L23.0899,33.1974L41.2389,15.0474L44.0679,17.8754L23.0899,38.8534Z" - android:fillColor="@color/udfps_enroll_progress" + android:fillColor="?attr/biometricsEnrollProgress" android:fillType="evenOdd"/> </vector> diff --git a/packages/SystemUI/res/drawable/user_switcher_fullscreen_button_bg.xml b/packages/SystemUI/res/drawable/user_switcher_fullscreen_button_bg.xml new file mode 100644 index 000000000000..ae0f4b2e19db --- /dev/null +++ b/packages/SystemUI/res/drawable/user_switcher_fullscreen_button_bg.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2022 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<inset xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" + android:insetTop="@dimen/dialog_button_vertical_inset" + android:insetBottom="@dimen/dialog_button_vertical_inset"> + <ripple android:color="?android:attr/colorControlHighlight"> + <item android:id="@android:id/mask"> + <shape android:shape="rectangle"> + <solid android:color="@android:color/white"/> + <corners android:radius="20dp"/> + </shape> + </item> + <item> + <shape android:shape="rectangle"> + <corners android:radius="20dp"/> + <solid android:color="@android:color/transparent"/> + <stroke android:color="?androidprv:attr/colorAccentPrimaryVariant" + android:width="1dp" + /> + <padding android:left="@dimen/dialog_button_horizontal_padding" + android:top="@dimen/dialog_button_vertical_padding" + android:right="@dimen/dialog_button_horizontal_padding" + android:bottom="@dimen/dialog_button_vertical_padding"/> + </shape> + </item> + </ripple> +</inset> diff --git a/packages/SystemUI/res/layout/dream_overlay_status_bar_view.xml b/packages/SystemUI/res/layout/dream_overlay_status_bar_view.xml index 006b260434bc..9add32c6ee0a 100644 --- a/packages/SystemUI/res/layout/dream_overlay_status_bar_view.xml +++ b/packages/SystemUI/res/layout/dream_overlay_status_bar_view.xml @@ -18,6 +18,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/dream_overlay_status_bar" + android:visibility="invisible" android:layout_width="match_parent" android:layout_height="@dimen/dream_overlay_status_bar_height" android:paddingEnd="@dimen/dream_overlay_status_bar_margin" diff --git a/packages/SystemUI/res/layout/screen_record_options.xml b/packages/SystemUI/res/layout/screen_record_options.xml new file mode 100644 index 000000000000..a93691434bc0 --- /dev/null +++ b/packages/SystemUI/res/layout/screen_record_options.xml @@ -0,0 +1,86 @@ +<!-- + Copyright (C) 2022 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + <ImageView + android:layout_width="@dimen/screenrecord_option_icon_size" + android:layout_height="@dimen/screenrecord_option_icon_size" + android:src="@drawable/ic_mic_26dp" + android:tint="?android:attr/textColorSecondary" + android:layout_gravity="center_vertical" + android:layout_weight="0" + android:layout_marginRight="@dimen/screenrecord_option_padding" + android:importantForAccessibility="no"/> + <Spinner + android:id="@+id/screen_recording_options" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:minHeight="48dp" + android:layout_weight="1" + android:popupBackground="@drawable/screenrecord_spinner_background" + android:dropDownWidth="274dp" + android:importantForAccessibility="yes"/> + <Switch + android:layout_width="wrap_content" + android:minWidth="48dp" + android:layout_height="48dp" + android:layout_weight="0" + android:layout_gravity="end" + android:id="@+id/screenrecord_audio_switch" + style="@style/ScreenRecord.Switch" + android:importantForAccessibility="yes"/> + </LinearLayout> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:layout_marginTop="@dimen/screenrecord_option_padding"> + <ImageView + android:layout_width="@dimen/screenrecord_option_icon_size" + android:layout_height="@dimen/screenrecord_option_icon_size" + android:layout_weight="0" + android:src="@drawable/ic_touch" + android:tint="?android:attr/textColorSecondary" + android:layout_gravity="center_vertical" + android:layout_marginRight="@dimen/screenrecord_option_padding" + android:importantForAccessibility="no"/> + <TextView + android:layout_width="0dp" + android:layout_height="match_parent" + android:minHeight="48dp" + android:layout_weight="1" + android:gravity="center_vertical" + android:text="@string/screenrecord_taps_label" + android:textAppearance="?android:attr/textAppearanceMedium" + android:fontFamily="@*android:string/config_headlineFontFamily" + android:textColor="?android:attr/textColorPrimary" + android:contentDescription="@string/screenrecord_taps_label"/> + <Switch + android:layout_width="wrap_content" + android:minWidth="48dp" + android:layout_height="48dp" + android:layout_weight="0" + android:id="@+id/screenrecord_taps_switch" + style="@style/ScreenRecord.Switch" + android:importantForAccessibility="yes"/> + </LinearLayout> +</LinearLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/screen_share_dialog.xml b/packages/SystemUI/res/layout/screen_share_dialog.xml new file mode 100644 index 000000000000..ac46cdb1be24 --- /dev/null +++ b/packages/SystemUI/res/layout/screen_share_dialog.xml @@ -0,0 +1,94 @@ +<!-- + Copyright (C) 2022 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<!-- Scrollview is necessary to fit everything in landscape layout --> +<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:id="@+id/screen_share_permission_dialog" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingStart="@dimen/dialog_side_padding" + android:paddingEnd="@dimen/dialog_side_padding" + android:paddingTop="@dimen/dialog_top_padding" + android:paddingBottom="@dimen/dialog_bottom_padding" + android:orientation="vertical" + android:gravity="center_horizontal"> + + <ImageView + android:layout_width="@dimen/screenrecord_logo_size" + android:layout_height="@dimen/screenrecord_logo_size" + android:src="@drawable/ic_screenrecord" + android:tint="@color/screenrecord_icon_color" + android:importantForAccessibility="no"/> + <TextView + android:id="@+id/screen_share_dialog_title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceLarge" + android:fontFamily="@*android:string/config_headlineFontFamily" + android:layout_marginTop="22dp" + android:layout_marginBottom="15dp"/> + <Spinner + android:id="@+id/screen_share_mode_spinner" + android:layout_width="320dp" + android:layout_height="72dp" + android:layout_marginTop="24dp" + android:layout_marginBottom="24dp" /> + <ViewStub + android:id="@+id/options_stub" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> + <TextView + android:id="@+id/text_warning" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/screenrecord_description" + android:textAppearance="?android:attr/textAppearanceSmall" + android:textColor="?android:textColorSecondary" + android:gravity="start" + android:layout_marginBottom="20dp"/> + + <!-- Buttons --> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:layout_marginTop="36dp"> + <TextView + android:id="@+id/button_cancel" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_weight="0" + android:text="@string/cancel" + style="@style/Widget.Dialog.Button.BorderButton" /> + <Space + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="1"/> + <TextView + android:id="@+id/button_start" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_weight="0" + android:text="@string/screenrecord_start" + style="@style/Widget.Dialog.Button" /> + </LinearLayout> + </LinearLayout> +</ScrollView>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/screenshot_static.xml b/packages/SystemUI/res/layout/screenshot_static.xml index 1ac78d491d78..88429925eed0 100644 --- a/packages/SystemUI/res/layout/screenshot_static.xml +++ b/packages/SystemUI/res/layout/screenshot_static.xml @@ -44,7 +44,7 @@ app:layout_constraintHorizontal_bias="0" app:layout_constraintWidth_percent="1.0" app:layout_constraintWidth_max="wrap" - app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintBottom_toTopOf="@id/screenshot_message_container" app:layout_constraintStart_toEndOf="@+id/screenshot_preview_border" app:layout_constraintEnd_toEndOf="parent"> <LinearLayout @@ -70,7 +70,7 @@ android:alpha="0" android:background="@drawable/overlay_border" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintBottom_toTopOf="@id/screenshot_message_container" app:layout_constraintEnd_toEndOf="@id/screenshot_preview_end" app:layout_constraintTop_toTopOf="@id/screenshot_preview_top"/> <androidx.constraintlayout.widget.Barrier @@ -142,4 +142,41 @@ app:layout_constraintStart_toStartOf="@id/screenshot_preview" app:layout_constraintTop_toTopOf="@id/screenshot_preview" android:elevation="7dp"/> + + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/screenshot_message_container" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginHorizontal="@dimen/overlay_action_container_margin_horizontal" + android:layout_marginVertical="4dp" + android:paddingHorizontal="@dimen/overlay_action_container_padding_right" + android:paddingVertical="@dimen/overlay_action_container_padding_vertical" + android:elevation="4dp" + android:background="@drawable/action_chip_container_background" + android:visibility="gone" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintBottom_toBottomOf="parent"> + + <ImageView + android:id="@+id/screenshot_message_icon" + android:layout_width="48dp" + android:layout_height="48dp" + android:paddingEnd="4dp" + android:src="@drawable/ic_work_app_badge" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintBottom_toBottomOf="parent"/> + + <TextView + android:id="@+id/screenshot_message_content" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_gravity="start" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toEndOf="@id/screenshot_message_icon" + app:layout_constraintEnd_toEndOf="parent"/> + + </androidx.constraintlayout.widget.ConstraintLayout> </com.android.systemui.screenshot.DraggableConstraintLayout> diff --git a/packages/SystemUI/res/layout/user_switcher_fullscreen.xml b/packages/SystemUI/res/layout/user_switcher_fullscreen.xml index 78884ffbe1a2..fa9d7390dcf8 100644 --- a/packages/SystemUI/res/layout/user_switcher_fullscreen.xml +++ b/packages/SystemUI/res/layout/user_switcher_fullscreen.xml @@ -80,7 +80,7 @@ <TextView android:id="@+id/add" - style="@style/Widget.Dialog.Button.BorderButton" + android:background="@drawable/user_switcher_fullscreen_button_bg" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" diff --git a/packages/SystemUI/res/raw/biometricprompt_folded_base_bottomright.json b/packages/SystemUI/res/raw/biometricprompt_folded_base_bottomright.json new file mode 100644 index 000000000000..2797996c6ef2 --- /dev/null +++ b/packages/SystemUI/res/raw/biometricprompt_folded_base_bottomright.json @@ -0,0 +1 @@ +{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"biometricprompt_portrait_base_bottomright","ddd":0,"assets":[{"id":"comp_0","nm":"biometricprompt_landscape_base","fr":60,"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 16","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[170,170,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":3,"nm":"Null_Circle","parent":1,"sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-108,"s":[70.333,-88.75,0],"to":[-11.722,17.639,0],"ti":[11.722,-17.639,0]},{"t":-48,"s":[0,17.083,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".grey600","cl":"grey600","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.501960784314,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"circle mask 3","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Finger","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":-60,"s":[55]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":110,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":140,"s":[10]},{"t":170,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-60,"s":[92.146,-65.896,0],"to":[1.361,6.667,0],"ti":[-1.361,-6.667,0]},{"i":{"x":0.2,"y":0.2},"o":{"x":0.167,"y":0.167},"t":0,"s":[100.313,-25.896,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.2,"y":0.2},"o":{"x":0.7,"y":0.7},"t":110,"s":[100.313,-25.896,0],"to":[0,0,0],"ti":[0,0,0]},{"t":170,"s":[100.313,-25.896,0]}],"ix":2,"l":2},"a":{"a":0,"k":[160.315,58.684,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-11.013,2.518],[5.251,5.023],[8.982,-2.829],[-0.264,-5.587]],"o":[[12.768,-2.854],[-14.961,2.071],[-6.004,1.89],[8.052,1.403]],"v":[[5.115,7.499],[19.814,-10.087],[-16.489,-3.588],[-24.801,8.684]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.760784373564,0.478431402468,0.400000029919,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[34.67,28.053],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[22.231,-7],[-27.395,-1.197],[-26.792,4.092],[14.179,15.736]],"o":[[-17.931,5.646],[56.062,2.45],[-1.765,-22.396],[-51.819,17.744]],"v":[[-62.102,-8.314],[-39.958,30.079],[80.033,25.905],[54.879,-32.529]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.678431372549,0.403921598547,0.305882352941,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[80.283,32.779],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"circle mask 7","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".grey600","cl":"grey600","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.25,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[114.218,-17.096],[-112.938,-17.096]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.501960784314,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":36.9,"ix":2},"o":{"a":0,"k":114.2,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"circle mask","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".grey800","cl":"grey800","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.5,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[114.218,-17.096],[-112.938,-17.096]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"circle mask 6","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":".grey900","cl":"grey900","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":377,"s":[-180]},{"t":417,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":377,"s":[-1.137,1.771,0],"to":[0.375,0,0],"ti":[-0.375,0,0]},{"t":417,"s":[1.113,1.771,0]}],"ix":2,"l":2},"a":{"a":0,"k":[6.238,5.063,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":77,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,-4.637],[-10.23,-3.195],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":107,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":137,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,-4.637],[-10.23,-3.195],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":167,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":197,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,-4.637],[-10.23,-3.195],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.7,"y":0},"t":232,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":562,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"t":602,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-4.546,-0.421],[-5.988,1.021],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[6.238,5.063],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"circle mask 2","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":".blue400","cl":"blue400","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,8.308,0],"ix":2,"l":2},"a":{"a":0,"k":[41.706,20.979,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[18.645,0],[0,18.645]],"o":[[0,18.645],[-18.644,0],[0,0]],"v":[[33.76,-16.88],[-0.001,16.88],[-33.76,-16.88]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[41.706,17.13],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[22.896,0],[0,22.896]],"o":[[0,22.896],[-22.896,0],[0,0]],"v":[[41.457,-20.729],[-0.001,20.729],[-41.457,-20.729]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[41.706,20.979],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":"circle mask 4","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":15,"ty":1,"nm":".grey900","cl":"grey900","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,66,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[52,52,100],"ix":6,"l":2}},"ao":0,"sw":412,"sh":300,"sc":"#202124","ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":"circle mask 5","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":17,"ty":1,"nm":".black","cl":"black","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,-17.333,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[72,72,100],"ix":6,"l":2}},"ao":0,"sw":412,"sh":300,"sc":"#000000","ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":".grey800","cl":"grey800","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-108,"s":[-192.25,99.933,0],"to":[5,3.333,0],"ti":[-5,-3.333,0]},{"t":-48,"s":[-162.25,119.933,0]}],"ix":2,"l":2},"a":{"a":0,"k":[-163,100.85,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2,0.833],"y":[1,1,1]},"o":{"x":[0.7,0.7,0.167],"y":[0,0,0]},"t":-108,"s":[100,100,100]},{"t":-48,"s":[59,59,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":".grey900","cl":"grey900","parent":23,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[0,18.167,0],"to":[0,-1.25,0],"ti":[0,1.25,0]},{"t":-199,"s":[0,10.667,0]}],"ix":2,"l":2},"a":{"a":0,"k":[5.5,4,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-0.07,1.5],[0,-1.5],[-0.047,1.5]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":-199,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":-171,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":-141,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,3.512],[0,0.512],[3,3.512]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":-111,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]},{"t":-81,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,3.967],[0,0.967],[3,3.967]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[5.5,4],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-199,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":"Shape Layer 4","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[71,-116.083,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.7,"y":0},"t":-199,"s":[71,-101.083,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":365,"s":[71,-101.083,0],"to":[0,0,0],"ti":[16.833,-14.361,0]},{"t":405,"s":[-30,-14.917,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-239,"s":[29,29]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-199,"s":[29,38]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":365,"s":[29,36]},{"t":405,"s":[83,83]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":365,"s":[50]},{"t":405,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":21,"ty":4,"nm":".grey900","cl":"grey900","parent":1,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[71,-82.917,0],"to":[0,-1.25,0],"ti":[0,1.25,0]},{"t":-199,"s":[71,-90.417,0]}],"ix":2,"l":2},"a":{"a":0,"k":[5.5,4,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-0.07,1.5],[0,-1.5],[-0.047,1.5]],"c":false}]},{"t":-199,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[5.5,4],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":-199,"st":-255,"bm":0},{"ddd":0,"ind":22,"ty":4,"nm":"device frame mask","parent":24,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,1.167,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":23,"ty":4,"nm":".blue400","cl":"blue400","parent":18,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[100.25,-115.167,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-199,"s":[100.25,-100.167,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.7,"y":0},"t":-159,"s":[100.25,-105.667,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":365,"s":[100.25,-100.167,0],"to":[0,0,0],"ti":[16.833,-14.361,0]},{"t":405,"s":[-0.75,-14,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-239,"s":[29,29]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-199,"s":[29,38]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":365,"s":[29,36]},{"t":405,"s":[83,83]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":365,"s":[50]},{"t":405,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":24,"ty":3,"nm":"device frame mask 5","parent":18,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":-165,"op":6.00000000000001,"st":-271,"bm":0},{"ddd":0,"ind":28,"ty":4,"nm":"device frame mask 9","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-29.25,-0.917,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-181,"op":-62,"st":-181,"bm":0},{"ddd":0,"ind":29,"ty":4,"nm":".blue400","cl":"blue400","parent":23,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":-145,"s":[50]},{"t":-75,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-165,"s":[0,0]},{"t":-75,"s":[94,94]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":73,"s":[50]},{"t":113,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-181,"op":-62,"st":-181,"bm":0},{"ddd":0,"ind":30,"ty":4,"nm":"device frame mask 8","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-29.25,-0.917,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-211,"op":-92,"st":-211,"bm":0},{"ddd":0,"ind":31,"ty":4,"nm":".blue400","cl":"blue400","parent":23,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":-165,"s":[50]},{"t":-95,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-195,"s":[0,0]},{"t":-105,"s":[94,94]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":43,"s":[50]},{"t":83,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-211,"op":-92,"st":-211,"bm":0},{"ddd":0,"ind":32,"ty":4,"nm":"device frame mask 7","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-29.25,-0.917,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-241,"op":-122,"st":-241,"bm":0},{"ddd":0,"ind":33,"ty":4,"nm":".blue400","cl":"blue400","parent":23,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":-195,"s":[50]},{"t":-125,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-225,"s":[0,0]},{"t":-135,"s":[94,94]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":13,"s":[50]},{"t":53,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-241,"op":-122,"st":-241,"bm":0},{"ddd":0,"ind":34,"ty":4,"nm":"device frame mask 6","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-29.25,-0.917,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-271,"op":-152,"st":-271,"bm":0},{"ddd":0,"ind":35,"ty":4,"nm":".blue400","cl":"blue400","parent":23,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":-225,"s":[50]},{"t":-155,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-255,"s":[0,0]},{"t":-165,"s":[94,94]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":-17,"s":[50]},{"t":23,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-271,"op":-152,"st":-271,"bm":0}]}],"layers":[{"ddd":0,"ind":6,"ty":0,"nm":"biometricprompt_landscape_base","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[170,170,0],"ix":2,"l":2},"a":{"a":0,"k":[170,170,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":340,"h":340,"ip":0,"op":900,"st":0,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]} diff --git a/packages/SystemUI/res/raw/biometricprompt_folded_base_default.json b/packages/SystemUI/res/raw/biometricprompt_folded_base_default.json new file mode 100644 index 000000000000..bf65b3418b61 --- /dev/null +++ b/packages/SystemUI/res/raw/biometricprompt_folded_base_default.json @@ -0,0 +1 @@ +{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"biometricprompt_landscape_base","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 16","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[170,170,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":3,"nm":"Null_Circle","parent":1,"sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-108,"s":[70.333,-88.75,0],"to":[-11.722,17.639,0],"ti":[11.722,-17.639,0]},{"t":-48,"s":[0,17.083,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".grey600","cl":"grey600","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.501960784314,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"circle mask 3","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Finger","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":-60,"s":[55]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":110,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":140,"s":[10]},{"t":170,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-60,"s":[92.146,-65.896,0],"to":[1.361,6.667,0],"ti":[-1.361,-6.667,0]},{"i":{"x":0.2,"y":0.2},"o":{"x":0.167,"y":0.167},"t":0,"s":[100.313,-25.896,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.2,"y":0.2},"o":{"x":0.7,"y":0.7},"t":110,"s":[100.313,-25.896,0],"to":[0,0,0],"ti":[0,0,0]},{"t":170,"s":[100.313,-25.896,0]}],"ix":2,"l":2},"a":{"a":0,"k":[160.315,58.684,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-11.013,2.518],[5.251,5.023],[8.982,-2.829],[-0.264,-5.587]],"o":[[12.768,-2.854],[-14.961,2.071],[-6.004,1.89],[8.052,1.403]],"v":[[5.115,7.499],[19.814,-10.087],[-16.489,-3.588],[-24.801,8.684]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.760784373564,0.478431402468,0.400000029919,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[34.67,28.053],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[22.231,-7],[-27.395,-1.197],[-26.792,4.092],[14.179,15.736]],"o":[[-17.931,5.646],[56.062,2.45],[-1.765,-22.396],[-51.819,17.744]],"v":[[-62.102,-8.314],[-39.958,30.079],[80.033,25.905],[54.879,-32.529]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.678431372549,0.403921598547,0.305882352941,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[80.283,32.779],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"circle mask 7","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".grey600","cl":"grey600","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.25,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[114.218,-17.096],[-112.938,-17.096]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.501960784314,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":36.9,"ix":2},"o":{"a":0,"k":114.2,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"circle mask","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".grey800","cl":"grey800","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.5,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[114.218,-17.096],[-112.938,-17.096]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"circle mask 6","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":".grey900","cl":"grey900","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":377,"s":[-180]},{"t":417,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":377,"s":[-1.137,1.771,0],"to":[0.375,0,0],"ti":[-0.375,0,0]},{"t":417,"s":[1.113,1.771,0]}],"ix":2,"l":2},"a":{"a":0,"k":[6.238,5.063,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":77,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,-4.637],[-10.23,-3.195],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":107,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":137,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,-4.637],[-10.23,-3.195],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":167,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":197,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,-4.637],[-10.23,-3.195],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.7,"y":0},"t":232,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":562,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"t":602,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-4.546,-0.421],[-5.988,1.021],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[6.238,5.063],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"circle mask 2","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":".blue400","cl":"blue400","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,8.308,0],"ix":2,"l":2},"a":{"a":0,"k":[41.706,20.979,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[18.645,0],[0,18.645]],"o":[[0,18.645],[-18.644,0],[0,0]],"v":[[33.76,-16.88],[-0.001,16.88],[-33.76,-16.88]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[41.706,17.13],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[22.896,0],[0,22.896]],"o":[[0,22.896],[-22.896,0],[0,0]],"v":[[41.457,-20.729],[-0.001,20.729],[-41.457,-20.729]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[41.706,20.979],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":"circle mask 4","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":15,"ty":1,"nm":".grey900","cl":"grey900","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,66,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[52,52,100],"ix":6,"l":2}},"ao":0,"sw":412,"sh":300,"sc":"#202124","ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":"circle mask 5","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":17,"ty":1,"nm":".black","cl":"black","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,-17.333,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[72,72,100],"ix":6,"l":2}},"ao":0,"sw":412,"sh":300,"sc":"#000000","ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":".grey800","cl":"grey800","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-108,"s":[-192.25,99.933,0],"to":[5,3.333,0],"ti":[-5,-3.333,0]},{"t":-48,"s":[-162.25,119.933,0]}],"ix":2,"l":2},"a":{"a":0,"k":[-163,100.85,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2,0.833],"y":[1,1,1]},"o":{"x":[0.7,0.7,0.167],"y":[0,0,0]},"t":-108,"s":[100,100,100]},{"t":-48,"s":[59,59,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":".grey900","cl":"grey900","parent":23,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[0,18.167,0],"to":[0,-1.25,0],"ti":[0,1.25,0]},{"t":-199,"s":[0,10.667,0]}],"ix":2,"l":2},"a":{"a":0,"k":[5.5,4,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-0.07,1.5],[0,-1.5],[-0.047,1.5]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":-199,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":-171,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":-141,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,3.512],[0,0.512],[3,3.512]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":-111,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]},{"t":-81,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,3.967],[0,0.967],[3,3.967]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[5.5,4],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-199,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":"Shape Layer 4","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[71,-116.083,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.7,"y":0},"t":-199,"s":[71,-101.083,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":365,"s":[71,-101.083,0],"to":[0,0,0],"ti":[16.833,-14.361,0]},{"t":405,"s":[-30,-14.917,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-239,"s":[29,29]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-199,"s":[29,38]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":365,"s":[29,36]},{"t":405,"s":[83,83]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":365,"s":[50]},{"t":405,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":21,"ty":4,"nm":".grey900","cl":"grey900","parent":1,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[71,-82.917,0],"to":[0,-1.25,0],"ti":[0,1.25,0]},{"t":-199,"s":[71,-90.417,0]}],"ix":2,"l":2},"a":{"a":0,"k":[5.5,4,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-0.07,1.5],[0,-1.5],[-0.047,1.5]],"c":false}]},{"t":-199,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[5.5,4],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":-199,"st":-255,"bm":0},{"ddd":0,"ind":22,"ty":4,"nm":"device frame mask","parent":24,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,1.167,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":23,"ty":4,"nm":".blue400","cl":"blue400","parent":18,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[100.25,-115.167,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-199,"s":[100.25,-100.167,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.7,"y":0},"t":-159,"s":[100.25,-105.667,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":365,"s":[100.25,-100.167,0],"to":[0,0,0],"ti":[16.833,-14.361,0]},{"t":405,"s":[-0.75,-14,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-239,"s":[29,29]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-199,"s":[29,38]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":365,"s":[29,36]},{"t":405,"s":[83,83]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":365,"s":[50]},{"t":405,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":24,"ty":3,"nm":"device frame mask 5","parent":18,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":-165,"op":6.00000000000001,"st":-271,"bm":0},{"ddd":0,"ind":28,"ty":4,"nm":"device frame mask 9","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-29.25,-0.917,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-181,"op":-62,"st":-181,"bm":0},{"ddd":0,"ind":29,"ty":4,"nm":".blue400","cl":"blue400","parent":23,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":-145,"s":[50]},{"t":-75,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-165,"s":[0,0]},{"t":-75,"s":[94,94]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":73,"s":[50]},{"t":113,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-181,"op":-62,"st":-181,"bm":0},{"ddd":0,"ind":30,"ty":4,"nm":"device frame mask 8","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-29.25,-0.917,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-211,"op":-92,"st":-211,"bm":0},{"ddd":0,"ind":31,"ty":4,"nm":".blue400","cl":"blue400","parent":23,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":-165,"s":[50]},{"t":-95,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-195,"s":[0,0]},{"t":-105,"s":[94,94]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":43,"s":[50]},{"t":83,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-211,"op":-92,"st":-211,"bm":0},{"ddd":0,"ind":32,"ty":4,"nm":"device frame mask 7","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-29.25,-0.917,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-241,"op":-122,"st":-241,"bm":0},{"ddd":0,"ind":33,"ty":4,"nm":".blue400","cl":"blue400","parent":23,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":-195,"s":[50]},{"t":-125,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-225,"s":[0,0]},{"t":-135,"s":[94,94]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":13,"s":[50]},{"t":53,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-241,"op":-122,"st":-241,"bm":0},{"ddd":0,"ind":34,"ty":4,"nm":"device frame mask 6","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-29.25,-0.917,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-271,"op":-152,"st":-271,"bm":0},{"ddd":0,"ind":35,"ty":4,"nm":".blue400","cl":"blue400","parent":23,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":-225,"s":[50]},{"t":-155,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-255,"s":[0,0]},{"t":-165,"s":[94,94]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":-17,"s":[50]},{"t":23,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-271,"op":-152,"st":-271,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]} diff --git a/packages/SystemUI/res/raw/biometricprompt_folded_base_topleft.json b/packages/SystemUI/res/raw/biometricprompt_folded_base_topleft.json new file mode 100644 index 000000000000..7351d7c38a39 --- /dev/null +++ b/packages/SystemUI/res/raw/biometricprompt_folded_base_topleft.json @@ -0,0 +1 @@ +{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"BiometricPrompt_Portrait_Base_TopLeft","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":6,"ty":3,"nm":"Null 16","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":-90,"ix":10},"p":{"a":0,"k":[170,170,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":3,"nm":"Null_Circle","parent":6,"sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-108,"s":[70.333,-88.75,0],"to":[-11.722,17.639,0],"ti":[11.722,-17.639,0]},{"t":-48,"s":[0,17.083,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".grey600","cl":"grey600","parent":7,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.501960784314,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"circle mask 3","parent":7,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"Finger_Flipped","parent":6,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[-24.98,-35.709,0],"ix":2,"l":2},"a":{"a":0,"k":[31.791,75.23,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[5.03,5.25],[-2.83,8.98],[-5.59,-0.26],[2.52,-11.02]],"o":[[-2.85,12.77],[2.07,-14.96],[1.9,-6],[1.4,8.05],[0,0]],"v":[[7.5,4.99],[-10.09,19.69],[-3.59,-16.61],[8.69,-24.92],[7.5,5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.760784373564,0.478431402468,0.400000029919,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[27.8,24.94],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-7.01,22.23],[-1.2,-27.39],[4.09,-26.79],[15.73,14.18]],"o":[[5.64,-17.93],[2.45,56.06],[-22.4,-1.77],[17.73,-51.82]],"v":[[-7.57,-66.9],[30.82,-44.76],[26.65,75.23],[-31.78,50.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.678431372549,0.403921598547,0.305882352941,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[31.79,75.23],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"circle mask 7","parent":7,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":".grey600","cl":"grey600","parent":7,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.25,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[114.218,-17.096],[-112.938,-17.096]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.501960784314,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":36.9,"ix":2},"o":{"a":0,"k":114.2,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":"circle mask","parent":7,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":".grey900","cl":"grey900","parent":7,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.5,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[114.218,-17.096],[-112.938,-17.096]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":"circle mask 6","parent":7,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":".grey900","cl":"grey900","parent":7,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":377,"s":[-180]},{"t":417,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":377,"s":[-1.137,1.771,0],"to":[0.375,0,0],"ti":[-0.375,0,0]},{"t":417,"s":[1.113,1.771,0]}],"ix":2,"l":2},"a":{"a":0,"k":[6.238,5.063,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":77,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,-4.637],[-10.23,-3.195],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":107,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":137,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,-4.637],[-10.23,-3.195],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":167,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":197,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,-4.637],[-10.23,-3.195],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.7,"y":0},"t":232,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":562,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"t":602,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-4.546,-0.421],[-5.988,1.021],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[6.238,5.063],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":17,"ty":4,"nm":"circle mask 2","parent":7,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":".blue400","cl":"blue400","parent":7,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,8.308,0],"ix":2,"l":2},"a":{"a":0,"k":[41.706,20.979,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[18.645,0],[0,18.645]],"o":[[0,18.645],[-18.644,0],[0,0]],"v":[[33.76,-16.88],[-0.001,16.88],[-33.76,-16.88]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[41.706,17.13],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[22.896,0],[0,22.896]],"o":[[0,22.896],[-22.896,0],[0,0]],"v":[[41.457,-20.729],[-0.001,20.729],[-41.457,-20.729]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[41.706,20.979],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":"circle mask 4","parent":7,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":20,"ty":1,"nm":".grey900","cl":"grey900","parent":7,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,66,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[52,52,100],"ix":6,"l":2}},"ao":0,"sw":412,"sh":300,"sc":"#202124","ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":21,"ty":4,"nm":"circle mask 5","parent":7,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":22,"ty":1,"nm":".black","cl":"black","parent":7,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,-17.333,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[72,72,100],"ix":6,"l":2}},"ao":0,"sw":412,"sh":300,"sc":"#000000","ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":23,"ty":4,"nm":".grey800","cl":"grey800","parent":6,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-108,"s":[-192.25,99.933,0],"to":[5,3.333,0],"ti":[-5,-3.333,0]},{"t":-48,"s":[-162.25,119.933,0]}],"ix":2,"l":2},"a":{"a":0,"k":[-163,100.85,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2,0.833],"y":[1,1,1]},"o":{"x":[0.7,0.7,0.167],"y":[0,0,0]},"t":-108,"s":[100,100,100]},{"t":-48,"s":[59,59,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":24,"ty":4,"nm":".grey900","cl":"grey900","parent":23,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[100.25,-87.156,0],"to":[0,-1.25,0],"ti":[0,1.25,0]},{"t":-199,"s":[100.25,-94.656,0]}],"ix":2,"l":2},"a":{"a":0,"k":[5.5,4,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-0.07,1.5],[0,-1.5],[-0.047,1.5]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":-199,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":-171,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":-141,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,3.512],[0,0.512],[3,3.512]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":-111,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]},{"t":-81,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,3.967],[0,0.967],[3,3.967]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[5.5,4],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-199,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":25,"ty":4,"nm":"Shape Layer 4","parent":6,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[71,-116.083,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.7,"y":0},"t":-199,"s":[71,-101.083,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":365,"s":[71,-101.083,0],"to":[0,0,0],"ti":[16.833,-14.361,0]},{"t":405,"s":[-30,-14.917,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-239,"s":[29,29]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-199,"s":[29,38]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":365,"s":[29,36]},{"t":405,"s":[83,83]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":365,"s":[50]},{"t":405,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":26,"ty":4,"nm":".grey900","cl":"grey900","parent":6,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[71,-82.917,0],"to":[0,-1.25,0],"ti":[0,1.25,0]},{"t":-199,"s":[71,-90.417,0]}],"ix":2,"l":2},"a":{"a":0,"k":[5.5,4,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-0.07,1.5],[0,-1.5],[-0.047,1.5]],"c":false}]},{"t":-199,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[5.5,4],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":-199,"st":-255,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]} diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index ecb567961c1f..5e82f6d5090f 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Kan nie gesig herken nie"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Gebruik eerder vingerafdruk"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth gekoppel."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Batterypersentasie is onbekend."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Gekoppel aan <xliff:g id="BLUETOOTH">%s</xliff:g>."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Helderheid"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Kleuromkering"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Kleurregstelling"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Bestuur gebruikers"</string> <string name="quick_settings_done" msgid="2163641301648855793">"Klaar"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Maak toe"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"Gekoppel"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Wanneer jy ’n program deel, opneem of uitsaai, het <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> toegang tot enigiets wat in daardie program sigbaar is of daarin gespeel word. Wees dus versigtig met wagwoorde, betalingbesonderhede, boodskappe of ander sensitiewe inligting."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Gaan voort"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Deel of neem ’n program op"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Vee alles uit"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Bestuur"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Geskiedenis"</string> diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index 19d73b7e6ba2..c0a23d904b39 100644 --- a/packages/SystemUI/res/values-am/strings.xml +++ b/packages/SystemUI/res/values-am/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"መልክን መለየት አልተቻለም"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"በምትኩ የጣት አሻራን ይጠቀሙ"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ብሉቱዝ ተያይዟል።"</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"የባትሪ መቶኛ አይታወቅም።"</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"ከ<xliff:g id="BLUETOOTH">%s</xliff:g> ጋር ተገናኝቷል።"</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"ብሩህነት"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"ተቃራኒ ቀለም"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"የቀለም ማስተካከያ"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"ተጠቃሚዎችን ያስተዳድሩ"</string> <string name="quick_settings_done" msgid="2163641301648855793">"ተከናውኗል"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"ዝጋ"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"ተገናኝቷል"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"አንድን መተግበሪያ ሲያጋሩ፣ ሲቀርጹ ወይም cast ሲያደርጉ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> በዚያ መተግበሪያ ላይ ለሚታይ ወይም ለሚጫወት ማንኛውም ነገር መዳረሻ አለው። ስለዚህ በይለፍ ቃላት፣ በክፍያ ዝርዝሮች፣ በመልዕክቶች ወይም በሌሎች ልዩ ጥንቃቄ የሚያስፈልጋቸው መረጃዎች ላይ ጥንቃቄ ያድርጉ።"</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"ቀጥል"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"መተግበሪያ ያጋሩ ወይም ይቅረጹ"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"ሁሉንም አጽዳ"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"ያቀናብሩ"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"ታሪክ"</string> diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index d3bee6f815f0..7f1b3c991707 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"يتعذّر التعرّف على الوجه."</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"يمكنك استخدام بصمة إصبعك."</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"تم توصيل البلوتوث."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"نسبة شحن البطارية غير معروفة."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"متصل بـ <xliff:g id="BLUETOOTH">%s</xliff:g>."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"السطوع"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"قلب الألوان"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"تصحيح الألوان"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"إدارة المستخدمين"</string> <string name="quick_settings_done" msgid="2163641301648855793">"تم"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"إغلاق"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"متصل"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"أثناء مشاركة محتوى تطبيق أو تسجيله أو بثه، يمكن لتطبيق <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> الوصول إلى كل العناصر المعروضة أو التي يتم تشغيلها في ذلك التطبيق، لذا يُرجى توخي الحذر بشأن كلمات المرور أو تفاصيل الدفع أو الرسائل أو المعلومات الحساسة الأخرى."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"متابعة"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"مشاركة محتوى تطبيق أو تسجيله"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"محو الكل"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"إدارة"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"السجلّ"</string> diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml index 9045f77df46d..5dfe17df5a8c 100644 --- a/packages/SystemUI/res/values-as/strings.xml +++ b/packages/SystemUI/res/values-as/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"মুখাৱয়ব চিনিব নোৱাৰি"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"ইয়াৰ সলনি ফিংগাৰপ্ৰিণ্ট ব্যৱহাৰ কৰক"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ব্লুটুথ সংযোগ হ’ল।"</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"বেটাৰীৰ চাৰ্জৰ শতাংশ অজ্ঞাত।"</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>ৰ লগত সংযোগ কৰা হ’ল।"</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"উজ্জ্বলতা"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"ৰং বিপৰীতকৰণ"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"ৰং শুধৰণী"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"ব্যৱহাৰকাৰী পৰিচালনা কৰক"</string> <string name="quick_settings_done" msgid="2163641301648855793">"সম্পন্ন কৰা হ’ল"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"বন্ধ কৰক"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"সংযোগ কৰা হ’ল"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"আপুনি শ্বেয়াৰ কৰা, ৰেকৰ্ড কৰা অথবা কাষ্ট কৰাৰ সময়ত, সেইটো এপত দৃশ্যমান যিকোনো বস্তু অথবা আপোনাৰ ডিভাইচত প্লে’ কৰা যিকোনো সমললৈ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>ৰ এক্সেছ থাকে। গতিকে, পাছৱৰ্ড, পৰিশোধৰ সবিশেষ, বাৰ্তা অথবা অন্য সংবেদনশীল তথ্যৰ ক্ষেত্ৰত সাৱধান হওক।"</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"অব্যাহত ৰাখক"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"এটা এপ্ শ্বেয়াৰ অথবা ৰেকৰ্ড কৰক"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"আটাইবোৰ মচক"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"পৰিচালনা"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"ইতিহাস"</string> diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml index 041ec59e1e7d..feab7f0bdb6a 100644 --- a/packages/SystemUI/res/values-az/strings.xml +++ b/packages/SystemUI/res/values-az/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Üzü tanımaq olmur"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Barmaq izi istifadə edin"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth qoşulub."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Batareyanın faizi naməlumdur."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> üzərindən qoşuldu."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Parlaqlıq"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Rəng inversiyası"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Rəng korreksiyası"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"İstifadəçiləri idarə edin"</string> <string name="quick_settings_done" msgid="2163641301648855793">"Hazır"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Bağlayın"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"Qoşulu"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Paylaşdığınız, qeydə aldığınız və ya yayımladığınız zaman <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> tətbiqi həmin tətbiqdə göstərilən və ya oxudulan hər şeyə giriş edə bilir. Odur ki, parollar, ödəniş detalları, mesajlar və ya digər həssas məlumatlarla bağlı diqqətli olun."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Davam edin"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Tətbiqi paylaşın və ya qeydə alın"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Hamısını silin"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"İdarə edin"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Tarixçə"</string> diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml index f724edd39a06..efed08fc07b8 100644 --- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml +++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Lice nije prepoznato"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Koristite otisak prsta"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth je priključen."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Procenat napunjenosti baterije nije poznat."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Povezani ste sa <xliff:g id="BLUETOOTH">%s</xliff:g>."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Osvetljenost"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inverzija boja"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Korekcija boja"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Upravljajte korisnicima"</string> <string name="quick_settings_done" msgid="2163641301648855793">"Gotovo"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Zatvori"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"Povezan"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Kada delite, snimate ili prebacujete aplikaciju, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ima pristup kompletnom sadržaju koji je vidljiv ili se pušta u toj aplikaciji. Budite pažljivi sa lozinkama, informacijama o plaćanju, porukama ili drugim osetljivim informacijama."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Nastavi"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Delite ili snimite aplikaciju"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Obriši sve"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Upravljajte"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Istorija"</string> diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml index 163335f62fd7..cc37204e49ea 100644 --- a/packages/SystemUI/res/values-be/strings.xml +++ b/packages/SystemUI/res/values-be/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Твар не распазнаны"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Скарыстайце адбітак пальца"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth-сувязь."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Працэнт зараду акумулятара невядомы."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Падлучаны да <xliff:g id="BLUETOOTH">%s</xliff:g>."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Яркасць"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Інверсія колераў"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Карэкцыя колераў"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Кіраваць карыстальнікамі"</string> <string name="quick_settings_done" msgid="2163641301648855793">"Гатова"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Закрыць"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"Падлучана"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Калі пачынаецца абагульванне, запіс ці трансляцыя змесціва праграмы, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> атрымлівае доступ да ўсяго змесціва, якое паказваецца ці прайграецца ў праграме. Таму прадухіліце паказ пароляў, плацежных рэквізітаў, паведамленняў і іншай канфідэнцыяльнай інфармацыі."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Далей"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Абагульванне або запіс праграмы"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Ачысціць усё"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Кіраваць"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Гісторыя"</string> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index 60d8c133af0f..5a6ad7336531 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Лицето не е разпознато"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Използвайте отпечатък"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth е включен."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Процентът на батерията е неизвестен."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Има връзка с <xliff:g id="BLUETOOTH">%s</xliff:g>."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Яркост"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Цветове: инверт."</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Корекция на цветове"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Управление на потребителите"</string> <string name="quick_settings_done" msgid="2163641301648855793">"Готово"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Затваряне"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"Установена е връзка"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Когато споделяте, записвате или предавате, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> има достъп до всичко, което се показва или възпроизвежда в това приложение, затова бъдете внимателни с пароли, подробности за начини на плащане, съобщения или друга поверителна информация."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Напред"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Споделяне или записване на приложение"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Изчистване на всички"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Управление"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"История"</string> diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml index e43e8cb18147..9533963b70ae 100644 --- a/packages/SystemUI/res/values-bn/strings.xml +++ b/packages/SystemUI/res/values-bn/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"ফেস শনাক্ত করা যায়নি"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"পরিবর্তে ফিঙ্গারপ্রিন্ট ব্যবহার করুন"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ব্লুটুথ সংযুক্ত হয়েছে৷"</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"ব্যাটারি কত শতাংশ আছে তা জানা যায়নি।"</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>এ সংযুক্ত হয়ে আছে।"</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"উজ্জ্বলতা"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"কালার ইনভার্সন"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"রঙ সংশোধন"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"ব্যবহারকারীদের ম্যানেজ করুন"</string> <string name="quick_settings_done" msgid="2163641301648855793">"সম্পন্ন হয়েছে"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"বন্ধ করুন"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"সংযুক্ত হয়েছে"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"কোনও অ্যাপ আপনার শেয়ার করা, রেকর্ড করা বা কাস্ট করার সময়, সেই অ্যাপে দেখা যায় বা খেলা হয় এমন সব কিছু অ্যাক্সেস করার অনুমতি <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>-এর আছে। তাই পাসওয়ার্ড, পেমেন্টের বিবরণ, মেসেজ বা অন্য সংবেদনশীল তথ্য সম্পর্কে সতর্ক থাকুন।"</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"চালিয়ে যান"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"অ্যাপ শেয়ার বা রেকর্ড করা"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"সবকিছু সাফ করুন"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"পরিচালনা করুন"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"ইতিহাস"</string> diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml index a0ebffa067d3..69b093935fc9 100644 --- a/packages/SystemUI/res/values-bs/strings.xml +++ b/packages/SystemUI/res/values-bs/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Nije moguće prepoznati lice"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Koristite otisak prsta"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth je povezan."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Postotak napunjenosti baterije nije poznat"</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Povezan na <xliff:g id="BLUETOOTH">%s</xliff:g>."</string> @@ -373,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Kada aplikaciju dijelite, snimate ili emitirate, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ima pristup svemu što se prikazuje ili reproducira u toj aplikaciji. Zato budite oprezni s lozinkama, detaljima o plaćanju, porukama i drugim osjetljivim informacijama."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Nastavi"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Dijelite ili snimite aplikaciju"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Očisti sve"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Upravljajte"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Historija"</string> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index 327f50f48f4f..e99261502a53 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"No es reconeix la cara"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Utilitza l\'empremta digital"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth connectat."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Es desconeix el percentatge de bateria."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"S\'ha connectat a <xliff:g id="BLUETOOTH">%s</xliff:g>."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brillantor"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversió de colors"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Correcció de color"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Gestiona els usuaris"</string> <string name="quick_settings_done" msgid="2163641301648855793">"Fet"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Tanca"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"Connectat"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Quan estàs compartint, gravant o emetent, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> té accés a qualsevol cosa que es vegi a la pantalla o que es reprodueixi a l\'aplicació. Per aquest motiu, ves amb compte amb les contrasenyes, les dades de pagament, els missatges o altra informació sensible."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Continua"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Comparteix o grava una aplicació"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Esborra-ho tot"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Gestiona"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Historial"</string> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index fdc3139bc020..56b91856d60b 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Obličej nelze rozpoznat"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Použijte otisk prstu"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Rozhraní Bluetooth je připojeno."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Procento baterie není známé."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Připojeno k zařízení <xliff:g id="BLUETOOTH">%s</xliff:g>."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Jas"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Převrácení barev"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Korekce barev"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Správa uživatelů"</string> <string name="quick_settings_done" msgid="2163641301648855793">"Hotovo"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Zavřít"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"Připojeno"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Když sdílíte, nahráváte nebo odesíláte aplikaci, aplikace <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> má přístup k veškerému obsahu, který je v této aplikaci zobrazen nebo přehráván. Dejte proto pozor na hesla, platební údaje, zprávy nebo jiné citlivé informace."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Pokračovat"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Sdílení nebo nahrání aplikace"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Smazat vše"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Spravovat"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Historie"</string> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index bf0ac5b55b20..c97705815c5b 100644 --- a/packages/SystemUI/res/values-da/strings.xml +++ b/packages/SystemUI/res/values-da/strings.xml @@ -161,13 +161,15 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Hvis du angiver et forkert mønster i næste forsøg, slettes din arbejdsprofil og de tilhørende data."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Hvis du angiver en forkert pinkode i næste forsøg, slettes din arbejdsprofil og de tilhørende data."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Hvis du angiver en forkert adgangskode i næste forsøg, slettes din arbejdsprofil og de tilhørende data."</string> - <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Sæt fingeren på fingeraftrykslæseren"</string> + <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Sæt fingeren på fingeraftrykssensoren"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ikon for fingeraftryk"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Ansigtet kan ikke genkendes. Brug fingeraftryk i stedet."</string> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Ansigt kan ikke genkendes"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Brug fingeraftryk i stedet"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth tilsluttet."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Batteriniveauet er ukendt."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Tilsluttet <xliff:g id="BLUETOOTH">%s</xliff:g>."</string> @@ -373,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Når du deler, optager eller caster en app, har <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> adgang til alt, der vises eller afspilles i den pågældende app. Vær derfor forsigtig med adgangskoder, betalingsoplysninger, beskeder og andre følsomme oplysninger."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Fortsæt"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Del eller optag en app"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Ryd alle"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Administrer"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Historik"</string> @@ -908,11 +920,11 @@ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Der er problemer med at aflæse dit batteriniveau"</string> <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Tryk for at få flere oplysninger"</string> <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Ingen alarm er indstillet"</string> - <string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Fingeraftrykslæser"</string> + <string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Fingeraftrykssensor"</string> <string name="accessibility_authenticate_hint" msgid="798914151813205721">"godkende"</string> <string name="accessibility_enter_hint" msgid="2617864063504824834">"få adgang til enheden"</string> <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Brug fingeraftryk for at åbne"</string> - <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Godkendelse er påkrævet. Sæt fingeren på fingeraftrykslæseren for at godkende."</string> + <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Godkendelse er påkrævet. Sæt fingeren på fingeraftrykssensoren for at godkende."</string> <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Igangværende telefonopkald"</string> <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobildata"</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> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index af3e57906e05..74f9c5f855cb 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Gesicht nicht erkannt"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Fingerabdruck verwenden"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Mit Bluetooth verbunden"</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Akkustand unbekannt."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Mit <xliff:g id="BLUETOOTH">%s</xliff:g> verbunden"</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Helligkeit"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Farbumkehr"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Farbkorrektur"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Nutzer verwalten"</string> <string name="quick_settings_done" msgid="2163641301648855793">"Fertig"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Schließen"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"Verbunden"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Beim Teilen, Aufnehmen oder Übertragen einer App hat <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> Zugriff auf alle Inhalte, die in dieser App sichtbar sind oder wiedergegeben werden. Sei daher mit Passwörtern, Zahlungsdetails, Nachrichten oder anderen vertraulichen Informationen vorsichtig."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Weiter"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"App teilen oder aufnehmen"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Alle löschen"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Verwalten"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Verlauf"</string> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index 14ffda1a498b..59f645dc248b 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Αδύνατη η αναγν. προσώπου"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Χρησιμ. δακτυλ. αποτύπ."</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Το Bluetooth είναι συνδεδεμένο."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Άγνωστο ποσοστό μπαταρίας."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Συνδέθηκε στο <xliff:g id="BLUETOOTH">%s</xliff:g>."</string> @@ -373,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Όταν κάνετε κοινοποίηση, εγγραφή ή μετάδοση μιας εφαρμογής, η εφαρμογή <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> έχει πρόσβαση σε οτιδήποτε είναι ορατό ή αναπαράγεται στη συγκεκριμένη εφαρμογή. Επομένως, να είστε προσεκτικοί με τους κωδικούς πρόσβασης, τα στοιχεία πληρωμής, τα μηνύματα ή άλλες ευαίσθητες πληροφορίες."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Συνέχεια"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Κοινοποίηση ή εγγραφή εφαρμογής"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Διαγραφή όλων"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Διαχείριση"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Ιστορικό"</string> diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml index 58db4dd370f1..19845f4dbdaa 100644 --- a/packages/SystemUI/res/values-en-rAU/strings.xml +++ b/packages/SystemUI/res/values-en-rAU/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Can’t recognise face"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Use fingerprint instead"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth connected."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Battery percentage unknown."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Connected to <xliff:g id="BLUETOOTH">%s</xliff:g>."</string> @@ -373,6 +375,11 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"When you\'re sharing, recording or casting an app, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> has access to anything shown or played on that app. So, be careful with passwords, payment details, messages or other sensitive information."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Continue"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Share or record an app"</string> + <string name="media_projection_permission_dialog_system_service_title" msgid="6827129613741303726">"Allow this app to share or record?"</string> + <string name="media_projection_permission_dialog_system_service_warning_entire_screen" msgid="8801616203805837575">"When you\'re sharing, recording or casting, this app has access to anything visible on your screen or played on your device. So be careful with passwords, payment details, messages or other sensitive information."</string> + <string name="media_projection_permission_dialog_system_service_warning_single_app" msgid="543310680568419338">"When you\'re sharing, recording or casting an app, this app has access to anything shown or played on that app. So be careful with passwords, payment details, messages or other sensitive information."</string> + <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Blocked by your IT admin"</string> + <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Screen capturing is disabled by device policy"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Clear all"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Manage"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"History"</string> diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml index 7be5b1554b23..615e8b61f6ab 100644 --- a/packages/SystemUI/res/values-en-rCA/strings.xml +++ b/packages/SystemUI/res/values-en-rCA/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Can’t recognise face"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Use fingerprint instead"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth connected."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Battery percentage unknown."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Connected to <xliff:g id="BLUETOOTH">%s</xliff:g>."</string> @@ -373,6 +375,11 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"When you\'re sharing, recording or casting an app, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> has access to anything shown or played on that app. So, be careful with passwords, payment details, messages or other sensitive information."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Continue"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Share or record an app"</string> + <string name="media_projection_permission_dialog_system_service_title" msgid="6827129613741303726">"Allow this app to share or record?"</string> + <string name="media_projection_permission_dialog_system_service_warning_entire_screen" msgid="8801616203805837575">"When you\'re sharing, recording or casting, this app has access to anything visible on your screen or played on your device. So be careful with passwords, payment details, messages or other sensitive information."</string> + <string name="media_projection_permission_dialog_system_service_warning_single_app" msgid="543310680568419338">"When you\'re sharing, recording or casting an app, this app has access to anything shown or played on that app. So be careful with passwords, payment details, messages or other sensitive information."</string> + <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Blocked by your IT admin"</string> + <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Screen capturing is disabled by device policy"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Clear all"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Manage"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"History"</string> diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml index 58db4dd370f1..19845f4dbdaa 100644 --- a/packages/SystemUI/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/res/values-en-rGB/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Can’t recognise face"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Use fingerprint instead"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth connected."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Battery percentage unknown."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Connected to <xliff:g id="BLUETOOTH">%s</xliff:g>."</string> @@ -373,6 +375,11 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"When you\'re sharing, recording or casting an app, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> has access to anything shown or played on that app. So, be careful with passwords, payment details, messages or other sensitive information."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Continue"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Share or record an app"</string> + <string name="media_projection_permission_dialog_system_service_title" msgid="6827129613741303726">"Allow this app to share or record?"</string> + <string name="media_projection_permission_dialog_system_service_warning_entire_screen" msgid="8801616203805837575">"When you\'re sharing, recording or casting, this app has access to anything visible on your screen or played on your device. So be careful with passwords, payment details, messages or other sensitive information."</string> + <string name="media_projection_permission_dialog_system_service_warning_single_app" msgid="543310680568419338">"When you\'re sharing, recording or casting an app, this app has access to anything shown or played on that app. So be careful with passwords, payment details, messages or other sensitive information."</string> + <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Blocked by your IT admin"</string> + <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Screen capturing is disabled by device policy"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Clear all"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Manage"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"History"</string> diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml index 58db4dd370f1..19845f4dbdaa 100644 --- a/packages/SystemUI/res/values-en-rIN/strings.xml +++ b/packages/SystemUI/res/values-en-rIN/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Can’t recognise face"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Use fingerprint instead"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth connected."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Battery percentage unknown."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Connected to <xliff:g id="BLUETOOTH">%s</xliff:g>."</string> @@ -373,6 +375,11 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"When you\'re sharing, recording or casting an app, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> has access to anything shown or played on that app. So, be careful with passwords, payment details, messages or other sensitive information."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Continue"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Share or record an app"</string> + <string name="media_projection_permission_dialog_system_service_title" msgid="6827129613741303726">"Allow this app to share or record?"</string> + <string name="media_projection_permission_dialog_system_service_warning_entire_screen" msgid="8801616203805837575">"When you\'re sharing, recording or casting, this app has access to anything visible on your screen or played on your device. So be careful with passwords, payment details, messages or other sensitive information."</string> + <string name="media_projection_permission_dialog_system_service_warning_single_app" msgid="543310680568419338">"When you\'re sharing, recording or casting an app, this app has access to anything shown or played on that app. So be careful with passwords, payment details, messages or other sensitive information."</string> + <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Blocked by your IT admin"</string> + <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Screen capturing is disabled by device policy"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Clear all"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Manage"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"History"</string> diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml index 3fbbe617b8d2..b028bf360cbd 100644 --- a/packages/SystemUI/res/values-en-rXC/strings.xml +++ b/packages/SystemUI/res/values-en-rXC/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Can’t recognize face"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Use fingerprint instead"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth connected."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Battery percentage unknown."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Connected to <xliff:g id="BLUETOOTH">%s</xliff:g>."</string> @@ -373,6 +375,11 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"When you\'re sharing, recording, or casting an app, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> has access to anything shown or played on that app. So be careful with passwords, payment details, messages, or other sensitive information."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Continue"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Share or record an app"</string> + <string name="media_projection_permission_dialog_system_service_title" msgid="6827129613741303726">"Allow this app to share or record?"</string> + <string name="media_projection_permission_dialog_system_service_warning_entire_screen" msgid="8801616203805837575">"When you\'re sharing, recording, or casting, this app has access to anything visible on your screen or played on your device. So be careful with passwords, payment details, messages, or other sensitive information."</string> + <string name="media_projection_permission_dialog_system_service_warning_single_app" msgid="543310680568419338">"When you\'re sharing, recording, or casting an app, this app has access to anything shown or played on that app. So be careful with passwords, payment details, messages, or other sensitive information."</string> + <string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Blocked by your IT admin"</string> + <string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"Screen capturing is disabled by device policy"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Clear all"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Manage"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"History"</string> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index 65234a8cfb3e..696737953a8b 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"No se reconoce el rostro"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Usa la huella dactilar"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth conectado"</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Se desconoce el porcentaje de la batería."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Conectado a <xliff:g id="BLUETOOTH">%s</xliff:g>"</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brillo"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Invertir colores"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Corregir colores"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Administrar usuarios"</string> <string name="quick_settings_done" msgid="2163641301648855793">"Listo"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Cerrar"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"Conectado"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Cuando compartas, grabes o transmitas una app, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> podrá acceder a todo el contenido que se muestre o reproduzca en ella. Por lo tanto, debes tener cuidado con contraseñas, detalles de pagos, mensajes y otra información sensible."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Continuar"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Compartir o grabar una app"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Borrar todo"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Administrar"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Historial"</string> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index 1334add2a4e9..cbce6bfb5c5d 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"No se reconoce la cara"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Usa la huella digital"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth conectado"</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Porcentaje de batería desconocido."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Conectado a <xliff:g id="BLUETOOTH">%s</xliff:g>."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brillo"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Invertir colores"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Corrección de color"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Gestionar usuarios"</string> <string name="quick_settings_done" msgid="2163641301648855793">"Hecho"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Cerrar"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"Conectado"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Cuando compartas, grabes o envíes una aplicación, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> podrá acceder a todo lo que muestre o reproduzca la aplicación. Debes tener cuidado con contraseñas, detalles de pagos, mensajes o cualquier otra información sensible."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Continuar"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Compartir o grabar una aplicación"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Borrar todo"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Gestionar"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Historial"</string> diff --git a/packages/SystemUI/res/values-es/tiles_states_strings.xml b/packages/SystemUI/res/values-es/tiles_states_strings.xml index d7a8133d3741..fe4cbedb6b36 100644 --- a/packages/SystemUI/res/values-es/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-es/tiles_states_strings.xml @@ -78,8 +78,8 @@ </string-array> <string-array name="tile_states_location"> <item msgid="3316542218706374405">"No disponible"</item> - <item msgid="4813655083852587017">"Desactivado"</item> - <item msgid="6744077414775180687">"Activado"</item> + <item msgid="4813655083852587017">"Desactivada"</item> + <item msgid="6744077414775180687">"Activada"</item> </string-array> <string-array name="tile_states_hotspot"> <item msgid="3145597331197351214">"No disponible"</item> diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml index ee7ff292aac7..44812de671c7 100644 --- a/packages/SystemUI/res/values-et/strings.xml +++ b/packages/SystemUI/res/values-et/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Nägu ei õnnestu tuvastada"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Kasutage sõrmejälge"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth on ühendatud."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Aku laetuse protsent on teadmata."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Ühendatud: <xliff:g id="BLUETOOTH">%s</xliff:g>."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Heledus"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Värvide ümberpööramine"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Värviparandus"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Kasutajate haldamine"</string> <string name="quick_settings_done" msgid="2163641301648855793">"Valmis"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Sule"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"Ühendatud"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Kui jagate, salvestate või kannate rakendust üle, on rakendusel <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> juurdepääs kõigele, mida selles rakenduses kuvatakse või esitatakse. Seega olge paroolide, makseteabe, sõnumite ja muu tundliku teabega ettevaatlik."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Jätka"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Rakenduse jagamine või salvestamine"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Tühjenda kõik"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Haldamine"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Ajalugu"</string> diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml index d6de14770bc3..45b4cd66c322 100644 --- a/packages/SystemUI/res/values-eu/strings.xml +++ b/packages/SystemUI/res/values-eu/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Ezin da ezagutu aurpegia"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Erabili hatz-marka"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetootha konektatuta."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Bateriaren ehunekoa ezezaguna da."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> gailura konektatuta."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Distira"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Kolore-alderantzikatzea"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Koloreen zuzenketa"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Kudeatu erabiltzaileak"</string> <string name="quick_settings_done" msgid="2163641301648855793">"Eginda"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Itxi"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"Konektatuta"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Aplikazio bat partekatzen, grabatzen edo igortzen ari zarenean, aplikazio horretan ikusgai dagoen edo bertan erreproduzitzen ari den guztirako sarbidea du <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> aplikazioak. Beraz, kontuz ibili pasahitzekin, ordainketen xehetasunekin, mezuekin edo bestelako kontuzko informazioarekin."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Egin aurrera"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Partekatu edo grabatu aplikazioak"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Garbitu guztiak"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Kudeatu"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Historia"</string> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index ba820f16ee03..a50472081322 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"چهره شناسایی نشد"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"از اثر انگشت استفاده کنید"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"بلوتوث متصل است."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"درصد شارژ باتری مشخص نیست."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"به <xliff:g id="BLUETOOTH">%s</xliff:g> متصل شد."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"روشنایی"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"وارونگی رنگ"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"تصحیح رنگ"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"مدیریت کاربران"</string> <string name="quick_settings_done" msgid="2163641301648855793">"تمام"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"بستن"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"متصل"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"وقتی درحال همرسانی، ضبط، یا پخش محتوای برنامهای هستید، <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> به همه محتوایی که در آن برنامه نمایان است یا پخش میشود دسترسی دارد. بنابراین مراقب گذرواژهها، جزئیات پرداخت، پیامها، یا دیگر اطلاعات حساس باشید."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"ادامه"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"همرسانی یا ضبط برنامه"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"پاک کردن همه موارد"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"مدیریت"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"سابقه"</string> diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index 4859ac7cc1b0..ba8bfe0c808f 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Kasvoja ei voi tunnistaa"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Käytä sormenjälkeä"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth yhdistetty."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Akun varaustaso ei tiedossa."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Yhteys: <xliff:g id="BLUETOOTH">%s</xliff:g>."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Kirkkaus"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Käänteiset värit"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Värinkorjaus"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Ylläpidä käyttäjiä"</string> <string name="quick_settings_done" msgid="2163641301648855793">"Valmis"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Sulje"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"Yhdistetty"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Kun jaat, tallennat tai striimaat sovellusta, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> saa pääsyn kaikkeen sovelluksessa näkyvään tai toistettuun sisältöön. Ole siis varovainen, kun lisäät salasanoja, maksutietoja, viestejä tai muita arkaluontoisia tietoja."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Jatka"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Jaa sovellus tai tallenna sen sisältöä"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Tyhjennä kaikki"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Muuta asetuksia"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Historia"</string> diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml index a2bd1c192a90..8b183bf222dc 100644 --- a/packages/SystemUI/res/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Visage non reconnu"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Utiliser l\'empreinte digitale"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth connecté"</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Pourcentage de la pile inconnu."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Connecté à : <xliff:g id="BLUETOOTH">%s</xliff:g>"</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Luminosité"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversion des couleurs"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Correction des couleurs"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Gérer les utilisateurs"</string> <string name="quick_settings_done" msgid="2163641301648855793">"Terminé"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Fermer"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"Connecté"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Lorsque vous partagez, enregistrez ou diffusez une application, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> a accès à tout ce qui est affiché ou lu sur cette application. Par conséquent, soyez prudent avec les mots de passe, les détails du paiement, les messages ou toute autre information confidentielle."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Continuer"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Partager ou enregistrer une application"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Tout effacer"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Gérer"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Historique"</string> @@ -608,8 +619,8 @@ <string name="accessibility_status_bar_headset" msgid="2699275863720926104">"Écouteurs connectés"</string> <string name="data_saver" msgid="3484013368530820763">"Économiseur de données"</string> <string name="accessibility_data_saver_on" msgid="5394743820189757731">"La fonction Économiseur de données est activée"</string> - <string name="switch_bar_on" msgid="1770868129120096114">"Activé"</string> - <string name="switch_bar_off" msgid="5669805115416379556">"Désactivé"</string> + <string name="switch_bar_on" msgid="1770868129120096114">"Activée"</string> + <string name="switch_bar_off" msgid="5669805115416379556">"Désactivée"</string> <string name="tile_unavailable" msgid="3095879009136616920">"Non disponible"</string> <string name="accessibility_tile_disabled_by_policy_action_description" msgid="6958422730461646926">"En savoir plus"</string> <string name="nav_bar" msgid="4642708685386136807">"Barre de navigation"</string> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index 3909099f8687..f5bcfb37656b 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Visage non reconnu"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Utilisez empreinte digit."</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth connecté"</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Pourcentage de la batterie inconnu."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Connecté à : <xliff:g id="BLUETOOTH">%s</xliff:g>"</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Luminosité"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversion des couleurs"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Correction des couleurs"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Gérer les utilisateurs"</string> <string name="quick_settings_done" msgid="2163641301648855793">"OK"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Fermer"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"Connecté"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Lorsque vous partagez, enregistrez ou castez une appli, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> a accès à tout ce qui est visible sur votre écran ou lu sur votre appareil. Faites donc attention à vos mots de passe, détails de mode de paiement, messages ou autres informations sensibles."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Continuer"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Partager ou enregistrer une appli"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Tout effacer"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Gérer"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Historique"</string> diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml index 0e1628e246c1..4b1809be5d2e 100644 --- a/packages/SystemUI/res/values-gl/strings.xml +++ b/packages/SystemUI/res/values-gl/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Non se recoñeceu a cara"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Usa a impresión dixital"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth conectado"</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Descoñécese a porcentaxe da batería."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Conectado a <xliff:g id="BLUETOOTH">%s</xliff:g>."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brillo"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversión da cor"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Corrección da cor"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Administrar usuarios"</string> <string name="quick_settings_done" msgid="2163641301648855793">"Feito"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Pechar"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"Conectado"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Cando compartes, gravas ou emites unha aplicación, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ten acceso a todo o que se vexa ou se reproduza nela. Polo tanto, debes ter coidado cos contrasinais, os detalles de pago, as mensaxes ou outra información confidencial."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Continuar"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Compartir ou gravar unha aplicación"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Eliminar todas"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Xestionar"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Historial"</string> diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml index 76411bd28ff1..8174ce7bfa6a 100644 --- a/packages/SystemUI/res/values-gu/strings.xml +++ b/packages/SystemUI/res/values-gu/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"ચહેરો ઓળખાતો નથી"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"તો ફિંગરપ્રિન્ટ વાપરો"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"બ્લૂટૂથ કનેક્ટ થયું."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"બૅટરીની ટકાવારી અજાણ છે."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> થી કનેક્ટ થયાં."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"તેજ"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"વિપરીત રંગમાં બદલવું"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"રંગ સુધારણા"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"વપરાશકર્તાઓને મેનેજ કરો"</string> <string name="quick_settings_done" msgid="2163641301648855793">"થઈ ગયું"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"બંધ કરો"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"કનેક્ટ થયેલું"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"જ્યારે તમે કોઈ ઍપ શેર, રેકોર્ડ અથવા કાસ્ટ કરી રહ્યાં હો, ત્યારે તે ઍપ પર બતાવવામાં કે ચલાવવામાં આવતી હોય તેવી કોઈપણ વસ્તુનો ઍક્સેસ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ધરાવે છે. તેથી પાસવર્ડ, ચુકવણીની વિગતો, મેસેજ અથવા અન્ય સંવેદનશીલ માહિતીની બાબતે સાવચેત રહેશો."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"ચાલુ રાખો"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"કોઈ ઍપ શેર કરો અથવા રેકોર્ડ કરો"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"બધુ સાફ કરો"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"મેનેજ કરો"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"ઇતિહાસ"</string> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index 17ec3486c3f0..862ef343f01a 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"चेहरे की पहचान नहीं हुई"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"फ़िंगरप्रिंट इस्तेमाल करें"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ब्लूटूथ कनेक्ट किया गया."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"इस बारे में जानकारी नहीं है कि अभी बैटरी कितने प्रतिशत चार्ज है."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> से कनेक्ट किया गया."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"स्क्रीन की रोशनी"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"रंग बदलने की सुविधा"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"रंग में सुधार करने की सुविधा"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"उपयोगकर्ताओं को मैनेज करें"</string> <string name="quick_settings_done" msgid="2163641301648855793">"हो गया"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"रद्द करें"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"कनेक्ट है"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"शेयर, रिकॉर्ड या कास्ट करते समय, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> के पास उस ऐप्लिकेशन पर दिख रही हर चीज़ या उस पर चल रहे हर मीडिया का ऐक्सेस होता है. इसलिए, शेयर, रिकॉर्ड या कास्ट करते समय, पासवर्ड, पेमेंट के तरीके की जानकारी, मैसेज या किसी और संवेदनशील जानकारी को लेकर खास सावधानी बरतें."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"जारी रखें"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"ऐप्लिकेशन शेयर करें या उसकी रिकॉर्डिंग करें"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"सभी को हटाएं"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"मैनेज करें"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"इतिहास"</string> diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index 25ce0c6af94e..d7fe7d8ac4bc 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Lice nije prepoznato"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Upotrijebite otisak prsta"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth povezan."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Postotak baterije nije poznat."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Spojen na <xliff:g id="BLUETOOTH">%s</xliff:g> ."</string> @@ -373,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Kad dijelite, snimate ili emitirate aplikaciju, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ima pristup svemu što se prikazuje ili reproducira u toj aplikaciji. Stoga pazite na zaporke, podatke o plaćanju, poruke i druge osjetljive podatke."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Nastavi"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Dijeljenje ili snimanje pomoću aplikacije"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Izbriši sve"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Upravljajte"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Povijest"</string> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index 88aff2debea7..51089e7d21a1 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Az arc nem ismerhető fel"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Használjon ujjlenyomatot"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth csatlakoztatva."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Az akkumulátor töltöttségi szintje ismeretlen."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Csatlakoztatva a következőhöz: <xliff:g id="BLUETOOTH">%s</xliff:g>."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Fényerő"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Színek invertálása"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Színjavítás"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Felhasználók kezelése"</string> <string name="quick_settings_done" msgid="2163641301648855793">"Kész"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Bezárás"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"Csatlakoztatva"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Amikor Ön megoszt, rögzít vagy átküld egy alkalmazást, a(z) <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> az adott appban látható vagy lejátszott minden tartalomhoz hozzáfér. Ezért legyen elővigyázatos a jelszavakkal, a fizetési adatokkal, az üzenetekkel és más bizalmas információkkal."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Folytatás"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Alkalmazás megosztása és rögzítése"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Az összes törlése"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Kezelés"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Előzmények"</string> diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml index a9317f193367..f1d11fb6f3aa 100644 --- a/packages/SystemUI/res/values-hy/strings.xml +++ b/packages/SystemUI/res/values-hy/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Դեմքը չի ճանաչվել"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Օգտագործեք մատնահետք"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth-ը միացված է:"</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Մարտկոցի լիցքի մակարդակն անհայտ է։"</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Միացված է <xliff:g id="BLUETOOTH">%s</xliff:g>-ին:"</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Պայծառություն"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Գունաշրջում"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Գունաշտկում"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Կառավարել օգտատերերին"</string> <string name="quick_settings_done" msgid="2163641301648855793">"Պատրաստ է"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Փակել"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"Միացված է"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Երբ դուք ցուցադրում, տեսագրում կամ հեռարձակում եք որևէ հավելվածի էկրանը, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> հավելվածին հասանելի է դառնում այն ամենը, ինչ ցուցադրվում է կամ նվագարկվում այդ հավելվածում։ Հիշեք այդ մասին, երբ պատրաստվում եք դիտել կամ մուտքագրել գաղտնաբառեր, վճարային տվյալներ, հաղորդագրություններ և այլ կոնֆիդենցիալ տեղեկություններ։"</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Շարունակել"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Հավելվածի էկրանի ցուցադրում կամ տեսագրում"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Մաքրել բոլորը"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Կառավարել"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Պատմություն"</string> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index 4dbab5b37210..ac5abde1e278 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Tidak mengenali wajah"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Gunakan sidik jari"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth terhubung."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Persentase baterai tidak diketahui."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Terhubung ke <xliff:g id="BLUETOOTH">%s</xliff:g>."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Kecerahan"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversi warna"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Koreksi warna"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Kelola pengguna"</string> <string name="quick_settings_done" msgid="2163641301648855793">"Selesai"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Tutup"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"Terhubung"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Jika Anda membagikan, merekam, atau mentransmisikan suatu aplikasi, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> akan memiliki akses ke semua hal yang ditampilkan atau yang diputar di aplikasi tersebut. Jadi, berhati-hatilah saat memasukkan sandi, detail pembayaran, pesan, atau informasi sensitif lainnya."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Lanjutkan"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Bagikan atau rekam aplikasi"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Hapus semua"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Kelola"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Histori"</string> diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml index a592be893947..40c7d9087d39 100644 --- a/packages/SystemUI/res/values-is/strings.xml +++ b/packages/SystemUI/res/values-is/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Andlit þekkist ekki"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Nota fingrafar í staðinn"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth tengt."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Staða rafhlöðu óþekkt."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Tengt við <xliff:g id="BLUETOOTH">%s</xliff:g>."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Birtustig"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Umsnúningur lita"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Litaleiðrétting"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Stjórna notendum"</string> <string name="quick_settings_done" msgid="2163641301648855793">"Lokið"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Loka"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"Tengt"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Þegar þú deilir, tekur upp eða sendir út forrit hefur <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> aðgang að öllu sem sést eða spilast í viðkomandi forriti. Passaðu því upp á aðgangsorð, greiðsluupplýsingar, skilaboð eða aðrar viðkvæmar upplýsingar."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Áfram"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Deila eða taka upp forrit"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Hreinsa allt"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Stjórna"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Ferill"</string> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index 55cb9920265c..1ebbbd8f810a 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Volto non riconosciuto"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Usa l\'impronta"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth collegato."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Percentuale della batteria sconosciuta."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Connesso a <xliff:g id="BLUETOOTH">%s</xliff:g>."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Luminosità"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversione dei colori"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Correzione del colore"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Gestisci utenti"</string> <string name="quick_settings_done" msgid="2163641301648855793">"Fine"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Chiudi"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"Connesso"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Quando condividi, registri o trasmetti un\'app, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ha accesso a qualsiasi elemento visualizzato o riprodotto sull\'app. Presta quindi attenzione a password, dati di pagamento, messaggi o altre informazioni sensibili."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Continua"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Condividi o registra un\'app"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Cancella tutto"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Gestisci"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Cronologia"</string> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index e206efd3d4bf..ce8c974e09c0 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"לא ניתן לזהות את הפנים"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"שימוש בטביעת אצבע במקום זאת"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth מחובר."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"אחוז טעינת הסוללה לא ידוע."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"התבצע חיבור אל <xliff:g id="BLUETOOTH">%s</xliff:g>."</string> @@ -373,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"בזמן שיתוף, הקלטה או העברה (cast) של אפליקציה, תהיה ל-<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> גישה לכל מה שגלוי באפליקציה או מופעל מהאפליקציה. כדאי להיזהר עם סיסמאות, פרטי תשלום, הודעות או מידע רגיש אחר."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"המשך"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"שיתוף או הקלטה של אפליקציה"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"ניקוי הכול"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"ניהול"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"היסטוריה"</string> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index 281eb29d09f9..c76b20765b0b 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"顔を認識できません"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"指紋認証をお使いください"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetoothに接続済み。"</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"バッテリー残量は不明です。"</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>に接続しました。"</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"画面の明るさ"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"色反転"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"色補正"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"ユーザーを管理"</string> <string name="quick_settings_done" msgid="2163641301648855793">"完了"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"閉じる"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"接続済み"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"アプリの共有、録画、キャスト中は、そのアプリで表示されている内容や再生している内容に <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> がアクセスできるため、パスワード、お支払いの詳細、メッセージなどの機密情報にご注意ください。"</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"続行"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"アプリの共有、録画"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"すべて消去"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"管理"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"履歴"</string> diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml index 548d928a1425..729951db2c72 100644 --- a/packages/SystemUI/res/values-ka/strings.xml +++ b/packages/SystemUI/res/values-ka/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"სახის ამოცნობა შეუძლებ."</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"გამოიყენეთ თითის ანაბეჭდი"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth დაკავშირებულია."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"ბატარეის პროცენტული მაჩვენებელი უცნობია."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"დაკავშირებულია <xliff:g id="BLUETOOTH">%s</xliff:g>-თან."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"განათება"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"ფერთა ინვერსია"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"ფერთა კორექცია"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"მომხმარებლების მართვა"</string> <string name="quick_settings_done" msgid="2163641301648855793">"დასრულდა"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"დახურვა"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"დაკავშირებულია"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"აპის გაზიარებისას, ჩაწერისას ან ტრანსლირებისას <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> აქვს წვდომა აქვს ყველაფერზე, რაც ჩანს აპში ან ითამაშეთ. ამიტომ იყავით ფრთხილად პაროლებთან, გადახდის დეტალებთან, შეტყობინებებთან ან სხვა მგრძნობიარე ინფორმაციასთან."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"გაგრძელება"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"გააზიარეთ ან ჩაწერეთ აპი"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"ყველას გასუფთავება"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"მართვა"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"ისტორია"</string> diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml index 5a8e3f21401b..9a6530e3c660 100644 --- a/packages/SystemUI/res/values-kk/strings.xml +++ b/packages/SystemUI/res/values-kk/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Бет танылмады."</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Орнына саусақ ізін пайдаланыңыз."</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth қосылған."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Батарея зарядының мөлшері белгісіз."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> қосылған."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Жарықтығы"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Түс инверсиясы"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Түсті түзету"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Пайдаланушыларды басқару"</string> <string name="quick_settings_done" msgid="2163641301648855793">"Дайын"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Жабу"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"Қосылды"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Қолданба экранын бөлісу, жазу не трансляциялау кезінде <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> қолданбасы онда көрінетін не ойнатылатын барлық нәрсені пайдалана алады. Сондықтан құпия сөздерді, төлем туралы мәліметті, хабарларды немесе басқа құпия ақпаратты енгізу кезінде сақ болыңыз."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Жалғастыру"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Қолданба экранын бөлісу не жазу"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Барлығын тазалау"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Басқару"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Тарих"</string> diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml index 11c334562894..979c1c32dc82 100644 --- a/packages/SystemUI/res/values-km/strings.xml +++ b/packages/SystemUI/res/values-km/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"មិនអាចសម្គាល់មុខបានទេ"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"ប្រើស្នាមម្រាមដៃជំនួសវិញ"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"បានតភ្ជាប់ប៊្លូធូស។"</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"មិនដឹងអំពីភាគរយថ្មទេ។"</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"បានភ្ជាប់ទៅ <xliff:g id="BLUETOOTH">%s</xliff:g> ។"</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"ពន្លឺ"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"ការបញ្ច្រាសពណ៌"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"ការកែតម្រូវពណ៌"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"គ្រប់គ្រងអ្នកប្រើប្រាស់"</string> <string name="quick_settings_done" msgid="2163641301648855793">"រួចរាល់"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"បិទ"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"បានភ្ជាប់"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"នៅពេលអ្នកកំពុងចែករំលែក ថត ឬបញ្ជូនកម្មវិធី <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> មានសិទ្ធិចូលប្រើប្រាស់អ្វីៗដែលបង្ហាញ ឬលេងនៅលើកម្មវិធីនោះ។ ដូច្នេះ សូមប្រុងប្រយ័ត្នចំពោះពាក្យសម្ងាត់ ព័ត៌មានលម្អិតអំពីការទូទាត់ប្រាក់ សារ ឬព័ត៌មានរសើបផ្សេងទៀត។"</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"បន្ត"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"ចែករំលែក ឬថតកម្មវិធី"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"សម្អាតទាំងអស់"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"គ្រប់គ្រង"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"ប្រវត្តិ"</string> diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml index 79f18baef8a0..48270a61e4c8 100644 --- a/packages/SystemUI/res/values-kn/strings.xml +++ b/packages/SystemUI/res/values-kn/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"ಮುಖ ಗುರುತಿಸಲಾಗುತ್ತಿಲ್ಲ"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"ಬದಲಿಗೆ ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಬಳಸಿ"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ಬ್ಲೂಟೂತ್ ಸಂಪರ್ಕಗೊಂಡಿದೆ."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"ಬ್ಯಾಟರಿ ಶೇಕಡಾವಾರು ತಿಳಿದಿಲ್ಲ."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> ಗೆ ಸಂಪರ್ಕಪಡಿಸಲಾಗಿದೆ."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"ಪ್ರಕಾಶಮಾನ"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"ಕಲರ್ ಇನ್ವರ್ಶನ್"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"ಬಣ್ಣದ ತಿದ್ದುಪಡಿ"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"ಬಳಕೆದಾರರನ್ನು ನಿರ್ವಹಿಸಿ"</string> <string name="quick_settings_done" msgid="2163641301648855793">"ಮುಗಿದಿದೆ"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"ಮುಚ್ಚಿರಿ"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"ನೀವು ಆ್ಯಪ್ ಅನ್ನು ಹಂಚಿಕೊಳ್ಳುತ್ತಿರುವಾಗ, ರೆಕಾರ್ಡ್ ಮಾಡುತ್ತಿರುವಾಗ ಅಥವಾ ಬಿತ್ತರಿಸುತ್ತಿರುವಾಗ, ಆ ಆ್ಯಪ್ನಲ್ಲಿ ತೋರಿಸಲಾಗುವ ಅಥವಾ ಪ್ಲೇ ಆಗುವ ಯಾವುದೇ ವಿಷಯಕ್ಕೆ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ಆ್ಯಕ್ಸೆಸ್ ಅನ್ನು ಹೊಂದಿರುತ್ತದೆ. ಹಾಗಾಗಿ, ಪಾಸ್ವರ್ಡ್ಗಳು, ಪಾವತಿ ವಿವರಗಳು, ಸಂದೇಶಗಳು ಅಥವಾ ಇತರ ಸೂಕ್ಷ್ಮ ಮಾಹಿತಿಯ ಕುರಿತು ಜಾಗರೂಕರಾಗಿರಿ."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"ಮುಂದುವರಿಸಿ"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"ಆ್ಯಪ್ ಅನ್ನು ಹಂಚಿಕೊಳ್ಳಿ ಅಥವಾ ರೆಕಾರ್ಡ್ ಮಾಡಿ"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"ಎಲ್ಲವನ್ನೂ ತೆರವುಗೊಳಿಸಿ"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"ನಿರ್ವಹಿಸಿ"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"ಇತಿಹಾಸ"</string> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index 74b3f0952960..dab98eb9185b 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"얼굴을 인식할 수 없습니다."</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"대신 지문을 사용하세요."</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"블루투스가 연결되었습니다."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"배터리 잔량을 알 수 없습니다."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>에 연결되었습니다."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"밝기"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"색상 반전"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"색상 보정"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"사용자 관리"</string> <string name="quick_settings_done" msgid="2163641301648855793">"완료"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"닫기"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"연결됨"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"앱을 공유하거나 녹화하거나 전송할 때는 <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>에서 해당 앱에 표시되거나 재생되는 모든 항목에 액세스할 수 있으므로 비밀번호, 결제 세부정보, 메시지 등 민감한 정보가 노출되지 않도록 주의하세요."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"계속"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"앱 공유 또는 녹화"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"모두 지우기"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"관리"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"기록"</string> diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml index ab85ba4c36e5..a3c98ce09f92 100644 --- a/packages/SystemUI/res/values-ky/strings.xml +++ b/packages/SystemUI/res/values-ky/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Жүз таанылбай жатат"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Манжа изин колдонуңуз"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth байланышта"</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Батарея кубатынын деңгээли белгисиз."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> менен туташкан."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Жарыктыгы"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Түстөрдү инверсиялоо"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Түстөрдү тууралоо"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Колдонуучуларды тескөө"</string> <string name="quick_settings_done" msgid="2163641301648855793">"Бүттү"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Жабуу"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"Туташкан"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Бөлүшүп, жаздырып же тышкы экранда бөлүшкөндө <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ал колдонмодо көрүнүп жана ойнотулуп жаткан нерселерге мүмкүнчүлүк алат. Андыктан сырсөздөрдү, төлөм маалыматын, билдирүүлөрдү жана башка купуя маалыматты көрсөтүп албаңыз."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Улантуу"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Колдонмону бөлүшүү же жаздыруу"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Баарын тазалап салуу"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Башкаруу"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Таржымал"</string> diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml index c7f6603a525d..862cd52f8365 100644 --- a/packages/SystemUI/res/values-lo/strings.xml +++ b/packages/SystemUI/res/values-lo/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"ບໍ່ສາມາດຈຳແນກໃບໜ້າໄດ້"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"ກະລຸນາໃຊ້ລາຍນິ້ວມືແທນ"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ເຊື່ອມຕໍ່ Bluetooth ແລ້ວ."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"ບໍ່ຮູ້ເປີເຊັນແບັດເຕີຣີ."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"ເຊື່ອມຕໍ່ຫາ <xliff:g id="BLUETOOTH">%s</xliff:g> ແລ້ວ."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"ຄວາມແຈ້ງ"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"ການປີ້ນສີ"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"ການແກ້ໄຂສີ"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"ຈັດການຜູ້ໃຊ້"</string> <string name="quick_settings_done" msgid="2163641301648855793">"ແລ້ວໆ"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"ປິດ"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"ເຊື່ອມຕໍ່ແລ້ວ"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"ໃນຕອນທີ່ທ່ານກຳລັງແບ່ງປັນ, ບັນທຶກ ຫຼື ສົ່ງສັນຍານແອັບ, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ມີສິດເຂົ້າເຖິງສິ່ງທີ່ສະແດງ ຫຼື ຫຼິ້ນຢູ່ໃນແອັບນັ້ນ. ດັ່ງນັ້ນໃຫ້ລະມັດລະວັງກ່ຽວກັບລະຫັດຜ່ານ, ລາຍລະອຽດການຈ່າຍເງິນ, ຂໍ້ຄວາມ ຫຼື ຂໍ້ມູນທີ່ລະອຽດອ່ອນອື່ນໆ."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"ສືບຕໍ່"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"ແບ່ງປັນ ຫຼື ບັນທຶກແອັບ"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"ລຶບລ້າງທັງໝົດ"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"ຈັດການ"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"ປະຫວັດ"</string> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index 2311e0f51b8b..0b1374782f95 100644 --- a/packages/SystemUI/res/values-lt/strings.xml +++ b/packages/SystemUI/res/values-lt/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Veidas neatpažintas"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Naudoti piršto antspaudą"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"„Bluetooth“ prijungtas."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Akumuliatoriaus energija procentais nežinoma."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Prisijungta prie „<xliff:g id="BLUETOOTH">%s</xliff:g>“."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Šviesumas"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Spalvų inversija"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Spalvų taisymas"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Tvarkyti naudotojus"</string> <string name="quick_settings_done" msgid="2163641301648855793">"Atlikta"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Uždaryti"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"Prijungtas"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Kai bendrinate, įrašote ar perduodate turinį, „<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>“ gali pasiekti viską, kas rodoma ar leidžiama programoje. Todėl būkite atsargūs su slaptažodžiais, išsamia mokėjimo metodo informacija, pranešimais ar kita neskelbtina informacija."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Tęsti"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Programos bendrinimas ar įrašymas"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Viską išvalyti"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Tvarkyti"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Istorija"</string> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index ecf21068b25f..e90a0a4a9cb4 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Nevar atpazīt seju"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Lietot pirksta nospiedumu"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth savienojums ir izveidots."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Akumulatora uzlādes līmenis procentos nav zināms."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Ir izveidots savienojum ar <xliff:g id="BLUETOOTH">%s</xliff:g>."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Spilgtums"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Krāsu inversija"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Krāsu korekcija"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Pārvaldīt lietotājus"</string> <string name="quick_settings_done" msgid="2163641301648855793">"Gatavs"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Aizvērt"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"Pievienota"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Lietotnes kopīgošanas, ierakstīšanas vai apraides laikā <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> var piekļūt visam, kas tiek rādīts vai atskaņots attiecīgajā lietotnē. Tāpēc piesardzīgi apejieties ar parolēm, maksājumu informāciju, ziņojumiem un citu sensitīvu informāciju."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Turpināt"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Lietotnes kopīgošana vai ierakstīšana"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Dzēst visu"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Pārvaldīt"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Vēsture"</string> diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml index 6bcbb078aecc..454d58d95ed3 100644 --- a/packages/SystemUI/res/values-mk/strings.xml +++ b/packages/SystemUI/res/values-mk/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Не се препознава ликот"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Користи отпечаток"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth е поврзан."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Процентот на батеријата е непознат."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Поврзано со <xliff:g id="BLUETOOTH">%s</xliff:g>."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Осветленост"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Инверзија на боите"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Корекција на боите"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Управувајте со корисниците"</string> <string name="quick_settings_done" msgid="2163641301648855793">"Готово"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Затвори"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"Поврзано"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Кога споделувате, снимате или емитувате апликација, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> има пристап до сѐ што се прикажува или пушта на таа апликација. Затоа, бидете внимателни со лозинки, детали за плаќање, пораки или други чувствителни податоци."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Продолжи"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Споделете или снимете апликација"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Избриши сѐ"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Управувајте"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Историја"</string> diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml index 19988a09bf37..cb9d469978a7 100644 --- a/packages/SystemUI/res/values-ml/strings.xml +++ b/packages/SystemUI/res/values-ml/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"മുഖം തിരിച്ചറിയാനാകുന്നില്ല"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"പകരം ഫിംഗർപ്രിന്റ് ഉപയോഗിക്കൂ"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ബ്ലൂടൂത്ത് കണക്റ്റുചെയ്തു."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"ബാറ്ററി ശതമാനം അജ്ഞാതമാണ്."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> എന്നതിലേക്ക് കണക്റ്റുചെയ്തു."</string> @@ -373,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"ഒരു ആപ്പ് പങ്കിടുമ്പോൾ, റെക്കോർഡ് ചെയ്യുമ്പോൾ അല്ലെങ്കിൽ കാസ്റ്റ് ചെയ്യുമ്പോൾ, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> എന്നതിന് ആപ്പിൽ കാണിക്കുന്ന അല്ലെങ്കിൽ പ്ലേ ചെയ്യുന്ന എല്ലാത്തിലേക്കും ആക്സസ് ഉണ്ട്. അതിനാൽ, പാസ്വേഡുകൾ, പേയ്മെന്റ് വിശദാംശങ്ങൾ, സന്ദേശങ്ങൾ അല്ലെങ്കിൽ സൂക്ഷ്മമായി കൈകാര്യം ചെയ്യേണ്ട മറ്റു വിവരങ്ങൾ എന്നിവ നൽകുമ്പോൾ സൂക്ഷിക്കുക."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"തുടരുക"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"ഒരു ആപ്പ് പങ്കിടുക അല്ലെങ്കിൽ റെക്കോർഡ് ചെയ്യുക"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"എല്ലാം മായ്ക്കുക"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"മാനേജ് ചെയ്യുക"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"ചരിത്രം"</string> diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml index 772d42390f12..6e5421ccafa6 100644 --- a/packages/SystemUI/res/values-mn/strings.xml +++ b/packages/SystemUI/res/values-mn/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Царайг танихгүй байна"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Оронд нь хурууны хээ ашиглах"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth холбогдсон."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Батарейн хувь тодорхойгүй байна."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>-тай холбогдсон."</string> @@ -373,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Таныг хуваалцаж, бичиж эсвэл дамжуулж байх үед <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> нь тухайн апп дээр харуулсан эсвэл тоглуулсан аливаа зүйлд хандах эрхтэй. Тиймээс нууц үг, төлбөрийн дэлгэрэнгүй, мессеж эсвэл бусад эмзэг мэдээлэлд болгоомжтой хандаарай."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Үргэлжлүүлэх"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Хуваалцах эсвэл бичих апп"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Бүгдийг арилгах"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Удирдах"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Түүх"</string> diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml index db30910c9b21..d3723c254076 100644 --- a/packages/SystemUI/res/values-mr/strings.xml +++ b/packages/SystemUI/res/values-mr/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"चेहरा ओळखू शकत नाही"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"त्याऐवजी फिंगरप्रिंट वापरा"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ब्लूटूथ कनेक्ट केले."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"बॅटरीच्या चार्जिंगची टक्केवारी माहित नाही."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> शी कनेक्ट केले."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"चमक"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"कलर इन्व्हर्जन"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"रंग सुधारणा"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"वापरकर्ते व्यवस्थापित करा"</string> <string name="quick_settings_done" msgid="2163641301648855793">"पूर्ण झाले"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"बंद करा"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"कनेक्ट केलेले"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"तुम्ही अॅप शेअर, रेकॉर्ड किंवा कास्ट करत असताना, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ला त्या अॅपवर दाखवलेल्या किंवा प्ले केलेल्या कोणत्याही गोष्टीचा अॅक्सेस असतो. त्यामुळे पासवर्ड, पेमेंट तपशील, मेसेज किंवा इतर संवेदनशील माहिती काळजीपूर्वक वापरा."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"पुढे सुरू ठेवा"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"अॅप शेअर किंवा रेकॉर्ड करा"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"सर्व साफ करा"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"व्यवस्थापित करा"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"इतिहास"</string> diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml index 1588a665a2c8..b9bbbb3a48a4 100644 --- a/packages/SystemUI/res/values-ms/strings.xml +++ b/packages/SystemUI/res/values-ms/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Tak dapat mengecam wajah"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Gunakan cap jari"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth disambungkan."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Peratusan kuasa bateri tidak diketahui."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Disambungkan kepada <xliff:g id="BLUETOOTH">%s</xliff:g>."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Kecerahan"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Penyongsangan warna"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Pembetulan warna"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Urus pengguna"</string> <string name="quick_settings_done" msgid="2163641301648855793">"Selesai"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Tutup"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"Disambungkan"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Apabila anda berkongsi, merakam atau menghantar apl, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> mempunyai akses kepada apa-apa yang dipaparkan atau dimainkan pada apl tersebut. Jadi berhati-hati dengan kata laluan, butiran pembayaran, mesej atau maklumat sensitif lain."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Teruskan"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Kongsi atau rakam apl"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Kosongkan semua"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Urus"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Sejarah"</string> diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml index cc67dd743c46..69f45be2275d 100644 --- a/packages/SystemUI/res/values-my/strings.xml +++ b/packages/SystemUI/res/values-my/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"မျက်နှာကို မမှတ်မိပါ"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"လက်ဗွေကို အစားထိုးသုံးပါ"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ဘလူးတုသ်ချိတ်ဆက်ထားမှု"</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"ဘက်ထရီရာခိုင်နှုန်းကို မသိပါ။"</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>သို့ ချိတ်ဆက်ထား"</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"အလင်းတောက်ပမှု"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"အရောင်ပြောင်းပြန်ပြုလုပ်ရန်"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"အရောင် အမှန်ပြင်ခြင်း"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"အသုံးပြုသူများ စီမံရန်"</string> <string name="quick_settings_done" msgid="2163641301648855793">"ပြီးပါပြီ"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"ပိတ်ရန်"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"ချိတ်ဆက်ထား"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"အက်ပ်ဖြင့် မျှဝေ၊ ရိုက်ကူး (သို့) ကာစ်လုပ်သည့်အခါ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> သည် ၎င်းအက်ပ်တွင် ပြထားသည့် (သို့) ဖွင့်ထားသည့် အရာအားလုံးကို တွေ့နိုင်သည်။ ထို့ကြောင့် စကားဝှက်၊ ငွေပေးချေမှု အချက်အလက်၊ မက်ဆေ့ဂျ် (သို့) အခြားအရေးကြီးအချက်အလက်များနှင့်ပတ်သက်၍ ဂရုစိုက်ပါ။"</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"ရှေ့ဆက်ရန်"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"အက်ပ် မျှဝေခြင်း (သို့) ရိုက်ကူးခြင်း"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"အားလုံးရှင်းရန်"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"စီမံရန်"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"မှတ်တမ်း"</string> diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index 2a23331dc1c2..7a1b05cf4618 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Ansiktet gjenkjennes ikke"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Bruk fingeravtrykk"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth er tilkoblet."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Batteriprosenten er ukjent."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Koblet til <xliff:g id="BLUETOOTH">%s</xliff:g>."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Lysstyrke"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Fargeinvertering"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Fargekorrigering"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Administrer brukere"</string> <string name="quick_settings_done" msgid="2163641301648855793">"Ferdig"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Lukk"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"Tilkoblet"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Når du deler, tar opp eller caster en app, har <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> tilgang til alt som vises eller spilles av i den aktuelle appen. Derfor bør du være forsiktig med passord, betalingsopplysninger, meldinger og annen sensitiv informasjon."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Fortsett"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Del eller ta opp en app"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Fjern alt"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Administrer"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Logg"</string> diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml index a265cffa94f5..df70c0dac3f2 100644 --- a/packages/SystemUI/res/values-ne/strings.xml +++ b/packages/SystemUI/res/values-ne/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"अनुहार पहिचान गर्न सकिएन"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"बरु फिंगरप्रिन्ट प्रयोग गर्नुहोस्"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ब्लुटुथ जडान भयो।"</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"ब्याट्रीमा कति प्रतिशत चार्ज छ भन्ने कुराको जानाकरी छैन।"</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> मा जडित।"</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"उज्यालपन"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"कलर इन्भर्सन"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"कलर करेक्सन"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"प्रयोगकर्ताहरू व्यवस्थित गर्नुहोस्"</string> <string name="quick_settings_done" msgid="2163641301648855793">"भयो"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"बन्द गर्नुहोस्"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"जोडिएको"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"तपाईंले सेयर गर्दा, रेकर्ड गर्दा वा कास्ट गर्दा<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ले तपाईंको स्क्रिनमा देखिने वा डिभाइसमा प्ले गरिएका सबै कुरा खिच्न सक्छ। त्यसैले पासवर्ड, भुक्तानीको विवरण, म्यासेज वा अन्य संवेदनशील जानकारी सुरक्षित राख्नुहोला।"</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"जारी राख्नुहोस्"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"सेयर वा रेकर्ड गर्नका लागि एप चयन गर्नुहोस्"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"सबै हटाउनुहोस्"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"व्यवस्थित गर्नुहोस्"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"इतिहास"</string> diff --git a/packages/SystemUI/res/values-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml index dc2bee56373c..e44155f472ea 100644 --- a/packages/SystemUI/res/values-night/colors.xml +++ b/packages/SystemUI/res/values-night/colors.xml @@ -78,9 +78,6 @@ <color name="biometric_dialog_accent">@color/material_dynamic_primary70</color> <color name="biometric_dialog_error">#fff28b82</color> <!-- red 300 --> - <!-- UDFPS colors --> - <color name="udfps_enroll_icon">#7DA7F1</color> - <color name="GM2_green_500">#FF41Af6A</color> <color name="GM2_blue_500">#5195EA</color> <color name="GM2_red_500">#E25142</color> @@ -101,4 +98,13 @@ <color name="accessibility_floating_menu_background">#B3000000</color> <!-- 70% --> <color name="people_tile_background">@color/material_dynamic_secondary20</color> + + <!-- UDFPS colors --> + <color name="udfps_enroll_icon">#7DA7F1</color> + <color name="udfps_moving_target_fill">#475670</color> + <!-- 50% of udfps_moving_target_fill--> + <color name="udfps_moving_target_fill_error">#80475670</color> + <color name="udfps_enroll_progress">#7DA7F1</color> + <color name="udfps_enroll_progress_help">#607DA7F1</color> + <color name="udfps_enroll_progress_help_with_talkback">#FFEE675C</color> </resources> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index 5477bb136d98..1debee4b4e6c 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Gezicht niet herkend"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Vingerafdruk gebruiken"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth-verbinding ingesteld."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Batterijpercentage onbekend."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Verbonden met <xliff:g id="BLUETOOTH">%s</xliff:g>."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Helderheid"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Kleurinversie"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Kleurcorrectie"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Gebruikers beheren"</string> <string name="quick_settings_done" msgid="2163641301648855793">"Klaar"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Sluiten"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"Verbonden"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Als je deelt, opneemt of cast, heeft <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> toegang tot alles dat wordt getoond of afgespeeld in die app. Wees daarom voorzichtig met wachtwoorden, betalingsgegevens, berichten en andere gevoelige informatie."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Doorgaan"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"App delen of opnemen"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Alles wissen"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Beheren"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Geschiedenis"</string> diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml index 84badf82293a..b4442288ed42 100644 --- a/packages/SystemUI/res/values-or/strings.xml +++ b/packages/SystemUI/res/values-or/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"ଫେସ ଚିହ୍ନଟ ହୋଇପାରିବ ନାହିଁ"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"ଟିପଚିହ୍ନ ବ୍ୟବହାର କରନ୍ତୁ"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ବ୍ଲୁଟୂଥ୍ ସଂଯୋଗ କରାଯାଇଛି।"</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"ବ୍ୟାଟେରୀ ଶତକଡ଼ା ଅଜଣା ଅଟେ।"</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> ସହ ସଂଯୁକ୍ତ"</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"ଉଜ୍ଜ୍ୱଳତା"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"ରଙ୍ଗ ଇନଭାର୍ସନ"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"ରଙ୍ଗ ସଂଶୋଧନ"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"ୟୁଜରମାନଙ୍କୁ ପରିଚାଳନା କରନ୍ତୁ"</string> <string name="quick_settings_done" msgid="2163641301648855793">"ହୋଇଗଲା"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"ବନ୍ଦ କରନ୍ତୁ"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"ସଂଯୁକ୍ତ"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"ଆପଣ ସେୟାର, ରେକର୍ଡ କିମ୍ବା କାଷ୍ଟ କରିବା ସମୟରେ, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ଆପରେ ଦେଖାଯାଉଥିବା କିମ୍ବା ପ୍ଲେ ହେଉଥିବା ସବୁକିଛିକୁ ସେହି ଆପର ଆକ୍ସେସ ଅଛି। ତେଣୁ ପାସୱାର୍ଡ, ପେମେଣ୍ଟ ବିବରଣୀ, ମେସେଜ କିମ୍ବା ଅନ୍ୟ ସମ୍ବେଦନଶୀଳ ସୂଚନା ପ୍ରତି ସତର୍କ ରୁହନ୍ତୁ।"</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"ଜାରି ରଖନ୍ତୁ"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"ଏକ ଆପକୁ ସେୟାର କିମ୍ବା ରେକର୍ଡ କରନ୍ତୁ"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"ସମସ୍ତ ଖାଲି କରନ୍ତୁ"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"ପରିଚାଳନା କରନ୍ତୁ"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"ଇତିହାସ"</string> diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml index 5738d22da067..1633c3bdcff2 100644 --- a/packages/SystemUI/res/values-pa/strings.xml +++ b/packages/SystemUI/res/values-pa/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"ਚਿਹਰੇ ਦੀ ਪਛਾਣ ਨਹੀਂ ਹੋਈ"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"ਇਸਦੀ ਬਜਾਏ ਫਿੰਗਰਪ੍ਰਿੰਟ ਵਰਤੋ"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth ਕਨੈਕਟ ਕੀਤੀ।"</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"ਬੈਟਰੀ ਪ੍ਰਤੀਸ਼ਤ ਅਗਿਆਤ ਹੈ।"</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ।"</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"ਚਮਕ"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"ਰੰਗ ਪਲਟਨਾ"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"ਰੰਗ ਸੁਧਾਈ"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"ਵਰਤੋਂਕਾਰਾਂ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰੋ"</string> <string name="quick_settings_done" msgid="2163641301648855793">"ਹੋ ਗਿਆ"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"ਬੰਦ ਕਰੋ"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"ਕਨੈਕਟ ਕੀਤਾ"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"ਤੁਹਾਡੇ ਵੱਲੋਂ ਸਾਂਝਾ ਕਰਨ, ਰਿਕਾਰਡ ਕਰਨ, ਜਾਂ ਕਾਸਟ ਕਰਨ \'ਤੇ, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ਕੋਲ ਉਸ ਐਪ \'ਤੇ ਦਿਖਾਈ ਗਈ ਜਾਂ ਚਲਾਈ ਗਈ ਹਰੇਕ ਚੀਜ਼ ਤੱਕ ਪਹੁੰਚ ਹੁੰਦੀ ਹੈ। ਇਸ ਲਈ ਪਾਸਵਰਡਾਂ, ਭੁਗਤਾਨ ਵੇਰਵਿਆਂ, ਸੁਨੇਹਿਆਂ ਜਾਂ ਹੋਰ ਸੰਵੇਦਨਸ਼ੀਲ ਜਾਣਕਾਰੀ ਸੰਬੰਧੀ ਸਾਵਧਾਨ ਰਹੋ।"</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"ਜਾਰੀ ਰੱਖੋ"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"ਐਪ ਨੂੰ ਸਾਂਝਾ ਕਰੋ ਜਾਂ ਰਿਕਾਰਡ ਕਰੋ"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"ਸਭ ਕਲੀਅਰ ਕਰੋ"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"ਪ੍ਰਬੰਧਨ ਕਰੋ"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"ਇਤਿਹਾਸ"</string> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index 67e09e282da4..fca76c4c9ce1 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Nie można rozpoznać twarzy"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Użyj odcisku palca"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth połączony."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Poziom naładowania baterii jest nieznany."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Połączono z <xliff:g id="BLUETOOTH">%s</xliff:g>."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Jasność"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Odwrócenie kolorów"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Korekcja kolorów"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Zarządzaj użytkownikami"</string> <string name="quick_settings_done" msgid="2163641301648855793">"Gotowe"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Zamknij"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"Połączono"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Podczas udostępniania, nagrywania lub przesyłania treści aplikacja <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ma dostęp do wszystkiego, co jest w niej wyświetlane lub odtwarzane. Zachowaj ostrożność w przypadku haseł, danych do płatności, wiadomości i innych informacji poufnych."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Dalej"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Udostępnianie i nagrywanie za pomocą aplikacji"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Usuń wszystkie"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Zarządzaj"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Historia"</string> diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml index 1ed32530ad33..9a3bfa691978 100644 --- a/packages/SystemUI/res/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res/values-pt-rBR/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Rosto não reconhecido"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Use a impressão digital"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth conectado."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Porcentagem da bateria desconhecida."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Conectado a <xliff:g id="BLUETOOTH">%s</xliff:g>."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brilho"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversão de cores"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Correção de cor"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Gerenciar usuários"</string> <string name="quick_settings_done" msgid="2163641301648855793">"Concluído"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Fechar"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"Conectado"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Quando você compartilha, grava ou transmite um app, o <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> tem acesso a todas as informações visíveis na tela ou reproduzidas no dispositivo. Tenha cuidado com senhas, detalhes de pagamento, mensagens ou outras informações sensíveis."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Continuar"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Compartilhar ou gravar um app"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Limpar tudo"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Gerenciar"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Histórico"</string> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index 06b942c1d018..dcddba80e4a2 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -143,7 +143,7 @@ <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Rosto reconhecido. Prima para continuar."</string> <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Rosto reconhecido. Prima ícone de desbloqueio para continuar"</string> <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autenticado"</string> - <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Utilizar PIN"</string> + <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Usar PIN"</string> <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Utilizar padrão"</string> <string name="biometric_dialog_use_password" msgid="3445033859393474779">"Utilizar palavra-passe"</string> <string name="biometric_dialog_wrong_pin" msgid="1878539073972762803">"PIN incorreto."</string> @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Imposs. reconhecer rosto"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Usar impressão digital"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth ligado."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Percentagem da bateria desconhecida."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Ligado a <xliff:g id="BLUETOOTH">%s</xliff:g>."</string> @@ -373,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Quando está a partilhar, gravar ou transmitir uma app, a app <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> tem acesso a tudo o que é apresentado ou reproduzido nessa app. Por isso, tenha cuidado com palavras-passe, detalhes de pagamento, mensagens ou outras informações confidenciais."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Continuar"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Partilhe ou grave uma app"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Limpar tudo"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Gerir"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Histórico"</string> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index 1ed32530ad33..9a3bfa691978 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Rosto não reconhecido"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Use a impressão digital"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth conectado."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Porcentagem da bateria desconhecida."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Conectado a <xliff:g id="BLUETOOTH">%s</xliff:g>."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brilho"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversão de cores"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Correção de cor"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Gerenciar usuários"</string> <string name="quick_settings_done" msgid="2163641301648855793">"Concluído"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Fechar"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"Conectado"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Quando você compartilha, grava ou transmite um app, o <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> tem acesso a todas as informações visíveis na tela ou reproduzidas no dispositivo. Tenha cuidado com senhas, detalhes de pagamento, mensagens ou outras informações sensíveis."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Continuar"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Compartilhar ou gravar um app"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Limpar tudo"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Gerenciar"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Histórico"</string> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index f4b290e833bc..582508915a6a 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Chip nerecunoscut"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Folosește amprenta"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Conectat prin Bluetooth."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Procentajul bateriei este necunoscut."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Conectat la <xliff:g id="BLUETOOTH">%s</xliff:g>."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Luminozitate"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversarea culorilor"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Corecția culorii"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Gestionează utilizatorii"</string> <string name="quick_settings_done" msgid="2163641301648855793">"Terminat"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Închide"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"Conectat"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Când permiți accesul, înregistrezi sau proiectezi o aplicație, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> are acces la orice se afișează pe ecran sau se redă în aplicație. Ai grijă cu parolele, detaliile de plată, mesajele sau alte informații sensibile."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Continuă"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Permite accesul la o aplicație sau înregistreaz-o"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Șterge toate notificările"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Gestionează"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Istoric"</string> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index 386e7af90462..b6b0628409e7 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Лицо не распознано."</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Используйте отпечаток."</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth-соединение установлено."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Уровень заряда батареи в процентах неизвестен."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>: подключено."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Яркость"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Инверсия цветов"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Коррекция цвета"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Управление пользователями"</string> <string name="quick_settings_done" msgid="2163641301648855793">"Готово"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Закрыть"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"Подключено"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Когда вы демонстрируете, транслируете экран или записываете видео с него, приложение \"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>\" получает доступ ко всему, что видно и воспроизводится на экране устройства. Помните об этом, если соберетесь вводить или просматривать пароли, платежные данные, сообщения и другую конфиденциальную информацию."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Далее"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Демонстрация экрана или запись видео с него"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Очистить все"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Настроить"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"История"</string> diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml index 847cbac4bc62..832c211cfdf3 100644 --- a/packages/SystemUI/res/values-si/strings.xml +++ b/packages/SystemUI/res/values-si/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"මුහුණ හඳුනා ගත නොහැක"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"ඒ වෙනුවට ඇඟිලි සලකුණ භාවිත කරන්න"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"බ්ලූටූත් සම්බන්ධිතයි."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"බැටරි ප්රතිශතය නොදනී."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> වෙත සම්බන්ධ කරන ලදි."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"දීප්තිමත් බව"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"වර්ණ අපවර්තනය"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"වර්ණ නිවැරදි කිරීම"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"පරිශීලකයන් කළමනාකරණය කරන්න"</string> <string name="quick_settings_done" msgid="2163641301648855793">"නිමයි"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"වසන්න"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"සම්බන්ධිත"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"ඔබ යෙදුමක් බෙදා ගන්නා විට, පටිගත කරන විට හෝ විකාශය කරන විට, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> හට එම යෙදුමේ පෙන්වන හෝ වාදනය කරන ඕනෑම දෙයකට ප්රවේශය ඇත. එබැවින් මුරපද, ගෙවීම් විස්තර, පණිවිඩ හෝ වෙනත් සංවේදී තොරතුරු සමග ප්රවේශම් වන්න."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"ඉදිරියට යන්න"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"යෙදුමක් බෙදා ගන්න හෝ පටිගත කරන්න"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"සියල්ල හිස් කරන්න"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"කළමනාකරණය කරන්න"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"ඉතිහාසය"</string> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index 888a21941916..032991498d22 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Tvár sa nedá rozpoznať"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Používať radšej odtlačok"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth pripojené."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Percento batérie nie je známe."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Pripojené k zariadeniu <xliff:g id="BLUETOOTH">%s</xliff:g>."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Jas"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inverzia farieb"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Úprava farieb"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Spravovať používateľov"</string> <string name="quick_settings_done" msgid="2163641301648855793">"Hotovo"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Zavrieť"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"Pripojené"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Počas zdieľania, nahrávania alebo prenosu bude mať aplikácia <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> prístup k všetkému obsahu, ktorý sa v nej bude zobrazovať alebo prehrávať. Preto venujte zvýšenú pozornosť heslám, platobným údajom, správam a ďalším citlivým údajom."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Pokračovať"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Aplikácia na zdieľanie alebo nahrávanie"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Vymazať všetko"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Spravovať"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"História"</string> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index 22b8008cf713..b935de739350 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Obraz ni bil prepoznan."</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Uporabite prstni odtis."</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Povezava Bluetooth vzpostavljena."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Neznan odstotek napolnjenosti baterije."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Povezava vzpostavljena z: <xliff:g id="BLUETOOTH">%s</xliff:g>."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Svetlost"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inverzija barv"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Popravljanje barv"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Upravljanje uporabnikov"</string> <string name="quick_settings_done" msgid="2163641301648855793">"Končano"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Zapri"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"Povezava je vzpostavljena"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Pri deljenju, snemanju ali predvajanju aplikacije ima aplikacija <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> dostop do vsega, kar je prikazano ali predvajano v tej aplikaciji, zato bodite previdni z gesli, podatki za plačilo, sporočili ali drugimi občutljivimi podatki."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Naprej"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Deljenje ali snemanje aplikacije"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Izbriši vse"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Upravljaj"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Zgodovina"</string> diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml index 9c33ca9e21e1..b7fef862abe6 100644 --- a/packages/SystemUI/res/values-sq/strings.xml +++ b/packages/SystemUI/res/values-sq/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Fytyra nuk mund të njihet"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Përdor më mirë gjurmën e gishtit"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Pajisja është lidhur me \"bluetooth\"."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Përqindja e baterisë e panjohur."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Lidhur me <xliff:g id="BLUETOOTH">%s</xliff:g>"</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Ndriçimi"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Anasjellja e ngjyrës"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Korrigjimi i ngjyrës"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Menaxho përdoruesit"</string> <string name="quick_settings_done" msgid="2163641301648855793">"U krye"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Mbyll"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"I lidhur"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Gjatë shpërndarjes, regjistrimit ose transmetimit të një aplikacioni, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ka qasje te çdo gjë e dukshme në ekranin tënd ose që po luhet në atë aplikacion. Prandaj, ki kujdes me fjalëkalimet, detajet e pagesës, mesazhet ose informacione të tjera të ndjeshme."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Vazhdo"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Shpërndaj ose regjistro një aplikacion"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Pastroji të gjitha"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Menaxho"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Historiku"</string> diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index 333927990aca..56cb3c8de8d5 100644 --- a/packages/SystemUI/res/values-sr/strings.xml +++ b/packages/SystemUI/res/values-sr/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Лице није препознато"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Користите отисак прста"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth је прикључен."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Проценат напуњености батерије није познат."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Повезани сте са <xliff:g id="BLUETOOTH">%s</xliff:g>."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Осветљеност"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Инверзија боја"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Корекција боја"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Управљаjте корисницима"</string> <string name="quick_settings_done" msgid="2163641301648855793">"Готово"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Затвори"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"Повезан"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Када делите, снимате или пребацујете апликацију, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> има приступ комплетном садржају који је видљив или се пушта у тој апликацији. Будите пажљиви са лозинкама, информацијама о плаћању, порукама или другим осетљивим информацијама."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Настави"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Делите или снимите апликацију"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Обриши све"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Управљајте"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Историја"</string> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index 7fd6710bf9d1..8de8d09915b8 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Ansiktet kändes inte igen"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Använd fingeravtryck"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth ansluten."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Okänd batterinivå."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Ansluten till <xliff:g id="BLUETOOTH">%s</xliff:g>."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Ljusstyrka"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Färginvertering"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Färgkorrigering"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Hantera användare"</string> <string name="quick_settings_done" msgid="2163641301648855793">"Klart"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Stäng"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"Ansluten"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"När du delar, spelar in eller castar en app har <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> åtkomst till allt som visas eller spelas upp i appen. Så var försiktig med lösenord, betalningsuppgifter, meddelanden och andra känsliga uppgifter."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Fortsätt"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Dela eller spela in en app"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Rensa alla"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Hantera"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Historik"</string> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index 6db67b662ce7..cfa370eab4cd 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Imeshindwa kutambua uso"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Badala yake, tumia alama ya kidole"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth imeunganishwa."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Asilimia ya betri haijulikani."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Imeunganishwa kwenye <xliff:g id="BLUETOOTH">%s</xliff:g>."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Ung\'avu"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Ugeuzaji rangi"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Usahihishaji wa rangirangi"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Dhibiti watumiaji"</string> <string name="quick_settings_done" msgid="2163641301648855793">"Nimemaliza"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Funga"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"Imeunganishwa"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Unapotuma, kurekodi au kushiriki programu, programu ya <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> inaweza kufikia kitu chochote kitakachoonekana au kuchezwa kwenye programu hiyo. Hivyo kuwa mwangalifu na manenosiri, maelezo ya malipo, ujumbe au maelezo mengine nyeti."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Endelea"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Shiriki au rekodi programu"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Futa zote"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Dhibiti"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Historia"</string> diff --git a/packages/SystemUI/res/values-sw600dp-h900dp/dimens.xml b/packages/SystemUI/res/values-sw600dp-h900dp/dimens.xml new file mode 100644 index 000000000000..aab914f19878 --- /dev/null +++ b/packages/SystemUI/res/values-sw600dp-h900dp/dimens.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2022 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<!-- Intended for wide devices that are currently oriented with a lot of available height, + such as tablets. 'hxxxdp' is used instead of 'port' in order to avoid this being applied + to wide devices that are shorter in height, like foldables. --> +<resources> + <!-- Space between status view and notification shelf --> + <dimen name="keyguard_status_view_bottom_margin">35dp</dimen> + <dimen name="keyguard_clock_top_margin">40dp</dimen> +</resources> diff --git a/packages/SystemUI/res/values-sw600dp-port/dimens.xml b/packages/SystemUI/res/values-sw600dp-port/dimens.xml index 347cf2965c77..d9df3373bef1 100644 --- a/packages/SystemUI/res/values-sw600dp-port/dimens.xml +++ b/packages/SystemUI/res/values-sw600dp-port/dimens.xml @@ -17,8 +17,6 @@ <resources> <dimen name="notification_panel_margin_horizontal">48dp</dimen> <dimen name="status_view_margin_horizontal">62dp</dimen> - <dimen name="keyguard_clock_top_margin">40dp</dimen> - <dimen name="keyguard_status_view_bottom_margin">40dp</dimen> <dimen name="bouncer_user_switcher_y_trans">20dp</dimen> <!-- qs_tiles_page_horizontal_margin should be margin / 2, otherwise full space between two diff --git a/packages/SystemUI/res/values-sw720dp-h1000dp/dimens.xml b/packages/SystemUI/res/values-sw720dp-h1000dp/dimens.xml new file mode 100644 index 000000000000..97ead01669a9 --- /dev/null +++ b/packages/SystemUI/res/values-sw720dp-h1000dp/dimens.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2022 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<!-- Intended for wide devices that are currently oriented with a lot of available height, + such as tablets. 'hxxxdp' is used instead of 'port' in order to avoid this being applied + to wide devices that are shorter in height, like foldables. --> +<resources> + <!-- Space between status view and notification shelf --> + <dimen name="keyguard_status_view_bottom_margin">70dp</dimen> + <dimen name="keyguard_clock_top_margin">80dp</dimen> +</resources> diff --git a/packages/SystemUI/res/values-sw720dp-port/dimens.xml b/packages/SystemUI/res/values-sw720dp-port/dimens.xml index 3d8da8a6c3e8..17f82b50d7be 100644 --- a/packages/SystemUI/res/values-sw720dp-port/dimens.xml +++ b/packages/SystemUI/res/values-sw720dp-port/dimens.xml @@ -21,8 +21,6 @@ for different hardware and product builds. --> <resources> <dimen name="status_view_margin_horizontal">124dp</dimen> - <dimen name="keyguard_clock_top_margin">80dp</dimen> - <dimen name="keyguard_status_view_bottom_margin">80dp</dimen> <dimen name="bouncer_user_switcher_y_trans">200dp</dimen> <dimen name="large_screen_shade_header_left_padding">24dp</dimen> diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml index 87394409e12b..caea7a033684 100644 --- a/packages/SystemUI/res/values-ta/strings.xml +++ b/packages/SystemUI/res/values-ta/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"முகத்தை கண்டறிய இயலவில்லை"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"கைரேகையை உபயோகிக்கவும்"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"புளூடூத் இணைக்கப்பட்டது."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"பேட்டரி சதவீதம் தெரியவில்லை."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>க்கு இணைக்கப்பட்டது."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"ஒளிர்வு"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"கலர் இன்வெர்ஷன்"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"கலர் கரெக்ஷன்"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"பயனர்களை நிர்வகியுங்கள்"</string> <string name="quick_settings_done" msgid="2163641301648855793">"முடிந்தது"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"மூடுக"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"இணைக்கப்பட்டது"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"ஓர் ஆப்ஸை நீங்கள் பகிரும்போதோ ரெக்கார்டு செய்யும்போதோ அலைபரப்பும்போதோ அந்த ஆப்ஸில் காட்டப்படும் அல்லது பிளே செய்யப்படும் அனைத்தையும் <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ஆப்ஸால் அணுக முடியும். எனவே கடவுச்சொற்கள், பேமெண்ட் விவரங்கள், மெசேஜ்கள், பிற பாதுகாக்கப்பட வேண்டிய தகவல்கள் ஆகியவை குறித்து கவனத்துடன் இருங்கள்."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"தொடர்க"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"ஆப்ஸைப் பகிர்தல் அல்லது ரெக்கார்டு செய்தல்"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"எல்லாவற்றையும் அழி"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"நிர்வகி"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"இதுவரை வந்த அறிவிப்புகள்"</string> diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml index db1c3b1bd099..22d7190e60c0 100644 --- a/packages/SystemUI/res/values-te/strings.xml +++ b/packages/SystemUI/res/values-te/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"ముఖం గుర్తించడం కుదరలేదు"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"బదులుగా వేలిముద్రను ఉపయోగించండి"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"బ్లూటూత్ కనెక్ట్ చేయబడింది."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"బ్యాటరీ శాతం తెలియదు."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>కి కనెక్ట్ చేయబడింది."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"ప్రకాశం"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"కలర్ మార్పిడి"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"కలర్ కరెక్షన్"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"యూజర్లను మేనేజ్ చేయండి"</string> <string name="quick_settings_done" msgid="2163641301648855793">"పూర్తయింది"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"మూసివేయి"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"కనెక్ట్ చేయబడినది"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"మీరు ఏదైనా యాప్ను షేర్ చేస్తున్నప్పుడు, రికార్డ్ చేస్తున్నప్పుడు, లేదా ప్రసారం చేస్తున్నప్పుడు, ఆ యాప్లో చూపబడిన దేనికైనా లేదా ప్లే అయిన దేనికైనా <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>కు యాక్సెస్ ఉంటుంది. కాబట్టి, పాస్వర్డ్లు, పేమెంట్ వివరాలు, మెసేజ్లు, లేదా ఏదైనా ఇతర సున్నితమైన సమాచారం పట్ల జాగ్రత్త వహించండి."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"కొనసాగించండి"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"యాప్ను షేర్ చేయండి లేదా రికార్డ్ చేయండి"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"అన్నీ క్లియర్ చేయండి"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"మేనేజ్ చేయండి"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"హిస్టరీ"</string> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index d04b3677d978..bb3e4fa1fd86 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"ไม่รู้จักใบหน้า"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"ใช้ลายนิ้วมือแทน"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"เชื่อมต่อบลูทูธแล้ว"</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"ไม่ทราบเปอร์เซ็นต์แบตเตอรี่"</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"เชื่อมต่อกับ <xliff:g id="BLUETOOTH">%s</xliff:g> แล้ว"</string> @@ -373,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"เมื่อกำลังแชร์ บันทึก หรือแคสต์แอป \"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>\" จะมีสิทธิ์เข้าถึงทุกสิ่งที่แสดงหรือเล่นอยู่ในแอปดังกล่าว ดังนั้นโปรดระวังเกี่ยวกับรหัสผ่าน รายละเอียดการชำระเงิน ข้อความ หรือข้อมูลที่ละเอียดอ่อนอื่นๆ"</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"ต่อไป"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"แชร์หรือบันทึกแอป"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"ล้างทั้งหมด"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"จัดการ"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"ประวัติ"</string> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index aaea43b99602..8ddb64e9504a 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Hindi makilala ang mukha"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Gumamit ng fingerprint"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Nakakonekta ang Bluetooth."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Hindi alam ang porsyento ng baterya."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Nakakonekta sa <xliff:g id="BLUETOOTH">%s</xliff:g>."</string> @@ -373,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Kapag nagbabahagi, nagre-record, o nagka-cast ka ng app, may access ang <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> sa kahit anong ipinapakita o pine-play sa app na iyon. Kaya mag-ingat sa mga password, detalye ng pagbabayad, mensahe, o iba pang impormasyon."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Magpatuloy"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Ibahagi o i-record ang isang app"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"I-clear lahat"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Pamahalaan"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"History"</string> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index bba8195fc0ef..177ce9868de2 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Yüz tanınamadı"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Bunun yerine parmak izi kullanın"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth bağlandı."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Pil yüzdesi bilinmiyor."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> ile bağlı."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Parlaklık"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Rengi ters çevirme"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Renk düzeltme"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Kullanıcıları yönet"</string> <string name="quick_settings_done" msgid="2163641301648855793">"Bitti"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Kapat"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"Bağlı"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Bir uygulamayı paylaşma, kaydetme ve yayınlama özelliklerini kullandığınızda <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>, söz konusu uygulamada gösterilen veya oynatılan her şeye erişebilir. Dolayısıyla şifreler, ödeme ayrıntıları, mesajlar veya diğer hassas bilgiler konusunda dikkatli olun."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Devam"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Uygulamayı paylaşın veya kaydedin"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Tümünü temizle"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Yönet"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Geçmiş"</string> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index c67764e4b159..fdfcadce5dc7 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Обличчя не розпізнано"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Скористайтеся відбитком"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth під’єднано."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Відсоток заряду акумулятора невідомий."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Підключено до <xliff:g id="BLUETOOTH">%s</xliff:g>."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Яскравість"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Інверсія кольорів"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Корекція кольору"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Керувати користувачами"</string> <string name="quick_settings_done" msgid="2163641301648855793">"Готово"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Закрити"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"Під’єднано"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Коли ви показуєте, записуєте або транслюєте додаток, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> отримує доступ до всього, що відображається або відтворюється в цьому додатку. Тому будьте уважні з паролями, повідомленнями, платіжною й іншою конфіденційною інформацією."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Продовжити"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Показувати або записувати додаток"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Очистити все"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Керувати"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Історія"</string> diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml index 446c4d0f4194..e222148464c8 100644 --- a/packages/SystemUI/res/values-ur/strings.xml +++ b/packages/SystemUI/res/values-ur/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"چہرے کی پہچان نہیں ہو سکی"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"اس کے بجائے فنگر پرنٹ استعمال کریں"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"بلوٹوتھ مربوط ہے۔"</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"بیٹری کی فیصد نامعلوم ہے۔"</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> سے منسلک ہیں۔"</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"چمکیلا پن"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"رنگوں کی تقلیب"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"رنگ کی اصلاح"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"صارفین کا نظم کریں"</string> <string name="quick_settings_done" msgid="2163641301648855793">"ہو گیا"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"بند کریں"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"مربوط"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"جب آپ اشتراک، ریکارڈنگ یا کاسٹ کر رہے ہوتے ہیں تو <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> کو آپ کی اسکرین پر دکھائی گئی یا آپ کے آلے پر چلائی گئی ہر چیز تک رسائی حاصل ہوتی ہے۔ اس لیے پاس ورڈز، ادائیگی کی تفصیلات، پیغامات، یا دیگر حساس معلومات کے سلسلے میں محتاط رہیں۔"</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"جاری رکھیں"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"ایپ کا اشتراک یا ریکارڈ کریں"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"سبھی کو صاف کریں"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"نظم کریں"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"سرگزشت"</string> diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml index 285f849924ca..597fa4e2619d 100644 --- a/packages/SystemUI/res/values-uz/strings.xml +++ b/packages/SystemUI/res/values-uz/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Yuz aniqlanmadi"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Barmoq izi orqali urining"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth ulandi."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Batareya quvvati foizi nomaʼlum."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Ulangan: <xliff:g id="BLUETOOTH">%s</xliff:g>."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Yorqinlik"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Ranglarni akslantirish"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Ranglarni tuzatish"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Foydalanuvchilarni boshqarish"</string> <string name="quick_settings_done" msgid="2163641301648855793">"Tayyor"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Yopish"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"Ulangan"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Ulashish, yozib olish va translatsiya qilish vaqtida <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ilovasi ekranda chiqadigan yoki qurilmada ijro qilinadigan kontentni koʻra oladi. Shu sababli parollar, toʻlov tafsilotlari, xabarlar yoki boshqa maxfiy axborot chiqmasligi uchun ehtiyot boʻling."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Davom etish"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Ilovada ulashish yoki yozib olish"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Hammasini tozalash"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Boshqarish"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Tarix"</string> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index c3f513920f76..485676a90bf5 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Không nhận ra khuôn mặt"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Hãy dùng vân tay"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Đã kết nối bluetooth."</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Tỷ lệ phần trăm pin không xác định."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Đã kết nối với <xliff:g id="BLUETOOTH">%s</xliff:g>."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Độ sáng"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Đảo màu"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Chỉnh màu"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Quản lý người dùng"</string> <string name="quick_settings_done" msgid="2163641301648855793">"Xong"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Đóng"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"Đã kết nối"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Khi bạn chia sẻ, ghi hoặc truyền ứng dụng, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> sẽ có quyền truy cập vào mọi nội dung xuất hiện hoặc phát trên ứng dụng đó. Vì vậy, hãy thận trọng để không làm lộ mật khẩu, thông tin thanh toán, tin nhắn hoặc thông tin nhạy cảm khác."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Tiếp tục"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Chia sẻ hoặc ghi ứng dụng"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Xóa tất cả"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Quản lý"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Lịch sử"</string> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index 18d69c38012c..1b65855c2880 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"人脸识别失败"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"改用指纹"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"蓝牙已连接。"</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"电池电量百分比未知。"</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"已连接到<xliff:g id="BLUETOOTH">%s</xliff:g>。"</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"亮度"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"颜色反转"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"色彩校正"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"管理用户"</string> <string name="quick_settings_done" msgid="2163641301648855793">"完成"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"关闭"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"已连接"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"在您进行分享、录制或投射时,<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> 可以访问通过此应用显示或播放的所有内容。因此,请注意保护密码、付款信息、消息或其他敏感信息。"</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"继续"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"分享或录制应用"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"全部清除"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"管理"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"历史记录"</string> diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml index 282785c9f8ee..75cc85bc8826 100644 --- a/packages/SystemUI/res/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"無法辨識面孔"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"請改用指紋"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"藍牙連線已建立。"</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"電量百分比不明。"</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"已連線至<xliff:g id="BLUETOOTH">%s</xliff:g>。"</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"亮度"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"色彩反轉"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"色彩校正"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"管理使用者"</string> <string name="quick_settings_done" msgid="2163641301648855793">"完成"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"關閉"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"已連線"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"進行分享、錄製或投放時,<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> 可存取顯示在螢幕畫面上或在裝置上播放的所有內容。因此請謹慎處理密碼、付款資料、訊息或其他敏感資料。"</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"繼續"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"分享或錄製應用程式"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"全部清除"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"管理"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"記錄"</string> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index a7bba6d402db..ae8e6db6f9e7 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"無法辨識臉孔"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"請改用指紋"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"藍牙連線已建立。"</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"電池電量不明。"</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"已連線至<xliff:g id="BLUETOOTH">%s</xliff:g>。"</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"亮度"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"色彩反轉"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"色彩校正"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"管理使用者"</string> <string name="quick_settings_done" msgid="2163641301648855793">"完成"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"關閉"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"已連線"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"進行分享、錄製或投放應用程式時,<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> 可以存取在該應用程式中顯示或播放的所有內容。因此請謹慎處理密碼、付款資料、訊息或其他機密資訊。"</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"繼續"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"分享或錄製應用程式"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"全部清除"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"管理"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"記錄"</string> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index 5fb39f45d1be..0ce0613d02fb 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -168,6 +168,8 @@ <skip /> <string name="keyguard_face_failed" msgid="9044619102286917151">"Ayikwazi ukubona ubuso"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Kunalokho sebenzisa isigxivizo somunwe"</string> + <!-- no translation found for keyguard_face_unlock_unavailable (8145547300240405980) --> + <skip /> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth ixhunyiwe"</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Iphesenti lebhethri alaziwa."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Xhuma ku-<xliff:g id="BLUETOOTH">%s</xliff:g>."</string> @@ -248,8 +250,7 @@ <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Ukugqama"</string> <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Ukuguqulwa kombala"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Ukulungiswa kombala"</string> - <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) --> - <skip /> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Phatha abasebenzisi"</string> <string name="quick_settings_done" msgid="2163641301648855793">"Kwenziwe"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Vala"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"Ixhunyiwe"</string> @@ -374,6 +375,16 @@ <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Uma wabelana, urekhoda, noma usakaza i-app, i-<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> inokufinyelela kunoma yini eboniswayo noma edlalwayo kuleyo app. Ngakho-ke qaphela amagama ayimfihlo, imininingwane yokukhokha, imiyalezo, noma olunye ulwazi olubucayi."</string> <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Qhubeka"</string> <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Yabelana noma rekhoda i-app"</string> + <!-- no translation found for media_projection_permission_dialog_system_service_title (6827129613741303726) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_entire_screen (8801616203805837575) --> + <skip /> + <!-- no translation found for media_projection_permission_dialog_system_service_warning_single_app (543310680568419338) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_title (2113331792064527203) --> + <skip /> + <!-- no translation found for screen_capturing_disabled_by_policy_dialog_description (6015975736747696431) --> + <skip /> <string name="clear_all_notifications_text" msgid="348312370303046130">"Sula konke"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Phatha"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Umlando"</string> diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml index df0659d67afe..f46266b339d1 100644 --- a/packages/SystemUI/res/values/attrs.xml +++ b/packages/SystemUI/res/values/attrs.xml @@ -204,5 +204,15 @@ <attr name="passwordTextAppearance" format="reference" /> <attr name="errorTextAppearance" format="reference"/> </declare-styleable> + + <declare-styleable name="BiometricsEnrollView"> + <attr name="biometricsEnrollStyle" format="reference" /> + <attr name="biometricsEnrollIcon" format="reference|color" /> + <attr name="biometricsMovingTargetFill" format="reference|color" /> + <attr name="biometricsMovingTargetFillError" format="reference|color" /> + <attr name="biometricsEnrollProgress" format="reference|color" /> + <attr name="biometricsEnrollProgressHelp" format="reference|color" /> + <attr name="biometricsEnrollProgressHelpWithTalkback" format="reference|color" /> + </declare-styleable> </resources> diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml index 75baeeff6025..4ce0852901ff 100644 --- a/packages/SystemUI/res/values/colors.xml +++ b/packages/SystemUI/res/values/colors.xml @@ -134,12 +134,12 @@ <color name="biometric_dialog_error">#ffd93025</color> <!-- red 600 --> <!-- UDFPS colors --> - <color name="udfps_enroll_icon">#7DA7F1</color> - <color name="udfps_moving_target_fill">#475670</color> + <color name="udfps_enroll_icon">#699FF3</color> + <color name="udfps_moving_target_fill">#C2D7F7</color> <!-- 50% of udfps_moving_target_fill--> - <color name="udfps_moving_target_fill_error">#80475670</color> - <color name="udfps_enroll_progress">#7DA7F1</color> - <color name="udfps_enroll_progress_help">#607DA7F1</color> + <color name="udfps_moving_target_fill_error">#80C2D7F7</color> + <color name="udfps_enroll_progress">#699FF3</color> + <color name="udfps_enroll_progress_help">#70699FF3</color> <color name="udfps_enroll_progress_help_with_talkback">#FFEE675C</color> <!-- Floating overlay actions --> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 93982cb2c5b9..ce9829b318cd 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -743,6 +743,17 @@ <integer name="complicationRestoreMs">1000</integer> + <!-- Duration in milliseconds of the dream in un-blur animation. --> + <integer name="config_dreamOverlayInBlurDurationMs">249</integer> + <!-- Delay in milliseconds of the dream in un-blur animation. --> + <integer name="config_dreamOverlayInBlurDelayMs">133</integer> + <!-- Duration in milliseconds of the dream in complications fade-in animation. --> + <integer name="config_dreamOverlayInComplicationsDurationMs">282</integer> + <!-- Delay in milliseconds of the dream in top complications fade-in animation. --> + <integer name="config_dreamOverlayInTopComplicationsDelayMs">216</integer> + <!-- Delay in milliseconds of the dream in bottom complications fade-in animation. --> + <integer name="config_dreamOverlayInBottomComplicationsDelayMs">299</integer> + <!-- Icons that don't show in a collapsed non-keyguard statusbar --> <string-array name="config_collapsed_statusbar_icon_blocklist" translatable="false"> <item>@*android:string/status_bar_volume</item> @@ -783,4 +794,8 @@ <item>@color/dream_overlay_aqi_very_unhealthy</item> <item>@color/dream_overlay_aqi_hazardous</item> </integer-array> + + <!-- Whether the device should display hotspot UI. If true, UI will display only when tethering + is available. If false, UI will never show regardless of tethering availability" --> + <bool name="config_show_wifi_tethering">true</bool> </resources> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 93926ef9e780..e8ae929a6782 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -407,7 +407,7 @@ <dimen name="match_parent">-1px</dimen> <!-- Height of status bar in split shade mode - visible only on large screens --> - <dimen name="large_screen_shade_header_height">@*android:dimen/quick_qs_offset_height</dimen> + <dimen name="large_screen_shade_header_height">48dp</dimen> <dimen name="large_screen_shade_header_min_height">@dimen/qs_header_row_min_height</dimen> <dimen name="large_screen_shade_header_left_padding">@dimen/qs_horizontal_margin</dimen> @@ -762,7 +762,7 @@ <dimen name="keyguard_lock_padding">20dp</dimen> <dimen name="keyguard_indication_margin_bottom">32dp</dimen> - <dimen name="lock_icon_margin_bottom">110dp</dimen> + <dimen name="lock_icon_margin_bottom">74dp</dimen> <dimen name="ambient_indication_margin_bottom">71dp</dimen> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 212c77b50477..72305c62030d 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -235,6 +235,8 @@ <string name="screenshot_left_boundary_pct">Left boundary <xliff:g id="percent" example="50">%1$d</xliff:g> percent</string> <!-- Content description for the right boundary of the screenshot being cropped, with the current position as a percentage. [CHAR LIMIT=NONE] --> <string name="screenshot_right_boundary_pct">Right boundary <xliff:g id="percent" example="50">%1$d</xliff:g> percent</string> + <!-- Notification displayed when a screenshot is saved in a work profile. [CHAR LIMIT=NONE] --> + <string name="screenshot_work_profile_notification" translatable="false">Work screenshots are saved in the work <xliff:g id="app" example="Files">%1$s</xliff:g> app</string> <!-- Notification title displayed for screen recording [CHAR LIMIT=50]--> <string name="screenrecord_name">Screen Recorder</string> @@ -403,6 +405,8 @@ <string name="keyguard_face_failed">Can\u2019t recognize face</string> <!-- Message shown to suggest using fingerprint sensor to authenticate after another biometric failed. [CHAR LIMIT=25] --> <string name="keyguard_suggest_fingerprint">Use fingerprint instead</string> + <!-- Message shown to inform the user that face unlock is not available. [CHAR LIMIT=25] --> + <string name="keyguard_face_unlock_unavailable">Face unlock unavailable.</string> <!-- Content description of the bluetooth icon when connected for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> <string name="accessibility_bluetooth_connected">Bluetooth connected.</string> @@ -989,6 +993,21 @@ <!-- Title of the dialog that allows to select an app to share or record [CHAR LIMIT=NONE] --> <string name="media_projection_permission_app_selector_title">Share or record an app</string> + <!-- Media projection permission dialog title when there is no app name (e.g. it could be a system service when casting). [CHAR LIMIT=100] --> + <string name="media_projection_permission_dialog_system_service_title">Allow this app to share or record?</string> + + <!-- Media projection permission warning for capturing the whole screen when a system service requests it (e.g. when casting). [CHAR LIMIT=350] --> + <string name="media_projection_permission_dialog_system_service_warning_entire_screen">When you\'re sharing, recording, or casting, this app has access to anything visible on your screen or played on your device. So be careful with passwords, payment details, messages, or other sensitive information.</string> + + <!-- Media projection permission warning for capturing a single app when a system service requests it (e.g. when casting). [CHAR LIMIT=350] --> + <string name="media_projection_permission_dialog_system_service_warning_single_app">When you\'re sharing, recording, or casting an app, this app has access to anything shown or played on that app. So be careful with passwords, payment details, messages, or other sensitive information.</string> + + <!-- Title for the dialog that is shown when screen capturing is disabled by enterprise policy. [CHAR LIMIT=100] --> + <string name="screen_capturing_disabled_by_policy_dialog_title">Blocked by your IT admin</string> + + <!-- Description for the dialog that is shown when screen capturing is disabled by enterprise policy. [CHAR LIMIT=350] --> + <string name="screen_capturing_disabled_by_policy_dialog_description">Screen capturing is disabled by device policy</string> + <!-- The text to clear all notifications. [CHAR LIMIT=60] --> <string name="clear_all_notifications_text">Clear all</string> @@ -1294,7 +1313,7 @@ <string name="wallet_lockscreen_settings_label">Lock screen settings</string> <!-- QR Code Scanner label, title [CHAR LIMIT=32] --> - <string name="qr_code_scanner_title">Scan QR code</string> + <string name="qr_code_scanner_title">QR code scanner</string> <!-- Name of the work status bar icon. --> <string name="status_bar_work">Work profile</string> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index e76887babc50..ff29039a962f 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -308,6 +308,10 @@ <!-- Needed for MediaRoute chooser dialog --> <item name="*android:isLightTheme">false</item> + + <!-- Biometrics enroll color style --> + <item name="biometricsEnrollStyle">@style/BiometricsEnrollStyle</item> + </style> <style name="Theme.SystemUI.LightWallpaper"> @@ -1274,4 +1278,13 @@ <item name="android:textColor">?androidprv:attr/textColorOnAccent</item> <item name="android:textSize">@dimen/broadcast_dialog_btn_text_size</item> </style> + + <style name="BiometricsEnrollStyle"> + <item name="biometricsEnrollIcon">@color/udfps_enroll_icon</item> + <item name="biometricsMovingTargetFill">@color/udfps_moving_target_fill</item> + <item name="biometricsMovingTargetFillError">@color/udfps_moving_target_fill_error</item> + <item name="biometricsEnrollProgress">@color/udfps_enroll_progress</item> + <item name="biometricsEnrollProgressHelp">@color/udfps_enroll_progress_help</item> + <item name="biometricsEnrollProgressHelpWithTalkback">@color/udfps_enroll_progress_help_with_talkback</item> + </style> </resources> diff --git a/packages/SystemUI/res/xml/large_screen_shade_header.xml b/packages/SystemUI/res/xml/large_screen_shade_header.xml index cdbf8ab0be41..06d425c57577 100644 --- a/packages/SystemUI/res/xml/large_screen_shade_header.xml +++ b/packages/SystemUI/res/xml/large_screen_shade_header.xml @@ -107,7 +107,7 @@ android:id="@+id/privacy_container"> <Layout android:layout_width="wrap_content" - android:layout_height="0dp" + android:layout_height="@dimen/large_screen_shade_header_min_height" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="@id/date" app:layout_constraintBottom_toBottomOf="@id/date" diff --git a/packages/SystemUI/res/xml/qqs_header.xml b/packages/SystemUI/res/xml/qqs_header.xml index 88b4f43b440b..af4be1ade656 100644 --- a/packages/SystemUI/res/xml/qqs_header.xml +++ b/packages/SystemUI/res/xml/qqs_header.xml @@ -98,7 +98,7 @@ android:id="@+id/privacy_container"> <Layout android:layout_width="wrap_content" - android:layout_height="0dp" + android:layout_height="@dimen/large_screen_shade_header_min_height" app:layout_constraintStart_toEndOf="@id/date" app:layout_constraintEnd_toEndOf="@id/end_guide" app:layout_constraintTop_toTopOf="parent" diff --git a/packages/SystemUI/shared/Android.bp b/packages/SystemUI/shared/Android.bp index 91fd6a60d0df..485a0d320bb9 100644 --- a/packages/SystemUI/shared/Android.bp +++ b/packages/SystemUI/shared/Android.bp @@ -52,7 +52,11 @@ android_library { "SystemUIUnfoldLib", "androidx.dynamicanimation_dynamicanimation", "androidx.concurrent_concurrent-futures", - "gson-prebuilt-jar", + "androidx.lifecycle_lifecycle-runtime-ktx", + "androidx.lifecycle_lifecycle-viewmodel-ktx", + "androidx.recyclerview_recyclerview", + "kotlinx_coroutines_android", + "kotlinx_coroutines", "dagger2", "jsr330", ], @@ -64,6 +68,7 @@ android_library { }, min_sdk_version: "current", plugins: ["dagger2-compiler"], + kotlincflags: ["-Xjvm-default=enable"], } java_library { diff --git a/packages/SystemUI/shared/src/com/android/systemui/flags/Flag.kt b/packages/SystemUI/shared/src/com/android/systemui/flags/Flag.kt index f7049cf8f4f2..196f7f05d20d 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/flags/Flag.kt +++ b/packages/SystemUI/shared/src/com/android/systemui/flags/Flag.kt @@ -22,9 +22,19 @@ import android.annotation.StringRes import android.os.Parcel import android.os.Parcelable +/** + * Base interface for flags that can change value on a running device. + * @property id unique id to help identify this flag. Must be unique. This will be removed soon. + * @property teamfood Set to true to include this flag as part of the teamfood flag. This will + * be removed soon. + * @property name Used for server-side flagging where appropriate. Also used for display. No spaces. + * @property namespace The server-side namespace that this flag lives under. + */ interface Flag<T> { val id: Int val teamfood: Boolean + val name: String + val namespace: String } interface ParcelableFlag<T> : Flag<T>, Parcelable { @@ -38,13 +48,10 @@ interface ResourceFlag<T> : Flag<T> { } interface DeviceConfigFlag<T> : Flag<T> { - val name: String - val namespace: String val default: T } interface SysPropFlag<T> : Flag<T> { - val name: String val default: T } @@ -56,6 +63,8 @@ interface SysPropFlag<T> : Flag<T> { // Consider using the "parcelize" kotlin library. abstract class BooleanFlag constructor( override val id: Int, + override val name: String, + override val namespace: String, override val default: Boolean = false, override val teamfood: Boolean = false, override val overridden: Boolean = false @@ -71,6 +80,8 @@ abstract class BooleanFlag constructor( private constructor(parcel: Parcel) : this( id = parcel.readInt(), + name = parcel.readString(), + namespace = parcel.readString(), default = parcel.readBoolean(), teamfood = parcel.readBoolean(), overridden = parcel.readBoolean() @@ -78,6 +89,8 @@ abstract class BooleanFlag constructor( override fun writeToParcel(parcel: Parcel, flags: Int) { parcel.writeInt(id) + parcel.writeString(name) + parcel.writeString(namespace) parcel.writeBoolean(default) parcel.writeBoolean(teamfood) parcel.writeBoolean(overridden) @@ -89,30 +102,36 @@ abstract class BooleanFlag constructor( * * It can be changed or overridden in debug builds but not in release builds. */ -data class UnreleasedFlag @JvmOverloads constructor( +data class UnreleasedFlag constructor( override val id: Int, + override val name: String, + override val namespace: String, override val teamfood: Boolean = false, override val overridden: Boolean = false -) : BooleanFlag(id, false, teamfood, overridden) +) : BooleanFlag(id, name, namespace, false, teamfood, overridden) /** - * A Flag that is is true by default. + * A Flag that is true by default. * * It can be changed or overridden in any build, meaning it can be turned off if needed. */ -data class ReleasedFlag @JvmOverloads constructor( +data class ReleasedFlag constructor( override val id: Int, + override val name: String, + override val namespace: String, override val teamfood: Boolean = false, override val overridden: Boolean = false -) : BooleanFlag(id, true, teamfood, overridden) +) : BooleanFlag(id, name, namespace, true, teamfood, overridden) /** * A Flag that reads its default values from a resource overlay instead of code. * * Prefer [UnreleasedFlag] and [ReleasedFlag]. */ -data class ResourceBooleanFlag @JvmOverloads constructor( +data class ResourceBooleanFlag constructor( override val id: Int, + override val name: String, + override val namespace: String, @BoolRes override val resourceId: Int, override val teamfood: Boolean = false ) : ResourceFlag<Boolean> @@ -124,7 +143,7 @@ data class ResourceBooleanFlag @JvmOverloads constructor( * * Prefer [UnreleasedFlag] and [ReleasedFlag]. */ -data class DeviceConfigBooleanFlag @JvmOverloads constructor( +data class DeviceConfigBooleanFlag constructor( override val id: Int, override val name: String, override val namespace: String, @@ -139,17 +158,20 @@ data class DeviceConfigBooleanFlag @JvmOverloads constructor( * * Prefer [UnreleasedFlag] and [ReleasedFlag]. */ -data class SysPropBooleanFlag @JvmOverloads constructor( +data class SysPropBooleanFlag constructor( override val id: Int, override val name: String, - override val default: Boolean = false + override val namespace: String, + override val default: Boolean = false, ) : SysPropFlag<Boolean> { // TODO(b/223379190): Teamfood not supported for sysprop flags yet. override val teamfood: Boolean = false } -data class StringFlag @JvmOverloads constructor( +data class StringFlag constructor( override val id: Int, + override val name: String, + override val namespace: String, override val default: String = "", override val teamfood: Boolean = false, override val overridden: Boolean = false @@ -164,23 +186,31 @@ data class StringFlag @JvmOverloads constructor( private constructor(parcel: Parcel) : this( id = parcel.readInt(), + name = parcel.readString(), + namespace = parcel.readString(), default = parcel.readString() ?: "" ) override fun writeToParcel(parcel: Parcel, flags: Int) { parcel.writeInt(id) + parcel.writeString(name) + parcel.writeString(namespace) parcel.writeString(default) } } -data class ResourceStringFlag @JvmOverloads constructor( +data class ResourceStringFlag constructor( override val id: Int, + override val name: String, + override val namespace: String, @StringRes override val resourceId: Int, override val teamfood: Boolean = false ) : ResourceFlag<String> -data class IntFlag @JvmOverloads constructor( +data class IntFlag constructor( override val id: Int, + override val name: String, + override val namespace: String, override val default: Int = 0, override val teamfood: Boolean = false, override val overridden: Boolean = false @@ -196,25 +226,33 @@ data class IntFlag @JvmOverloads constructor( private constructor(parcel: Parcel) : this( id = parcel.readInt(), + name = parcel.readString(), + namespace = parcel.readString(), default = parcel.readInt() ) override fun writeToParcel(parcel: Parcel, flags: Int) { parcel.writeInt(id) + parcel.writeString(name) + parcel.writeString(namespace) parcel.writeInt(default) } } -data class ResourceIntFlag @JvmOverloads constructor( +data class ResourceIntFlag constructor( override val id: Int, + override val name: String, + override val namespace: String, @IntegerRes override val resourceId: Int, override val teamfood: Boolean = false ) : ResourceFlag<Int> -data class LongFlag @JvmOverloads constructor( +data class LongFlag constructor( override val id: Int, override val default: Long = 0, override val teamfood: Boolean = false, + override val name: String, + override val namespace: String, override val overridden: Boolean = false ) : ParcelableFlag<Long> { @@ -228,17 +266,23 @@ data class LongFlag @JvmOverloads constructor( private constructor(parcel: Parcel) : this( id = parcel.readInt(), + name = parcel.readString(), + namespace = parcel.readString(), default = parcel.readLong() ) override fun writeToParcel(parcel: Parcel, flags: Int) { parcel.writeInt(id) + parcel.writeString(name) + parcel.writeString(namespace) parcel.writeLong(default) } } -data class FloatFlag @JvmOverloads constructor( +data class FloatFlag constructor( override val id: Int, + override val name: String, + override val namespace: String, override val default: Float = 0f, override val teamfood: Boolean = false, override val overridden: Boolean = false @@ -254,23 +298,31 @@ data class FloatFlag @JvmOverloads constructor( private constructor(parcel: Parcel) : this( id = parcel.readInt(), + name = parcel.readString(), + namespace = parcel.readString(), default = parcel.readFloat() ) override fun writeToParcel(parcel: Parcel, flags: Int) { parcel.writeInt(id) + parcel.writeString(name) + parcel.writeString(namespace) parcel.writeFloat(default) } } -data class ResourceFloatFlag @JvmOverloads constructor( +data class ResourceFloatFlag constructor( override val id: Int, + override val name: String, + override val namespace: String, override val resourceId: Int, - override val teamfood: Boolean = false + override val teamfood: Boolean = false, ) : ResourceFlag<Int> -data class DoubleFlag @JvmOverloads constructor( +data class DoubleFlag constructor( override val id: Int, + override val name: String, + override val namespace: String, override val default: Double = 0.0, override val teamfood: Boolean = false, override val overridden: Boolean = false @@ -286,11 +338,15 @@ data class DoubleFlag @JvmOverloads constructor( private constructor(parcel: Parcel) : this( id = parcel.readInt(), + name = parcel.readString(), + namespace = parcel.readString(), default = parcel.readDouble() ) override fun writeToParcel(parcel: Parcel, flags: Int) { parcel.writeInt(id) + parcel.writeString(name) + parcel.writeString(namespace) parcel.writeDouble(default) } } diff --git a/packages/SystemUI/shared/src/com/android/systemui/flags/FlagSerializer.kt b/packages/SystemUI/shared/src/com/android/systemui/flags/FlagSerializer.kt index e9ea19dad424..eeb6031df6d9 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/flags/FlagSerializer.kt +++ b/packages/SystemUI/shared/src/com/android/systemui/flags/FlagSerializer.kt @@ -24,6 +24,7 @@ private const val FIELD_VALUE = "value" private const val FIELD_TYPE = "type" private const val TYPE_BOOLEAN = "boolean" private const val TYPE_STRING = "string" +private const val TYPE_INT = "int" private const val TAG = "FlagSerializer" @@ -77,4 +78,10 @@ object StringFlagSerializer : FlagSerializer<String>( JSONObject::getString ) +object IntFlagSerializer : FlagSerializer<Int>( + TYPE_INT, + JSONObject::put, + JSONObject::getInt +) + class InvalidFlagStorageException : Exception("Data found but is invalid") diff --git a/packages/SystemUI/shared/src/com/android/systemui/navigationbar/buttons/KeyButtonRipple.java b/packages/SystemUI/shared/src/com/android/systemui/navigationbar/buttons/KeyButtonRipple.java index 8aa3abac831f..a14f97128662 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/navigationbar/buttons/KeyButtonRipple.java +++ b/packages/SystemUI/shared/src/com/android/systemui/navigationbar/buttons/KeyButtonRipple.java @@ -291,8 +291,10 @@ public class KeyButtonRipple extends Drawable { } private void endAnimations(String reason, boolean cancel) { - Trace.beginSection("KeyButtonRipple.endAnim: reason=" + reason + " cancel=" + cancel); - Trace.endSection(); + if (Trace.isEnabled()) { + Trace.instant(Trace.TRACE_TAG_APP, + "KeyButtonRipple.endAnim: reason=" + reason + " cancel=" + cancel); + } mVisible = false; mTmpArray.addAll(mRunningAnimations); int size = mTmpArray.size(); @@ -502,20 +504,23 @@ public class KeyButtonRipple extends Drawable { @Override public void onAnimationStart(Animator animation) { - Trace.beginSection("KeyButtonRipple.start." + mName); - Trace.endSection(); + if (Trace.isEnabled()) { + Trace.instant(Trace.TRACE_TAG_APP, "KeyButtonRipple.start." + mName); + } } @Override public void onAnimationCancel(Animator animation) { - Trace.beginSection("KeyButtonRipple.cancel." + mName); - Trace.endSection(); + if (Trace.isEnabled()) { + Trace.instant(Trace.TRACE_TAG_APP, "KeyButtonRipple.cancel." + mName); + } } @Override public void onAnimationEnd(Animator animation) { - Trace.beginSection("KeyButtonRipple.end." + mName); - Trace.endSection(); + if (Trace.isEnabled()) { + Trace.instant(Trace.TRACE_TAG_APP, "KeyButtonRipple.end." + mName); + } } } diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/ClockRegistry.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/ClockRegistry.kt index 48821e8d0bd3..601cb66d99c2 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/ClockRegistry.kt +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/ClockRegistry.kt @@ -28,7 +28,7 @@ import com.android.systemui.plugins.ClockProvider import com.android.systemui.plugins.ClockProviderPlugin import com.android.systemui.plugins.PluginListener import com.android.systemui.shared.plugins.PluginManager -import com.google.gson.Gson +import org.json.JSONObject private val TAG = ClockRegistry::class.simpleName private const val DEBUG = true @@ -47,7 +47,6 @@ open class ClockRegistry( fun onClockChanged() } - private val gson = Gson() private val availableClocks = mutableMapOf<ClockId, ClockInfo>() private val clockChangeListeners = mutableListOf<ClockChangeListener>() private val settingObserver = object : ContentObserver(handler) { @@ -70,7 +69,7 @@ open class ClockRegistry( context.contentResolver, Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE ) - gson.fromJson(json, ClockSetting::class.java)?.clockId ?: DEFAULT_CLOCK_ID + ClockSetting.deserialize(json)?.clockId ?: DEFAULT_CLOCK_ID } catch (ex: Exception) { Log.e(TAG, "Failed to parse clock setting", ex) DEFAULT_CLOCK_ID @@ -78,7 +77,7 @@ open class ClockRegistry( } set(value) { try { - val json = gson.toJson(ClockSetting(value, System.currentTimeMillis())) + val json = ClockSetting.serialize(ClockSetting(value, System.currentTimeMillis())) Settings.Secure.putString( context.contentResolver, Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE, json @@ -198,8 +197,27 @@ open class ClockRegistry( ) @Keep - private data class ClockSetting( + data class ClockSetting( val clockId: ClockId, val _applied_timestamp: Long? - ) + ) { + companion object { + private val KEY_CLOCK_ID = "clockId" + private val KEY_TIMESTAMP = "_applied_timestamp" + + fun serialize(setting: ClockSetting): String { + return JSONObject() + .put(KEY_CLOCK_ID, setting.clockId) + .put(KEY_TIMESTAMP, setting._applied_timestamp) + .toString() + } + + fun deserialize(jsonStr: String): ClockSetting { + val json = JSONObject(jsonStr) + return ClockSetting( + json.getString(KEY_CLOCK_ID), + if (!json.isNull(KEY_TIMESTAMP)) json.getLong(KEY_TIMESTAMP) else null) + } + } + } } diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/DefaultClockController.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/DefaultClockController.kt index 3961438ff591..ca780c8dd3c9 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/DefaultClockController.kt +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/DefaultClockController.kt @@ -188,13 +188,10 @@ class DefaultClockController( dozeFraction: Float, foldFraction: Float, ) : ClockAnimations { - private var foldState = AnimationState(0f) - private var dozeState = AnimationState(0f) + private val dozeState = AnimationState(dozeFraction) + private val foldState = AnimationState(foldFraction) init { - dozeState = AnimationState(dozeFraction) - foldState = AnimationState(foldFraction) - if (foldState.isActive) { clocks.forEach { it.animateFoldAppear(false) } } else { @@ -235,7 +232,7 @@ class DefaultClockController( private class AnimationState( var fraction: Float, ) { - var isActive: Boolean = fraction < 0.5f + var isActive: Boolean = fraction > 0.5f fun update(newFraction: Float): Pair<Boolean, Boolean> { if (newFraction == fraction) { return Pair(isActive, false) diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl index bfbe88c475ac..abefeba9c417 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl @@ -60,11 +60,6 @@ oneway interface IOverviewProxy { void onSystemUiStateChanged(int stateFlags) = 16; /** - * Sent when the split screen is resized - */ - void onSplitScreenSecondaryBoundsChanged(in Rect bounds, in Rect insets) = 17; - - /** * Sent when suggested rotation button could be shown */ void onRotationProposal(int rotation, boolean isValid) = 18; diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl index b99b72bb4275..1c532fe7a529 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl @@ -24,7 +24,6 @@ import android.os.UserHandle; import android.view.MotionEvent; import com.android.systemui.shared.recents.model.Task; -import com.android.systemui.shared.system.RemoteTransitionCompat; /** * Temporary callbacks into SystemUI. diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java index 647dd47159e0..08904658a27d 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java @@ -20,7 +20,7 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.view.Display.DEFAULT_DISPLAY; import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_ACTIVITY_TYPES; -import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_WINDOWING_MODES; +import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_WINDOWING_MODES_WHEN_ACTIVE; import android.app.ActivityManager; import android.app.ActivityManager.TaskDescription; @@ -255,7 +255,8 @@ public class Task { // Also consider undefined activity type to include tasks in overview right after rebooting // the device. final boolean isDockable = taskInfo.supportsMultiWindow - && ArrayUtils.contains(CONTROLLED_WINDOWING_MODES, taskInfo.getWindowingMode()) + && ArrayUtils.contains( + CONTROLLED_WINDOWING_MODES_WHEN_ACTIVE, taskInfo.getWindowingMode()) && (taskInfo.getActivityType() == ACTIVITY_TYPE_UNDEFINED || ArrayUtils.contains(CONTROLLED_ACTIVITY_TYPES, taskInfo.getActivityType())); return new Task(taskKey, diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java index 8a2509610310..82d70116bbff 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java @@ -53,6 +53,8 @@ public final class InteractionJankMonitorWrapper { InteractionJankMonitor.CUJ_LAUNCHER_UNLOCK_ENTRANCE_ANIMATION; public static final int CUJ_RECENTS_SCROLLING = InteractionJankMonitor.CUJ_RECENTS_SCROLLING; + public static final int CUJ_APP_SWIPE_TO_RECENTS = + InteractionJankMonitor.CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS; @IntDef({ CUJ_APP_LAUNCH_FROM_RECENTS, @@ -62,7 +64,8 @@ public final class InteractionJankMonitorWrapper { CUJ_QUICK_SWITCH, CUJ_APP_LAUNCH_FROM_WIDGET, CUJ_LAUNCHER_UNLOCK_ENTRANCE_ANIMATION, - CUJ_RECENTS_SCROLLING + CUJ_RECENTS_SCROLLING, + CUJ_APP_SWIPE_TO_RECENTS }) @Retention(RetentionPolicy.SOURCE) public @interface CujType { diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java deleted file mode 100644 index 37e706a9a4c9..000000000000 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java +++ /dev/null @@ -1,258 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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.shared.system; - -import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; -import static android.view.WindowManager.TRANSIT_CLOSE; -import static android.view.WindowManager.TRANSIT_OLD_NONE; -import static android.view.WindowManager.TRANSIT_OPEN; -import static android.view.WindowManager.TRANSIT_TO_BACK; -import static android.view.WindowManager.TRANSIT_TO_FRONT; -import static android.view.WindowManager.TransitionOldType; -import static android.window.TransitionInfo.FLAG_IS_WALLPAPER; - -import android.annotation.SuppressLint; -import android.app.IApplicationThread; -import android.os.IBinder; -import android.os.RemoteException; -import android.util.ArrayMap; -import android.util.Log; -import android.view.IRemoteAnimationFinishedCallback; -import android.view.IRemoteAnimationRunner; -import android.view.RemoteAnimationAdapter; -import android.view.RemoteAnimationTarget; -import android.view.SurfaceControl; -import android.window.IRemoteTransition; -import android.window.IRemoteTransitionFinishedCallback; -import android.window.RemoteTransition; -import android.window.TransitionInfo; - -import com.android.wm.shell.util.CounterRotator; - -/** - * @see RemoteAnimationAdapter - */ -public class RemoteAnimationAdapterCompat { - - private final RemoteAnimationAdapter mWrapped; - private final RemoteTransitionCompat mRemoteTransition; - - public RemoteAnimationAdapterCompat(RemoteAnimationRunnerCompat runner, long duration, - long statusBarTransitionDelay, IApplicationThread appThread) { - mWrapped = new RemoteAnimationAdapter(wrapRemoteAnimationRunner(runner), duration, - statusBarTransitionDelay); - mRemoteTransition = buildRemoteTransition(runner, appThread); - } - - public RemoteAnimationAdapter getWrapped() { - return mWrapped; - } - - /** Helper to just build a remote transition. Use this if the legacy adapter isn't needed. */ - public static RemoteTransitionCompat buildRemoteTransition(RemoteAnimationRunnerCompat runner, - IApplicationThread appThread) { - return new RemoteTransitionCompat( - new RemoteTransition(wrapRemoteTransition(runner), appThread)); - } - - public RemoteTransitionCompat getRemoteTransition() { - return mRemoteTransition; - } - - /** Wraps a RemoteAnimationRunnerCompat in an IRemoteAnimationRunner. */ - public static IRemoteAnimationRunner.Stub wrapRemoteAnimationRunner( - final RemoteAnimationRunnerCompat remoteAnimationAdapter) { - return new IRemoteAnimationRunner.Stub() { - @Override - public void onAnimationStart(@TransitionOldType int transit, - RemoteAnimationTarget[] apps, - RemoteAnimationTarget[] wallpapers, - RemoteAnimationTarget[] nonApps, - final IRemoteAnimationFinishedCallback finishedCallback) { - final Runnable animationFinishedCallback = new Runnable() { - @Override - public void run() { - try { - finishedCallback.onAnimationFinished(); - } catch (RemoteException e) { - Log.e("ActivityOptionsCompat", "Failed to call app controlled animation" - + " finished callback", e); - } - } - }; - remoteAnimationAdapter.onAnimationStart(transit, apps, wallpapers, - nonApps, animationFinishedCallback); - } - - @Override - public void onAnimationCancelled(boolean isKeyguardOccluded) { - remoteAnimationAdapter.onAnimationCancelled(); - } - }; - } - - private static IRemoteTransition.Stub wrapRemoteTransition( - final RemoteAnimationRunnerCompat remoteAnimationAdapter) { - return new IRemoteTransition.Stub() { - final ArrayMap<IBinder, Runnable> mFinishRunnables = new ArrayMap<>(); - - @Override - public void startAnimation(IBinder token, TransitionInfo info, - SurfaceControl.Transaction t, - IRemoteTransitionFinishedCallback finishCallback) { - final ArrayMap<SurfaceControl, SurfaceControl> leashMap = new ArrayMap<>(); - final RemoteAnimationTarget[] apps = - RemoteAnimationTargetCompat.wrapApps(info, t, leashMap); - final RemoteAnimationTarget[] wallpapers = - RemoteAnimationTargetCompat.wrapNonApps( - info, true /* wallpapers */, t, leashMap); - final RemoteAnimationTarget[] nonApps = - RemoteAnimationTargetCompat.wrapNonApps( - info, false /* wallpapers */, t, leashMap); - - // TODO(b/177438007): Move this set-up logic into launcher's animation impl. - boolean isReturnToHome = false; - TransitionInfo.Change launcherTask = null; - TransitionInfo.Change wallpaper = null; - int launcherLayer = 0; - int rotateDelta = 0; - float displayW = 0; - float displayH = 0; - for (int i = info.getChanges().size() - 1; i >= 0; --i) { - final TransitionInfo.Change change = info.getChanges().get(i); - // skip changes that we didn't wrap - if (!leashMap.containsKey(change.getLeash())) continue; - if (change.getTaskInfo() != null - && change.getTaskInfo().getActivityType() == ACTIVITY_TYPE_HOME) { - isReturnToHome = change.getMode() == TRANSIT_OPEN - || change.getMode() == TRANSIT_TO_FRONT; - launcherTask = change; - launcherLayer = info.getChanges().size() - i; - } else if ((change.getFlags() & FLAG_IS_WALLPAPER) != 0) { - wallpaper = change; - } - if (change.getParent() == null && change.getEndRotation() >= 0 - && change.getEndRotation() != change.getStartRotation()) { - rotateDelta = change.getEndRotation() - change.getStartRotation(); - displayW = change.getEndAbsBounds().width(); - displayH = change.getEndAbsBounds().height(); - } - } - - // Prepare for rotation if there is one - final CounterRotator counterLauncher = new CounterRotator(); - final CounterRotator counterWallpaper = new CounterRotator(); - if (launcherTask != null && rotateDelta != 0 && launcherTask.getParent() != null) { - counterLauncher.setup(t, info.getChange(launcherTask.getParent()).getLeash(), - rotateDelta, displayW, displayH); - if (counterLauncher.getSurface() != null) { - t.setLayer(counterLauncher.getSurface(), launcherLayer); - } - } - - if (isReturnToHome) { - if (counterLauncher.getSurface() != null) { - t.setLayer(counterLauncher.getSurface(), info.getChanges().size() * 3); - } - // Need to "boost" the closing things since that's what launcher expects. - for (int i = info.getChanges().size() - 1; i >= 0; --i) { - final TransitionInfo.Change change = info.getChanges().get(i); - final SurfaceControl leash = leashMap.get(change.getLeash()); - // skip changes that we didn't wrap - if (leash == null) continue; - final int mode = info.getChanges().get(i).getMode(); - // Only deal with independent layers - if (!TransitionInfo.isIndependent(change, info)) continue; - if (mode == TRANSIT_CLOSE || mode == TRANSIT_TO_BACK) { - t.setLayer(leash, info.getChanges().size() * 3 - i); - counterLauncher.addChild(t, leash); - } - } - // Make wallpaper visible immediately since launcher apparently won't do this. - for (int i = wallpapers.length - 1; i >= 0; --i) { - t.show(wallpapers[i].leash); - t.setAlpha(wallpapers[i].leash, 1.f); - } - } else { - if (launcherTask != null) { - counterLauncher.addChild(t, leashMap.get(launcherTask.getLeash())); - } - if (wallpaper != null && rotateDelta != 0 && wallpaper.getParent() != null) { - counterWallpaper.setup(t, info.getChange(wallpaper.getParent()).getLeash(), - rotateDelta, displayW, displayH); - if (counterWallpaper.getSurface() != null) { - t.setLayer(counterWallpaper.getSurface(), -1); - counterWallpaper.addChild(t, leashMap.get(wallpaper.getLeash())); - } - } - } - t.apply(); - - final Runnable animationFinishedCallback = new Runnable() { - @Override - @SuppressLint("NewApi") - public void run() { - final SurfaceControl.Transaction finishTransaction = - new SurfaceControl.Transaction(); - counterLauncher.cleanUp(finishTransaction); - counterWallpaper.cleanUp(finishTransaction); - // Release surface references now. This is apparently to free GPU memory - // while doing quick operations (eg. during CTS). - for (int i = info.getChanges().size() - 1; i >= 0; --i) { - info.getChanges().get(i).getLeash().release(); - } - // Don't release here since launcher might still be using them. Instead - // let launcher release them (eg. via RemoteAnimationTargets) - leashMap.clear(); - try { - finishCallback.onTransitionFinished(null /* wct */, finishTransaction); - } catch (RemoteException e) { - Log.e("ActivityOptionsCompat", "Failed to call app controlled animation" - + " finished callback", e); - } - } - }; - synchronized (mFinishRunnables) { - mFinishRunnables.put(token, animationFinishedCallback); - } - // TODO(bc-unlcok): Pass correct transit type. - remoteAnimationAdapter.onAnimationStart(TRANSIT_OLD_NONE, - apps, wallpapers, nonApps, () -> { - synchronized (mFinishRunnables) { - if (mFinishRunnables.remove(token) == null) return; - } - animationFinishedCallback.run(); - }); - } - - @Override - public void mergeAnimation(IBinder token, TransitionInfo info, - SurfaceControl.Transaction t, IBinder mergeTarget, - IRemoteTransitionFinishedCallback finishCallback) { - // TODO: hook up merge to recents onTaskAppeared if applicable. Until then, adapt - // to legacy cancel. - final Runnable finishRunnable; - synchronized (mFinishRunnables) { - finishRunnable = mFinishRunnables.remove(mergeTarget); - } - if (finishRunnable == null) return; - remoteAnimationAdapter.onAnimationCancelled(); - finishRunnable.run(); - } - }; - } -} diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationDefinitionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationDefinitionCompat.java deleted file mode 100644 index ab55037159ef..000000000000 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationDefinitionCompat.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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.shared.system; - -import android.view.RemoteAnimationDefinition; - -/** - * @see RemoteAnimationDefinition - */ -public class RemoteAnimationDefinitionCompat { - - private final RemoteAnimationDefinition mWrapped = new RemoteAnimationDefinition(); - - public void addRemoteAnimation(int transition, RemoteAnimationAdapterCompat adapter) { - mWrapped.addRemoteAnimation(transition, adapter.getWrapped()); - } - - public void addRemoteAnimation(int transition, int activityTypeFilter, - RemoteAnimationAdapterCompat adapter) { - mWrapped.addRemoteAnimation(transition, activityTypeFilter, adapter.getWrapped()); - } - - public RemoteAnimationDefinition getWrapped() { - return mWrapped; - } -} diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationRunnerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationRunnerCompat.java index 5809c8124946..93c807352521 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationRunnerCompat.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationRunnerCompat.java @@ -16,12 +16,197 @@ package com.android.systemui.shared.system; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; +import static android.view.WindowManager.TRANSIT_CLOSE; +import static android.view.WindowManager.TRANSIT_OLD_NONE; +import static android.view.WindowManager.TRANSIT_OPEN; +import static android.view.WindowManager.TRANSIT_TO_BACK; +import static android.view.WindowManager.TRANSIT_TO_FRONT; +import static android.window.TransitionInfo.FLAG_IS_WALLPAPER; + +import android.os.IBinder; +import android.os.RemoteException; +import android.util.ArrayMap; +import android.util.Log; +import android.view.IRemoteAnimationFinishedCallback; +import android.view.IRemoteAnimationRunner; import android.view.RemoteAnimationTarget; +import android.view.SurfaceControl; import android.view.WindowManager; +import android.view.WindowManager.TransitionOldType; +import android.window.IRemoteTransition; +import android.window.IRemoteTransitionFinishedCallback; +import android.window.TransitionInfo; + +import com.android.wm.shell.util.CounterRotator; + +public abstract class RemoteAnimationRunnerCompat extends IRemoteAnimationRunner.Stub { -public interface RemoteAnimationRunnerCompat { - void onAnimationStart(@WindowManager.TransitionOldType int transit, + public abstract void onAnimationStart(@WindowManager.TransitionOldType int transit, RemoteAnimationTarget[] apps, RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps, Runnable finishedCallback); - void onAnimationCancelled(); + + @Override + public final void onAnimationStart(@TransitionOldType int transit, + RemoteAnimationTarget[] apps, + RemoteAnimationTarget[] wallpapers, + RemoteAnimationTarget[] nonApps, + final IRemoteAnimationFinishedCallback finishedCallback) { + + onAnimationStart(transit, apps, wallpapers, + nonApps, () -> { + try { + finishedCallback.onAnimationFinished(); + } catch (RemoteException e) { + Log.e("ActivityOptionsCompat", "Failed to call app controlled animation" + + " finished callback", e); + } + }); + } + + public IRemoteTransition toRemoteTransition() { + return new IRemoteTransition.Stub() { + final ArrayMap<IBinder, Runnable> mFinishRunnables = new ArrayMap<>(); + + @Override + public void startAnimation(IBinder token, TransitionInfo info, + SurfaceControl.Transaction t, + IRemoteTransitionFinishedCallback finishCallback) { + final ArrayMap<SurfaceControl, SurfaceControl> leashMap = new ArrayMap<>(); + final RemoteAnimationTarget[] apps = + RemoteAnimationTargetCompat.wrapApps(info, t, leashMap); + final RemoteAnimationTarget[] wallpapers = + RemoteAnimationTargetCompat.wrapNonApps( + info, true /* wallpapers */, t, leashMap); + final RemoteAnimationTarget[] nonApps = + RemoteAnimationTargetCompat.wrapNonApps( + info, false /* wallpapers */, t, leashMap); + + // TODO(b/177438007): Move this set-up logic into launcher's animation impl. + boolean isReturnToHome = false; + TransitionInfo.Change launcherTask = null; + TransitionInfo.Change wallpaper = null; + int launcherLayer = 0; + int rotateDelta = 0; + float displayW = 0; + float displayH = 0; + for (int i = info.getChanges().size() - 1; i >= 0; --i) { + final TransitionInfo.Change change = info.getChanges().get(i); + // skip changes that we didn't wrap + if (!leashMap.containsKey(change.getLeash())) continue; + if (change.getTaskInfo() != null + && change.getTaskInfo().getActivityType() == ACTIVITY_TYPE_HOME) { + isReturnToHome = change.getMode() == TRANSIT_OPEN + || change.getMode() == TRANSIT_TO_FRONT; + launcherTask = change; + launcherLayer = info.getChanges().size() - i; + } else if ((change.getFlags() & FLAG_IS_WALLPAPER) != 0) { + wallpaper = change; + } + if (change.getParent() == null && change.getEndRotation() >= 0 + && change.getEndRotation() != change.getStartRotation()) { + rotateDelta = change.getEndRotation() - change.getStartRotation(); + displayW = change.getEndAbsBounds().width(); + displayH = change.getEndAbsBounds().height(); + } + } + + // Prepare for rotation if there is one + final CounterRotator counterLauncher = new CounterRotator(); + final CounterRotator counterWallpaper = new CounterRotator(); + if (launcherTask != null && rotateDelta != 0 && launcherTask.getParent() != null) { + counterLauncher.setup(t, info.getChange(launcherTask.getParent()).getLeash(), + rotateDelta, displayW, displayH); + if (counterLauncher.getSurface() != null) { + t.setLayer(counterLauncher.getSurface(), launcherLayer); + } + } + + if (isReturnToHome) { + if (counterLauncher.getSurface() != null) { + t.setLayer(counterLauncher.getSurface(), info.getChanges().size() * 3); + } + // Need to "boost" the closing things since that's what launcher expects. + for (int i = info.getChanges().size() - 1; i >= 0; --i) { + final TransitionInfo.Change change = info.getChanges().get(i); + final SurfaceControl leash = leashMap.get(change.getLeash()); + // skip changes that we didn't wrap + if (leash == null) continue; + final int mode = info.getChanges().get(i).getMode(); + // Only deal with independent layers + if (!TransitionInfo.isIndependent(change, info)) continue; + if (mode == TRANSIT_CLOSE || mode == TRANSIT_TO_BACK) { + t.setLayer(leash, info.getChanges().size() * 3 - i); + counterLauncher.addChild(t, leash); + } + } + // Make wallpaper visible immediately since launcher apparently won't do this. + for (int i = wallpapers.length - 1; i >= 0; --i) { + t.show(wallpapers[i].leash); + t.setAlpha(wallpapers[i].leash, 1.f); + } + } else { + if (launcherTask != null) { + counterLauncher.addChild(t, leashMap.get(launcherTask.getLeash())); + } + if (wallpaper != null && rotateDelta != 0 && wallpaper.getParent() != null) { + counterWallpaper.setup(t, info.getChange(wallpaper.getParent()).getLeash(), + rotateDelta, displayW, displayH); + if (counterWallpaper.getSurface() != null) { + t.setLayer(counterWallpaper.getSurface(), -1); + counterWallpaper.addChild(t, leashMap.get(wallpaper.getLeash())); + } + } + } + t.apply(); + + final Runnable animationFinishedCallback = () -> { + final SurfaceControl.Transaction finishTransaction = + new SurfaceControl.Transaction(); + counterLauncher.cleanUp(finishTransaction); + counterWallpaper.cleanUp(finishTransaction); + // Release surface references now. This is apparently to free GPU memory + // while doing quick operations (eg. during CTS). + for (int i = info.getChanges().size() - 1; i >= 0; --i) { + info.getChanges().get(i).getLeash().release(); + } + // Don't release here since launcher might still be using them. Instead + // let launcher release them (eg. via RemoteAnimationTargets) + leashMap.clear(); + try { + finishCallback.onTransitionFinished(null /* wct */, finishTransaction); + } catch (RemoteException e) { + Log.e("ActivityOptionsCompat", "Failed to call app controlled animation" + + " finished callback", e); + } + }; + synchronized (mFinishRunnables) { + mFinishRunnables.put(token, animationFinishedCallback); + } + // TODO(bc-unlcok): Pass correct transit type. + onAnimationStart(TRANSIT_OLD_NONE, + apps, wallpapers, nonApps, () -> { + synchronized (mFinishRunnables) { + if (mFinishRunnables.remove(token) == null) return; + } + animationFinishedCallback.run(); + }); + } + + @Override + public void mergeAnimation(IBinder token, TransitionInfo info, + SurfaceControl.Transaction t, IBinder mergeTarget, + IRemoteTransitionFinishedCallback finishCallback) throws RemoteException { + // TODO: hook up merge to recents onTaskAppeared if applicable. Until then, adapt + // to legacy cancel. + final Runnable finishRunnable; + synchronized (mFinishRunnables) { + finishRunnable = mFinishRunnables.remove(mergeTarget); + } + if (finishRunnable == null) return; + onAnimationCancelled(false /* isKeyguardOccluded */); + finishRunnable.run(); + } + }; + } }
\ No newline at end of file diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java index d6655a74219c..d4d3d2579b10 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java @@ -18,29 +18,22 @@ package com.android.systemui.shared.system; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.view.RemoteAnimationTarget.MODE_CLOSING; import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_CLOSE; -import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_LOCKED; import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_TO_BACK; import static android.view.WindowManager.TRANSIT_TO_FRONT; -import static android.window.TransitionFilter.CONTAINER_ORDER_TOP; import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.newTarget; -import android.annotation.NonNull; -import android.annotation.Nullable; import android.annotation.SuppressLint; import android.app.ActivityManager; import android.app.ActivityTaskManager; import android.app.IApplicationThread; -import android.content.ComponentName; import android.graphics.Rect; import android.os.IBinder; -import android.os.Parcelable; import android.os.RemoteException; import android.util.ArrayMap; import android.util.Log; @@ -53,72 +46,23 @@ import android.window.IRemoteTransitionFinishedCallback; import android.window.PictureInPictureSurfaceTransaction; import android.window.RemoteTransition; import android.window.TaskSnapshot; -import android.window.TransitionFilter; import android.window.TransitionInfo; import android.window.WindowContainerToken; import android.window.WindowContainerTransaction; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.DataClass; import com.android.systemui.shared.recents.model.ThumbnailData; import java.util.ArrayList; -import java.util.concurrent.Executor; /** - * Wrapper to expose RemoteTransition (shell transitions) to Launcher. - * - * @see IRemoteTransition - * @see TransitionFilter + * Helper class to build {@link RemoteTransition} objects */ -@DataClass -public class RemoteTransitionCompat implements Parcelable { +public class RemoteTransitionCompat { private static final String TAG = "RemoteTransitionCompat"; - @NonNull final RemoteTransition mTransition; - @Nullable TransitionFilter mFilter = null; - - RemoteTransitionCompat(RemoteTransition transition) { - mTransition = transition; - } - - public RemoteTransitionCompat(@NonNull RemoteTransitionRunner runner, - @NonNull Executor executor, @Nullable IApplicationThread appThread) { - IRemoteTransition remote = new IRemoteTransition.Stub() { - @Override - public void startAnimation(IBinder transition, TransitionInfo info, - SurfaceControl.Transaction t, - IRemoteTransitionFinishedCallback finishedCallback) { - final Runnable finishAdapter = () -> { - try { - finishedCallback.onTransitionFinished(null /* wct */, null /* sct */); - } catch (RemoteException e) { - Log.e(TAG, "Failed to call transition finished callback", e); - } - }; - executor.execute(() -> runner.startAnimation(transition, info, t, finishAdapter)); - } - - @Override - public void mergeAnimation(IBinder transition, TransitionInfo info, - SurfaceControl.Transaction t, IBinder mergeTarget, - IRemoteTransitionFinishedCallback finishedCallback) { - final Runnable finishAdapter = () -> { - try { - finishedCallback.onTransitionFinished(null /* wct */, null /* sct */); - } catch (RemoteException e) { - Log.e(TAG, "Failed to call transition finished callback", e); - } - }; - executor.execute(() -> runner.mergeAnimation(transition, info, t, mergeTarget, - finishAdapter)); - } - }; - mTransition = new RemoteTransition(remote, appThread); - } - /** Constructor specifically for recents animation */ - public RemoteTransitionCompat(RecentsAnimationListener recents, + public static RemoteTransition newRemoteTransition(RecentsAnimationListener recents, RecentsAnimationControllerCompat controller, IApplicationThread appThread) { IRemoteTransition remote = new IRemoteTransition.Stub() { final RecentsControllerWrap mRecentsSession = new RecentsControllerWrap(); @@ -193,25 +137,7 @@ public class RemoteTransitionCompat implements Parcelable { mRecentsSession.commitTasksAppearedIfNeeded(recents); } }; - mTransition = new RemoteTransition(remote, appThread); - } - - /** Adds a filter check that restricts this remote transition to home open transitions. */ - public void addHomeOpenCheck(ComponentName homeActivity) { - if (mFilter == null) { - mFilter = new TransitionFilter(); - } - // No need to handle the transition that also dismisses keyguard. - mFilter.mNotFlags = TRANSIT_FLAG_KEYGUARD_GOING_AWAY; - mFilter.mRequirements = - new TransitionFilter.Requirement[]{new TransitionFilter.Requirement(), - new TransitionFilter.Requirement()}; - mFilter.mRequirements[0].mActivityType = ACTIVITY_TYPE_HOME; - mFilter.mRequirements[0].mTopActivity = homeActivity; - mFilter.mRequirements[0].mModes = new int[]{TRANSIT_OPEN, TRANSIT_TO_FRONT}; - mFilter.mRequirements[0].mOrder = CONTAINER_ORDER_TOP; - mFilter.mRequirements[1].mActivityType = ACTIVITY_TYPE_STANDARD; - mFilter.mRequirements[1].mModes = new int[]{TRANSIT_CLOSE, TRANSIT_TO_BACK}; + return new RemoteTransition(remote, appThread); } /** @@ -505,161 +431,4 @@ public class RemoteTransitionCompat implements Parcelable { @Override public void animateNavigationBarToApp(long duration) { } } - - - - // Code below generated by codegen v1.0.23. - // - // DO NOT MODIFY! - // CHECKSTYLE:OFF Generated code - // - // To regenerate run: - // $ codegen $ANDROID_BUILD_TOP/frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java - // - // To exclude the generated code from IntelliJ auto-formatting enable (one-time): - // Settings > Editor > Code Style > Formatter Control - //@formatter:off - - - @DataClass.Generated.Member - /* package-private */ RemoteTransitionCompat( - @NonNull RemoteTransition transition, - @Nullable TransitionFilter filter) { - this.mTransition = transition; - com.android.internal.util.AnnotationValidations.validate( - NonNull.class, null, mTransition); - this.mFilter = filter; - - // onConstructed(); // You can define this method to get a callback - } - - @DataClass.Generated.Member - public @NonNull RemoteTransition getTransition() { - return mTransition; - } - - @DataClass.Generated.Member - public @Nullable TransitionFilter getFilter() { - return mFilter; - } - - @Override - @DataClass.Generated.Member - public void writeToParcel(@NonNull android.os.Parcel dest, int flags) { - // You can override field parcelling by defining methods like: - // void parcelFieldName(Parcel dest, int flags) { ... } - - byte flg = 0; - if (mFilter != null) flg |= 0x2; - dest.writeByte(flg); - dest.writeTypedObject(mTransition, flags); - if (mFilter != null) dest.writeTypedObject(mFilter, flags); - } - - @Override - @DataClass.Generated.Member - public int describeContents() { return 0; } - - /** @hide */ - @SuppressWarnings({"unchecked", "RedundantCast"}) - @DataClass.Generated.Member - protected RemoteTransitionCompat(@NonNull android.os.Parcel in) { - // You can override field unparcelling by defining methods like: - // static FieldType unparcelFieldName(Parcel in) { ... } - - byte flg = in.readByte(); - RemoteTransition transition = (RemoteTransition) in.readTypedObject(RemoteTransition.CREATOR); - TransitionFilter filter = (flg & 0x2) == 0 ? null : (TransitionFilter) in.readTypedObject(TransitionFilter.CREATOR); - - this.mTransition = transition; - com.android.internal.util.AnnotationValidations.validate( - NonNull.class, null, mTransition); - this.mFilter = filter; - - // onConstructed(); // You can define this method to get a callback - } - - @DataClass.Generated.Member - public static final @NonNull Parcelable.Creator<RemoteTransitionCompat> CREATOR - = new Parcelable.Creator<RemoteTransitionCompat>() { - @Override - public RemoteTransitionCompat[] newArray(int size) { - return new RemoteTransitionCompat[size]; - } - - @Override - public RemoteTransitionCompat createFromParcel(@NonNull android.os.Parcel in) { - return new RemoteTransitionCompat(in); - } - }; - - /** - * A builder for {@link RemoteTransitionCompat} - */ - @SuppressWarnings("WeakerAccess") - @DataClass.Generated.Member - public static class Builder { - - private @NonNull RemoteTransition mTransition; - private @Nullable TransitionFilter mFilter; - - private long mBuilderFieldsSet = 0L; - - public Builder( - @NonNull RemoteTransition transition) { - mTransition = transition; - com.android.internal.util.AnnotationValidations.validate( - NonNull.class, null, mTransition); - } - - @DataClass.Generated.Member - public @NonNull Builder setTransition(@NonNull RemoteTransition value) { - checkNotUsed(); - mBuilderFieldsSet |= 0x1; - mTransition = value; - return this; - } - - @DataClass.Generated.Member - public @NonNull Builder setFilter(@NonNull TransitionFilter value) { - checkNotUsed(); - mBuilderFieldsSet |= 0x2; - mFilter = value; - return this; - } - - /** Builds the instance. This builder should not be touched after calling this! */ - public @NonNull RemoteTransitionCompat build() { - checkNotUsed(); - mBuilderFieldsSet |= 0x4; // Mark builder used - - if ((mBuilderFieldsSet & 0x2) == 0) { - mFilter = null; - } - RemoteTransitionCompat o = new RemoteTransitionCompat( - mTransition, - mFilter); - return o; - } - - private void checkNotUsed() { - if ((mBuilderFieldsSet & 0x4) != 0) { - throw new IllegalStateException( - "This Builder should not be reused. Use a new Builder instance instead"); - } - } - } - - @DataClass.Generated( - time = 1629321609807L, - codegenVersion = "1.0.23", - sourceFile = "frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java", - inputSignatures = "private static final java.lang.String TAG\nfinal @android.annotation.NonNull android.window.RemoteTransition mTransition\n @android.annotation.Nullable android.window.TransitionFilter mFilter\npublic void addHomeOpenCheck(android.content.ComponentName)\nclass RemoteTransitionCompat extends java.lang.Object implements [android.os.Parcelable]\nprivate com.android.systemui.shared.system.RecentsAnimationControllerCompat mWrapped\nprivate android.window.IRemoteTransitionFinishedCallback mFinishCB\nprivate android.window.WindowContainerToken mPausingTask\nprivate android.window.WindowContainerToken mPipTask\nprivate android.window.TransitionInfo mInfo\nprivate android.view.SurfaceControl mOpeningLeash\nprivate android.util.ArrayMap<android.view.SurfaceControl,android.view.SurfaceControl> mLeashMap\nprivate android.window.PictureInPictureSurfaceTransaction mPipTransaction\nprivate android.os.IBinder mTransition\n void setup(com.android.systemui.shared.system.RecentsAnimationControllerCompat,android.window.TransitionInfo,android.window.IRemoteTransitionFinishedCallback,android.window.WindowContainerToken,android.window.WindowContainerToken,android.util.ArrayMap<android.view.SurfaceControl,android.view.SurfaceControl>,android.os.IBinder)\n @android.annotation.SuppressLint boolean merge(android.window.TransitionInfo,android.view.SurfaceControl.Transaction,com.android.systemui.shared.system.RecentsAnimationListener)\npublic @java.lang.Override com.android.systemui.shared.recents.model.ThumbnailData screenshotTask(int)\npublic @java.lang.Override void setInputConsumerEnabled(boolean)\npublic @java.lang.Override void setAnimationTargetsBehindSystemBars(boolean)\npublic @java.lang.Override void hideCurrentInputMethod()\npublic @java.lang.Override void setFinishTaskTransaction(int,android.window.PictureInPictureSurfaceTransaction,android.view.SurfaceControl)\npublic @java.lang.Override @android.annotation.SuppressLint void finish(boolean,boolean)\npublic @java.lang.Override void setDeferCancelUntilNextTransition(boolean,boolean)\npublic @java.lang.Override void cleanupScreenshot()\npublic @java.lang.Override void setWillFinishToHome(boolean)\npublic @java.lang.Override boolean removeTask(int)\npublic @java.lang.Override void detachNavigationBarFromApp(boolean)\npublic @java.lang.Override void animateNavigationBarToApp(long)\nclass RecentsControllerWrap extends com.android.systemui.shared.system.RecentsAnimationControllerCompat implements []\n@com.android.internal.util.DataClass") - @Deprecated - private void __metadata() {} - - - //@formatter:on - // End of generated code - } diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionRunner.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionRunner.java deleted file mode 100644 index accc456c4209..000000000000 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionRunner.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.shared.system; - -import android.os.IBinder; -import android.view.SurfaceControl; -import android.window.TransitionInfo; - -/** Interface for something that runs a remote transition animation. */ -public interface RemoteTransitionRunner { - /** - * Starts a transition animation. Once complete, the implementation should call - * `finishCallback`. - */ - void startAnimation(IBinder transition, TransitionInfo info, SurfaceControl.Transaction t, - Runnable finishCallback); - - /** - * Attempts to merge a transition into the currently-running animation. If merge is not - * possible/supported, this should do nothing. Otherwise, the implementation should call - * `finishCallback` immediately to indicate that it merged the transition. - * - * @param transition The transition that wants to be merged into the running animation. - * @param mergeTarget The transition to merge into (that this runner is currently animating). - */ - default void mergeAnimation(IBinder transition, TransitionInfo info, - SurfaceControl.Transaction t, IBinder mergeTarget, Runnable finishCallback) { } -} diff --git a/packages/SystemUI/src-debug/com/android/systemui/flags/FlagsFactory.kt b/packages/SystemUI/src-debug/com/android/systemui/flags/FlagsFactory.kt new file mode 100644 index 000000000000..74519c21820b --- /dev/null +++ b/packages/SystemUI/src-debug/com/android/systemui/flags/FlagsFactory.kt @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.flags + +import android.annotation.BoolRes + +object FlagsFactory { + private val flagMap = mutableMapOf<String, Flag<*>>() + + val knownFlags: Map<String, Flag<*>> + get() = flagMap + + fun unreleasedFlag( + id: Int, + name: String, + namespace: String = "systemui", + teamfood: Boolean = false + ): UnreleasedFlag { + val flag = UnreleasedFlag(id = id, name = name, namespace = namespace, teamfood = teamfood) + FlagsFactory.checkForDupesAndAdd(flag) + return flag + } + + fun releasedFlag( + id: Int, + name: String, + namespace: String = "systemui", + teamfood: Boolean = false + ): ReleasedFlag { + val flag = ReleasedFlag(id = id, name = name, namespace = namespace, teamfood = teamfood) + FlagsFactory.checkForDupesAndAdd(flag) + return flag + } + + fun resourceBooleanFlag( + id: Int, + @BoolRes resourceId: Int, + name: String, + namespace: String = "systemui", + teamfood: Boolean = false + ): ResourceBooleanFlag { + val flag = + ResourceBooleanFlag( + id = id, + name = name, + namespace = namespace, + resourceId = resourceId, + teamfood = teamfood + ) + FlagsFactory.checkForDupesAndAdd(flag) + return flag + } + + fun sysPropBooleanFlag( + id: Int, + name: String, + namespace: String = "systemui", + default: Boolean = false + ): SysPropBooleanFlag { + val flag = + SysPropBooleanFlag(id = id, name = name, namespace = "systemui", default = default) + FlagsFactory.checkForDupesAndAdd(flag) + return flag + } + + private fun checkForDupesAndAdd(flag: Flag<*>) { + if (flagMap.containsKey(flag.name)) { + throw IllegalArgumentException("Name {flag.name} is already registered") + } + flagMap.forEach { + if (it.value.id == flag.id) { + throw IllegalArgumentException("Name {flag.id} is already registered") + } + } + flagMap[flag.name] = flag + } +} diff --git a/packages/SystemUI/src-release/com/android/systemui/flags/FlagsFactory.kt b/packages/SystemUI/src-release/com/android/systemui/flags/FlagsFactory.kt new file mode 100644 index 000000000000..89c0786af6e3 --- /dev/null +++ b/packages/SystemUI/src-release/com/android/systemui/flags/FlagsFactory.kt @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.flags + +import android.annotation.BoolRes + +object FlagsFactory { + private val flagMap = mutableMapOf<String, Flag<*>>() + + val knownFlags: Map<String, Flag<*>> + get() = flagMap + + fun unreleasedFlag( + id: Int, + name: String, + namespace: String = "systemui", + teamfood: Boolean = false + ): UnreleasedFlag { + // Unreleased flags are always false in this build. + val flag = UnreleasedFlag(id = id, name = "", namespace = "", teamfood = false) + return flag + } + + fun releasedFlag( + id: Int, + name: String, + namespace: String = "systemui", + teamfood: Boolean = false + ): ReleasedFlag { + val flag = ReleasedFlag(id = id, name = name, namespace = namespace, teamfood = teamfood) + flagMap[name] = flag + return flag + } + + fun resourceBooleanFlag( + id: Int, + @BoolRes resourceId: Int, + name: String, + namespace: String = "systemui", + teamfood: Boolean = false + ): ResourceBooleanFlag { + val flag = + ResourceBooleanFlag( + id = id, + name = name, + namespace = namespace, + resourceId = resourceId, + teamfood = teamfood + ) + flagMap[name] = flag + return flag + } + + fun sysPropBooleanFlag( + id: Int, + name: String, + namespace: String = "systemui", + default: Boolean = false + ): SysPropBooleanFlag { + val flag = + SysPropBooleanFlag(id = id, name = name, namespace = namespace, default = default) + flagMap[name] = flag + return flag + } +} diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java index fbb114c72add..7a49926f8ef1 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java @@ -58,7 +58,8 @@ import com.android.keyguard.dagger.KeyguardBouncerScope; import com.android.settingslib.utils.ThreadUtils; import com.android.systemui.Gefingerpoken; import com.android.systemui.R; -import com.android.systemui.biometrics.SidefpsController; +import com.android.systemui.biometrics.SideFpsController; +import com.android.systemui.biometrics.SideFpsUiRequestSource; import com.android.systemui.classifier.FalsingA11yDelegate; import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.flags.FeatureFlags; @@ -100,7 +101,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard private final GlobalSettings mGlobalSettings; private final FeatureFlags mFeatureFlags; private final SessionTracker mSessionTracker; - private final Optional<SidefpsController> mSidefpsController; + private final Optional<SideFpsController> mSideFpsController; private final FalsingA11yDelegate mFalsingA11yDelegate; private int mLastOrientation = Configuration.ORIENTATION_UNDEFINED; @@ -290,7 +291,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard FeatureFlags featureFlags, GlobalSettings globalSettings, SessionTracker sessionTracker, - Optional<SidefpsController> sidefpsController, + Optional<SideFpsController> sideFpsController, FalsingA11yDelegate falsingA11yDelegate) { super(view); mLockPatternUtils = lockPatternUtils; @@ -311,7 +312,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard mFeatureFlags = featureFlags; mGlobalSettings = globalSettings; mSessionTracker = sessionTracker; - mSidefpsController = sidefpsController; + mSideFpsController = sideFpsController; mFalsingA11yDelegate = falsingA11yDelegate; } @@ -351,7 +352,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard } private void updateSideFpsVisibility() { - if (!mSidefpsController.isPresent()) { + if (!mSideFpsController.isPresent()) { return; } final boolean sfpsEnabled = getResources().getBoolean( @@ -369,9 +370,9 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard + "needsStrongAuth=" + needsStrongAuth); } if (toShow) { - mSidefpsController.get().show(); + mSideFpsController.get().show(SideFpsUiRequestSource.PRIMARY_BOUNCER); } else { - mSidefpsController.get().hide(); + mSideFpsController.get().hide(SideFpsUiRequestSource.PRIMARY_BOUNCER); } } @@ -745,7 +746,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard private final FeatureFlags mFeatureFlags; private final UserSwitcherController mUserSwitcherController; private final SessionTracker mSessionTracker; - private final Optional<SidefpsController> mSidefpsController; + private final Optional<SideFpsController> mSidefpsController; private final FalsingA11yDelegate mFalsingA11yDelegate; @Inject @@ -766,7 +767,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard FeatureFlags featureFlags, GlobalSettings globalSettings, SessionTracker sessionTracker, - Optional<SidefpsController> sidefpsController, + Optional<SideFpsController> sidefpsController, FalsingA11yDelegate falsingA11yDelegate) { mView = view; mAdminSecondaryLockScreenControllerFactory = adminSecondaryLockScreenControllerFactory; diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index 558869c46373..47ea8784aae8 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -314,8 +314,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab private boolean mCredentialAttempted; private boolean mKeyguardGoingAway; private boolean mGoingToSleep; - private boolean mBouncerFullyShown; - private boolean mBouncerIsOrWillBeShowing; + private boolean mPrimaryBouncerFullyShown; + private boolean mPrimaryBouncerIsOrWillBeShowing; private boolean mUdfpsBouncerShowing; private boolean mAuthInterruptActive; private boolean mNeedsSlowUnlockTransition; @@ -798,7 +798,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab mFingerprintCancelSignal = null; updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE, FACE_AUTH_UPDATED_FP_AUTHENTICATED); - mLogger.d("onFingerprintAuthenticated"); + mLogger.logFingerprintSuccess(userId, isStrongBiometric); for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); if (cb != null) { @@ -1664,8 +1664,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab public void onAuthenticationFailed() { String reason = mKeyguardBypassController.canBypass() ? "bypass" - : mUdfpsBouncerShowing ? "udfpsBouncer" : - mBouncerFullyShown ? "bouncer" : "udfpsFpDown"; + : mUdfpsBouncerShowing ? "udfpsBouncer" + : mPrimaryBouncerFullyShown ? "bouncer" + : "udfpsFpDown"; requestActiveUnlock( ActiveUnlockConfig.ACTIVE_UNLOCK_REQUEST_ORIGIN.BIOMETRIC_FAIL, "faceFailure-" + reason); @@ -2057,7 +2058,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab handleKeyguardReset(); break; case MSG_KEYGUARD_BOUNCER_CHANGED: - handleKeyguardBouncerChanged(msg.arg1, msg.arg2); + handlePrimaryBouncerChanged(msg.arg1, msg.arg2); break; case MSG_REPORT_EMERGENCY_CALL_ACTION: handleReportEmergencyCallAction(); @@ -2526,7 +2527,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab requestOrigin, extraReason, canFaceBypass || mUdfpsBouncerShowing - || mBouncerFullyShown + || mPrimaryBouncerFullyShown || mAuthController.isUdfpsFingerDown()); } @@ -2547,7 +2548,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab private boolean shouldTriggerActiveUnlock() { // Triggers: final boolean triggerActiveUnlockForAssistant = shouldTriggerActiveUnlockForAssistant(); - final boolean awakeKeyguard = mBouncerFullyShown || mUdfpsBouncerShowing + final boolean awakeKeyguard = mPrimaryBouncerFullyShown || mUdfpsBouncerShowing || (isKeyguardVisible() && !mGoingToSleep && mStatusBarState != StatusBarState.SHADE_LOCKED); @@ -2626,7 +2627,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab final boolean shouldListenKeyguardState = isKeyguardVisible() || !mDeviceInteractive - || (mBouncerIsOrWillBeShowing && !mKeyguardGoingAway) + || (mPrimaryBouncerIsOrWillBeShowing && !mKeyguardGoingAway) || mGoingToSleep || shouldListenForFingerprintAssistant || (mKeyguardOccluded && mIsDreaming) @@ -2645,8 +2646,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab && mIsPrimaryUser && biometricEnabledForUser; - final boolean shouldListenBouncerState = - !(mFingerprintLockedOut && mBouncerIsOrWillBeShowing && mCredentialAttempted); + final boolean shouldListenBouncerState = !(mFingerprintLockedOut + && mPrimaryBouncerIsOrWillBeShowing && mCredentialAttempted); final boolean isEncryptedOrLockdownForUser = isEncryptedOrLockdown(user); @@ -2671,7 +2672,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab user, shouldListen, biometricEnabledForUser, - mBouncerIsOrWillBeShowing, + mPrimaryBouncerIsOrWillBeShowing, userCanSkipBouncer, mCredentialAttempted, mDeviceInteractive, @@ -2716,7 +2717,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab || containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_TIMEOUT); // TODO: always disallow when fp is already locked out? - final boolean fpLockedout = mFingerprintLockedOut || mFingerprintLockedOutPermanent; + final boolean fpLockedOut = mFingerprintLockedOut || mFingerprintLockedOutPermanent; final boolean canBypass = mKeyguardBypassController != null && mKeyguardBypassController.canBypass(); @@ -2728,7 +2729,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab // Scan even when encrypted or timeout to show a preemptive bouncer when bypassing. // Lock-down mode shouldn't scan, since it is more explicit. boolean strongAuthAllowsScanning = (!isEncryptedOrTimedOut || canBypass - && !mBouncerFullyShown); + && !mPrimaryBouncerFullyShown); // If the device supports face detection (without authentication) and bypass is enabled, // allow face scanning to happen if the device is in lockdown mode. @@ -2745,12 +2746,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab final boolean faceDisabledForUser = isFaceDisabled(user); final boolean biometricEnabledForUser = mBiometricEnabledForUser.get(user); final boolean shouldListenForFaceAssistant = shouldListenForFaceAssistant(); - final boolean fpOrFaceIsLockedOut = isFaceLockedOut() || fpLockedout; // 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 = - (mBouncerFullyShown + (mPrimaryBouncerFullyShown || mAuthInterruptActive || mOccludingAppRequestingFace || awakeKeyguard @@ -2763,7 +2763,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab && (!mSecureCameraLaunched || mOccludingAppRequestingFace) && !faceAuthenticated && !mGoingToSleep - && !fpOrFaceIsLockedOut; + // We only care about fp locked out state and not face because we still trigger + // face auth even when face is locked out to show the user a message that face + // unlock was supposed to run but didn't + && !fpLockedOut; // Aggregate relevant fields for debug logging. maybeLogListenerModelData( @@ -2774,11 +2777,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab mAuthInterruptActive, becauseCannotSkipBouncer, biometricEnabledForUser, - mBouncerFullyShown, + mPrimaryBouncerFullyShown, faceAuthenticated, faceDisabledForUser, isFaceLockedOut(), - fpLockedout, + fpLockedOut, mGoingToSleep, awakeKeyguard, mKeyguardGoingAway, @@ -3304,17 +3307,19 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab /** * Handle {@link #MSG_KEYGUARD_BOUNCER_CHANGED} * - * @see #sendKeyguardBouncerChanged(boolean, boolean) + * @see #sendPrimaryBouncerChanged(boolean, boolean) */ - private void handleKeyguardBouncerChanged(int bouncerIsOrWillBeShowing, int bouncerFullyShown) { + private void handlePrimaryBouncerChanged(int primaryBouncerIsOrWillBeShowing, + int primaryBouncerFullyShown) { Assert.isMainThread(); - final boolean wasBouncerIsOrWillBeShowing = mBouncerIsOrWillBeShowing; - final boolean wasBouncerFullyShown = mBouncerFullyShown; - mBouncerIsOrWillBeShowing = bouncerIsOrWillBeShowing == 1; - mBouncerFullyShown = bouncerFullyShown == 1; - mLogger.logKeyguardBouncerChanged(mBouncerIsOrWillBeShowing, mBouncerFullyShown); - - if (mBouncerFullyShown) { + final boolean wasPrimaryBouncerIsOrWillBeShowing = mPrimaryBouncerIsOrWillBeShowing; + final boolean wasPrimaryBouncerFullyShown = mPrimaryBouncerFullyShown; + mPrimaryBouncerIsOrWillBeShowing = primaryBouncerIsOrWillBeShowing == 1; + mPrimaryBouncerFullyShown = primaryBouncerFullyShown == 1; + mLogger.logPrimaryKeyguardBouncerChanged(mPrimaryBouncerIsOrWillBeShowing, + mPrimaryBouncerFullyShown); + + if (mPrimaryBouncerFullyShown) { // If the bouncer is shown, always clear this flag. This can happen in the following // situations: 1) Default camera with SHOW_WHEN_LOCKED is not chosen yet. 2) Secure // camera requests dismiss keyguard (tapping on photos for example). When these happen, @@ -3324,18 +3329,18 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab mCredentialAttempted = false; } - if (wasBouncerIsOrWillBeShowing != mBouncerIsOrWillBeShowing) { + if (wasPrimaryBouncerIsOrWillBeShowing != mPrimaryBouncerIsOrWillBeShowing) { for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); if (cb != null) { - cb.onKeyguardBouncerStateChanged(mBouncerIsOrWillBeShowing); + cb.onKeyguardBouncerStateChanged(mPrimaryBouncerIsOrWillBeShowing); } } updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE); } - if (wasBouncerFullyShown != mBouncerFullyShown) { - if (mBouncerFullyShown) { + if (wasPrimaryBouncerFullyShown != mPrimaryBouncerFullyShown) { + if (mPrimaryBouncerFullyShown) { requestActiveUnlock( ActiveUnlockConfig.ACTIVE_UNLOCK_REQUEST_ORIGIN.UNLOCK_INTENT, "bouncerFullyShown"); @@ -3343,7 +3348,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); if (cb != null) { - cb.onKeyguardBouncerFullyShowingChanged(mBouncerFullyShown); + cb.onKeyguardBouncerFullyShowingChanged(mPrimaryBouncerFullyShown); } } updateFaceListeningState(BIOMETRIC_ACTION_UPDATE, @@ -3494,14 +3499,15 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } /** - * @see #handleKeyguardBouncerChanged(int, int) + * @see #handlePrimaryBouncerChanged(int, int) */ - public void sendKeyguardBouncerChanged(boolean bouncerIsOrWillBeShowing, - boolean bouncerFullyShown) { - mLogger.logSendKeyguardBouncerChanged(bouncerIsOrWillBeShowing, bouncerFullyShown); + public void sendPrimaryBouncerChanged(boolean primaryBouncerIsOrWillBeShowing, + boolean primaryBouncerFullyShown) { + mLogger.logSendPrimaryBouncerChanged(primaryBouncerIsOrWillBeShowing, + primaryBouncerFullyShown); Message message = mHandler.obtainMessage(MSG_KEYGUARD_BOUNCER_CHANGED); - message.arg1 = bouncerIsOrWillBeShowing ? 1 : 0; - message.arg2 = bouncerFullyShown ? 1 : 0; + message.arg1 = primaryBouncerIsOrWillBeShowing ? 1 : 0; + message.arg2 = primaryBouncerFullyShown ? 1 : 0; message.sendToTarget(); } @@ -3861,7 +3867,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab if (isUdfpsSupported()) { pw.println(" udfpsEnrolled=" + isUdfpsEnrolled()); pw.println(" shouldListenForUdfps=" + shouldListenForFingerprint(true)); - pw.println(" mBouncerIsOrWillBeShowing=" + mBouncerIsOrWillBeShowing); + pw.println(" mPrimaryBouncerIsOrWillBeShowing=" + + mPrimaryBouncerIsOrWillBeShowing); pw.println(" mStatusBarState=" + StatusBarState.toString(mStatusBarState)); pw.println(" mUdfpsBouncerShowing=" + mUdfpsBouncerShowing); } else if (isSfpsSupported()) { @@ -3891,7 +3898,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab pw.println(" mFaceLockedOutPermanent=" + mFaceLockedOutPermanent); pw.println(" enabledByUser=" + mBiometricEnabledForUser.get(userId)); pw.println(" mSecureCameraLaunched=" + mSecureCameraLaunched); - pw.println(" mBouncerFullyShown=" + mBouncerFullyShown); + pw.println(" mPrimaryBouncerFullyShown=" + mPrimaryBouncerFullyShown); pw.println(" mNeedsSlowUnlockTransition=" + mNeedsSlowUnlockTransition); } mListenModels.print(pw); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java index 90f0446ee34d..6c3c246e7fb9 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java @@ -50,16 +50,11 @@ public interface KeyguardViewController { /** * Resets the state of Keyguard View. - * @param hideBouncerWhenShowing + * @param hideBouncerWhenShowing when true, hides the primary and alternate bouncers if showing. */ void reset(boolean hideBouncerWhenShowing); /** - * Stop showing any alternate auth methods. - */ - void resetAlternateAuth(boolean forceUpdateScrim); - - /** * Called when the device started going to sleep. */ default void onStartedGoingToSleep() {}; @@ -156,20 +151,24 @@ public interface KeyguardViewController { void notifyKeyguardAuthenticated(boolean strongAuth); /** - * Shows the Bouncer. - * + * Shows the primary bouncer. + */ + void showPrimaryBouncer(boolean scrimmed); + + /** + * When the primary bouncer is fully visible or is showing but animation didn't finish yet. */ - void showBouncer(boolean scrimmed); + boolean primaryBouncerIsOrWillBeShowing(); /** - * Returns {@code true} when the bouncer is currently showing + * Returns {@code true} when the primary bouncer or alternate bouncer is currently showing */ boolean isBouncerShowing(); /** - * When bouncer is fully visible or it is showing but animation didn't finish yet. + * Stop showing the alternate bouncer, if showing. */ - boolean bouncerIsOrWillBeShowing(); + void hideAlternateBouncer(boolean forceUpdateScrim); // TODO: Deprecate registerStatusBar in KeyguardViewController interface. It is currently // only used for testing purposes in StatusBarKeyguardViewManager, and it prevents us from diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconView.java b/packages/SystemUI/src/com/android/keyguard/LockIconView.java index 0a82968ae4cb..34a5ef75f176 100644 --- a/packages/SystemUI/src/com/android/keyguard/LockIconView.java +++ b/packages/SystemUI/src/com/android/keyguard/LockIconView.java @@ -158,6 +158,10 @@ public class LockIconView extends FrameLayout implements Dumpable { return mLockIconCenter.y - mRadius; } + float getLocationBottom() { + return mLockIconCenter.y + mRadius; + } + /** * Updates the icon its default state where no visual is shown. */ diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java index fe7c70ae4c7e..dd6a1bd457b8 100644 --- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java @@ -280,6 +280,10 @@ public class LockIconViewController extends ViewController<LockIconView> impleme return mView.getLocationTop(); } + public float getBottom() { + return mView.getLocationBottom(); + } + private void updateVisibility() { if (mCancelDelayedUpdateVisibilityRunnable != null) { mCancelDelayedUpdateVisibilityRunnable.run(); @@ -695,7 +699,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme "lock-screen-lock-icon-longpress", TOUCH_VIBRATION_ATTRIBUTES); - mKeyguardViewController.showBouncer(/* scrim */ true); + mKeyguardViewController.showPrimaryBouncer(/* scrim */ true); } diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java index 49e97836b18b..ef067b89f9c7 100644 --- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java +++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java @@ -16,7 +16,7 @@ package com.android.keyguard.dagger; -import static com.android.systemui.biometrics.SidefpsControllerKt.hasSideFpsSensor; +import static com.android.systemui.biometrics.SideFpsControllerKt.hasSideFpsSensor; import android.annotation.Nullable; import android.hardware.fingerprint.FingerprintManager; @@ -27,7 +27,7 @@ import com.android.keyguard.KeyguardHostView; import com.android.keyguard.KeyguardSecurityContainer; import com.android.keyguard.KeyguardSecurityViewFlipper; import com.android.systemui.R; -import com.android.systemui.biometrics.SidefpsController; +import com.android.systemui.biometrics.SideFpsController; import com.android.systemui.dagger.qualifiers.RootView; import com.android.systemui.statusbar.phone.KeyguardBouncer; @@ -70,12 +70,12 @@ public interface KeyguardBouncerModule { return containerView.findViewById(R.id.view_flipper); } - /** Provides {@link SidefpsController} if the device has the side fingerprint sensor. */ + /** Provides {@link SideFpsController} if the device has the side fingerprint sensor. */ @Provides @KeyguardBouncerScope - static Optional<SidefpsController> providesOptionalSidefpsController( + static Optional<SideFpsController> providesOptionalSidefpsController( @Nullable FingerprintManager fingerprintManager, - Provider<SidefpsController> sidefpsControllerProvider) { + Provider<SideFpsController> sidefpsControllerProvider) { if (!hasSideFpsSensor(fingerprintManager)) { return Optional.empty(); } diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt index 3308f5550bfc..81b8dfed36a8 100644 --- a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt +++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt @@ -153,19 +153,29 @@ class KeyguardUpdateMonitorLogger @Inject constructor( { "fingerprintRunningState: $int1" }) } + fun logFingerprintSuccess(userId: Int, isStrongBiometric: Boolean) { + logBuffer.log(TAG, DEBUG, { + int1 = userId + bool1 = isStrongBiometric + }, {"Fingerprint auth successful: userId: $int1, isStrongBiometric: $bool1"}) + } + fun logInvalidSubId(subId: Int) { logBuffer.log(TAG, INFO, { int1 = subId }, { "Previously active sub id $int1 is now invalid, will remove" }) } - fun logKeyguardBouncerChanged(bouncerIsOrWillBeShowing: Boolean, bouncerFullyShown: Boolean) { + fun logPrimaryKeyguardBouncerChanged( + primaryBouncerIsOrWillBeShowing: Boolean, + primaryBouncerFullyShown: Boolean + ) { logBuffer.log(TAG, DEBUG, { - bool1 = bouncerIsOrWillBeShowing - bool2 = bouncerFullyShown + bool1 = primaryBouncerIsOrWillBeShowing + bool2 = primaryBouncerFullyShown }, { - "handleKeyguardBouncerChanged " + - "bouncerIsOrWillBeShowing=$bool1 bouncerFullyShowing=$bool2" + "handlePrimaryBouncerChanged " + + "primaryBouncerIsOrWillBeShowing=$bool1 primaryBouncerFullyShown=$bool2" }) } @@ -222,16 +232,16 @@ class KeyguardUpdateMonitorLogger @Inject constructor( { "Retrying fingerprint attempt: $int1" }) } - fun logSendKeyguardBouncerChanged( - bouncerIsOrWillBeShowing: Boolean, - bouncerFullyShown: Boolean, + fun logSendPrimaryBouncerChanged( + primaryBouncerIsOrWillBeShowing: Boolean, + primaryBouncerFullyShown: Boolean, ) { logBuffer.log(TAG, DEBUG, { - bool1 = bouncerIsOrWillBeShowing - bool2 = bouncerFullyShown + bool1 = primaryBouncerIsOrWillBeShowing + bool2 = primaryBouncerFullyShown }, { - "sendKeyguardBouncerChanged bouncerIsOrWillBeShowing=$bool1 " + - "bouncerFullyShown=$bool2" + "sendPrimaryBouncerChanged primaryBouncerIsOrWillBeShowing=$bool1 " + + "primaryBouncerFullyShown=$bool2" }) } diff --git a/packages/SystemUI/src/com/android/systemui/CameraAvailabilityListener.kt b/packages/SystemUI/src/com/android/systemui/CameraAvailabilityListener.kt index 3015710e8a98..eee705dea277 100644 --- a/packages/SystemUI/src/com/android/systemui/CameraAvailabilityListener.kt +++ b/packages/SystemUI/src/com/android/systemui/CameraAvailabilityListener.kt @@ -26,8 +26,6 @@ import java.util.concurrent.Executor import kotlin.math.roundToInt -const val TAG = "CameraAvailabilityListener" - /** * Listens for usage of the Camera and controls the ScreenDecorations transition to show extra * protection around a display cutout based on config_frontBuiltInDisplayCutoutProtection and diff --git a/packages/SystemUI/src/com/android/systemui/ChooserSelector.kt b/packages/SystemUI/src/com/android/systemui/ChooserSelector.kt index a89cbf57f95b..9ac45b3c77cc 100644 --- a/packages/SystemUI/src/com/android/systemui/ChooserSelector.kt +++ b/packages/SystemUI/src/com/android/systemui/ChooserSelector.kt @@ -4,30 +4,32 @@ import android.content.ComponentName import android.content.Context import android.content.pm.PackageManager import android.util.Log +import com.android.internal.R import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.FlagListenable import com.android.systemui.flags.Flags -import javax.inject.Inject +import com.android.systemui.settings.UserTracker import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.coroutines.withContext +import javax.inject.Inject @SysUISingleton class ChooserSelector @Inject constructor( private val context: Context, + private val userTracker: UserTracker, private val featureFlags: FeatureFlags, @Application private val coroutineScope: CoroutineScope, - @Background private val bgDispatcher: CoroutineDispatcher + @Background private val bgDispatcher: CoroutineDispatcher, ) : CoreStartable { - private val packageManager = context.packageManager private val chooserComponent = ComponentName.unflattenFromString( - context.resources.getString(ChooserSelectorResourceHelper.CONFIG_CHOOSER_ACTIVITY)) + context.resources.getString(R.string.config_chooserActivity)) override fun start() { coroutineScope.launch { @@ -56,10 +58,17 @@ class ChooserSelector @Inject constructor( } else { PackageManager.COMPONENT_ENABLED_STATE_DISABLED } - try { - packageManager.setComponentEnabledSetting(chooserComponent, newState, /* flags = */ 0) - } catch (e: IllegalArgumentException) { - Log.w("ChooserSelector", "Unable to set IntentResolver enabled=" + enabled, e) + userTracker.userProfiles.forEach { + try { + context.createContextAsUser(it.userHandle, /* flags = */ 0).packageManager + .setComponentEnabledSetting(chooserComponent, newState, /* flags = */ 0) + } catch (e: IllegalArgumentException) { + Log.w( + "ChooserSelector", + "Unable to set IntentResolver enabled=$enabled for user ${it.id}", + e, + ) + } } } diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java index b888d54956cf..83747b4f8636 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java @@ -278,7 +278,11 @@ public class SystemUIApplication extends Application implements } private static void notifyBootCompleted(CoreStartable coreStartable) { - Trace.beginSection(coreStartable.getClass().getSimpleName() + ".onBootCompleted()"); + if (Trace.isEnabled()) { + Trace.traceBegin( + Trace.TRACE_TAG_APP, + coreStartable.getClass().getSimpleName() + ".onBootCompleted()"); + } coreStartable.onBootCompleted(); Trace.endSection(); } @@ -300,14 +304,18 @@ public class SystemUIApplication extends Application implements private static CoreStartable startAdditionalStartable(String clsName) { CoreStartable startable; if (DEBUG) Log.d(TAG, "loading: " + clsName); + if (Trace.isEnabled()) { + Trace.traceBegin( + Trace.TRACE_TAG_APP, clsName + ".newInstance()"); + } try { - Trace.beginSection(clsName + ".newInstance()"); startable = (CoreStartable) Class.forName(clsName).newInstance(); - Trace.endSection(); } catch (ClassNotFoundException | IllegalAccessException | InstantiationException ex) { throw new RuntimeException(ex); + } finally { + Trace.endSection(); } return startStartable(startable); @@ -315,7 +323,10 @@ public class SystemUIApplication extends Application implements private static CoreStartable startStartable(String clsName, Provider<CoreStartable> provider) { if (DEBUG) Log.d(TAG, "loading: " + clsName); - Trace.beginSection("Provider<" + clsName + ">.get()"); + if (Trace.isEnabled()) { + Trace.traceBegin( + Trace.TRACE_TAG_APP, "Provider<" + clsName + ">.get()"); + } CoreStartable startable = provider.get(); Trace.endSection(); return startStartable(startable); @@ -323,7 +334,10 @@ public class SystemUIApplication extends Application implements private static CoreStartable startStartable(CoreStartable startable) { if (DEBUG) Log.d(TAG, "running: " + startable); - Trace.beginSection(startable.getClass().getSimpleName() + ".start()"); + if (Trace.isEnabled()) { + Trace.traceBegin( + Trace.TRACE_TAG_APP, startable.getClass().getSimpleName() + ".start()"); + } startable.start(); Trace.endSection(); @@ -364,15 +378,22 @@ public class SystemUIApplication extends Application implements public void onConfigurationChanged(Configuration newConfig) { if (mServicesStarted) { ConfigurationController configController = mSysUIComponent.getConfigurationController(); - Trace.beginSection( - configController.getClass().getSimpleName() + ".onConfigurationChanged()"); + if (Trace.isEnabled()) { + Trace.traceBegin( + Trace.TRACE_TAG_APP, + configController.getClass().getSimpleName() + ".onConfigurationChanged()"); + } configController.onConfigurationChanged(newConfig); Trace.endSection(); int len = mServices.length; for (int i = 0; i < len; i++) { if (mServices[i] != null) { - Trace.beginSection( - mServices[i].getClass().getSimpleName() + ".onConfigurationChanged()"); + if (Trace.isEnabled()) { + Trace.traceBegin( + Trace.TRACE_TAG_APP, + mServices[i].getClass().getSimpleName() + + ".onConfigurationChanged()"); + } mServices[i].onConfigurationChanged(newConfig); Trace.endSection(); } diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIInitializer.java b/packages/SystemUI/src/com/android/systemui/SystemUIInitializer.java index a21f45f701b3..632fcdc16259 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIInitializer.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIInitializer.java @@ -97,7 +97,6 @@ public abstract class SystemUIInitializer { .setDisplayAreaHelper(mWMComponent.getDisplayAreaHelper()) .setRecentTasks(mWMComponent.getRecentTasks()) .setBackAnimation(mWMComponent.getBackAnimation()) - .setFloatingTasks(mWMComponent.getFloatingTasks()) .setDesktopMode(mWMComponent.getDesktopMode()); // Only initialize when not starting from tests since this currently initializes some @@ -118,7 +117,6 @@ public abstract class SystemUIInitializer { .setStartingSurface(Optional.ofNullable(null)) .setRecentTasks(Optional.ofNullable(null)) .setBackAnimation(Optional.ofNullable(null)) - .setFloatingTasks(Optional.ofNullable(null)) .setDesktopMode(Optional.ofNullable(null)); } mSysUIComponent = builder.build(); diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIInitializerImpl.kt b/packages/SystemUI/src/com/android/systemui/SystemUIInitializerImpl.kt index 8920c928da09..8aa3040c6015 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIInitializerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/SystemUIInitializerImpl.kt @@ -17,7 +17,7 @@ package com.android.systemui import android.content.Context -import com.android.systemui.dagger.DaggerGlobalRootComponent +import com.android.systemui.dagger.DaggerReferenceGlobalRootComponent import com.android.systemui.dagger.GlobalRootComponent /** @@ -25,6 +25,6 @@ import com.android.systemui.dagger.GlobalRootComponent */ class SystemUIInitializerImpl(context: Context) : SystemUIInitializer(context) { override fun getGlobalRootComponentBuilder(): GlobalRootComponent.Builder { - return DaggerGlobalRootComponent.builder() + return DaggerReferenceGlobalRootComponent.builder() } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt index b40b3560f9db..b2a2a679b383 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt @@ -18,6 +18,7 @@ package com.android.systemui.biometrics import android.annotation.RawRes import android.content.Context +import android.content.res.Configuration import android.hardware.fingerprint.FingerprintManager import android.view.DisplayInfo import android.view.Surface @@ -33,15 +34,19 @@ import com.android.systemui.biometrics.AuthBiometricView.STATE_ERROR import com.android.systemui.biometrics.AuthBiometricView.STATE_HELP import com.android.systemui.biometrics.AuthBiometricView.STATE_IDLE import com.android.systemui.biometrics.AuthBiometricView.STATE_PENDING_CONFIRMATION +import com.android.systemui.unfold.compat.ScreenSizeFoldProvider +import com.android.systemui.unfold.updates.FoldProvider /** Fingerprint only icon animator for BiometricPrompt. */ open class AuthBiometricFingerprintIconController( context: Context, iconView: LottieAnimationView, protected val iconViewOverlay: LottieAnimationView -) : AuthIconController(context, iconView) { +) : AuthIconController(context, iconView), FoldProvider.FoldCallback { + private var isDeviceFolded: Boolean = false private val isSideFps: Boolean + private val screenSizeFoldProvider: ScreenSizeFoldProvider = ScreenSizeFoldProvider(context) var iconLayoutParamSize: Pair<Int, Int> = Pair(1, 1) set(value) { if (field == value) { @@ -74,6 +79,8 @@ open class AuthBiometricFingerprintIconController( if (isSideFps && displayInfo.rotation == Surface.ROTATION_180) { iconView.rotation = 180f } + screenSizeFoldProvider.registerCallback(this, context.mainExecutor) + screenSizeFoldProvider.onConfigurationChange(context.resources.configuration) } private fun updateIconSideFps(@BiometricState lastState: Int, @BiometricState newState: Int) { @@ -124,6 +131,10 @@ open class AuthBiometricFingerprintIconController( LottieColorUtils.applyDynamicColors(context, iconView) } + override fun onConfigurationChanged(newConfig: Configuration) { + screenSizeFoldProvider.onConfigurationChange(newConfig) + } + override fun updateIcon(@BiometricState lastState: Int, @BiometricState newState: Int) { if (isSideFps) { updateIconSideFps(lastState, newState) @@ -191,11 +202,21 @@ open class AuthBiometricFingerprintIconController( @RawRes private fun getSideFpsAnimationForTransition(rotation: Int): Int = when (rotation) { - Surface.ROTATION_0 -> R.raw.biometricprompt_landscape_base - Surface.ROTATION_90 -> R.raw.biometricprompt_portrait_base_topleft - Surface.ROTATION_180 -> R.raw.biometricprompt_landscape_base - Surface.ROTATION_270 -> R.raw.biometricprompt_portrait_base_bottomright - else -> R.raw.biometricprompt_landscape_base + Surface.ROTATION_90 -> if (isDeviceFolded) { + R.raw.biometricprompt_folded_base_topleft + } else { + R.raw.biometricprompt_portrait_base_topleft + } + Surface.ROTATION_270 -> if (isDeviceFolded) { + R.raw.biometricprompt_folded_base_bottomright + } else { + R.raw.biometricprompt_portrait_base_bottomright + } + else -> if (isDeviceFolded) { + R.raw.biometricprompt_folded_base_default + } else { + R.raw.biometricprompt_landscape_base + } } @RawRes @@ -273,4 +294,8 @@ open class AuthBiometricFingerprintIconController( } else -> null } + + override fun onFoldUpdated(isFolded: Boolean) { + isDeviceFolded = isFolded + } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricIconController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricIconController.kt index 15f487b05630..b3b6fa25c9b2 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricIconController.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricIconController.kt @@ -18,6 +18,7 @@ package com.android.systemui.biometrics import android.annotation.DrawableRes import android.content.Context +import android.content.res.Configuration import android.graphics.drawable.Animatable2 import android.graphics.drawable.AnimatedVectorDrawable import android.graphics.drawable.Drawable @@ -91,4 +92,6 @@ abstract class AuthIconController( /** Called during [onAnimationEnd] if the controller is not [deactivated]. */ open fun handleAnimationEnd(drawable: Drawable) {} + + open fun onConfigurationChanged(newConfig: Configuration) {} } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java index 0ac71c462e21..e12c1706798e 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java @@ -27,6 +27,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.StringRes; import android.content.Context; +import android.content.res.Configuration; import android.hardware.biometrics.BiometricAuthenticator.Modality; import android.hardware.biometrics.BiometricPrompt; import android.hardware.biometrics.PromptInfo; @@ -654,6 +655,12 @@ public abstract class AuthBiometricView extends LinearLayout { } @Override + protected void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + mIconController.onConfigurationChanged(newConfig); + } + + @Override protected void onFinishInflate() { super.onFinishInflate(); diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java index 0a2d8ec97ba6..94f71580901c 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java @@ -132,8 +132,7 @@ public class AuthContainerView extends LinearLayout private final OnBackInvokedCallback mBackCallback = this::onBackInvoked; private final @Background DelayableExecutor mBackgroundExecutor; - private int mOrientation; - private boolean mSkipFirstLostFocus = false; + private boolean mIsOrientationChanged = false; // Non-null only if the dialog is in the act of dismissing and has not sent the reason yet. @Nullable @AuthDialogCallback.DismissedReason private Integer mPendingCallbackReason; @@ -444,6 +443,7 @@ public class AuthContainerView extends LinearLayout @Override public void onOrientationChanged() { maybeUpdatePositionForUdfps(true /* invalidate */); + mIsOrientationChanged = true; } @Override @@ -452,8 +452,8 @@ public class AuthContainerView extends LinearLayout if (!hasWindowFocus) { //it's a workaround to avoid closing BP incorrectly //BP gets a onWindowFocusChanged(false) and then gets a onWindowFocusChanged(true) - if (mSkipFirstLostFocus) { - mSkipFirstLostFocus = false; + if (mIsOrientationChanged) { + mIsOrientationChanged = false; return; } Log.v(TAG, "Lost window focus, dismissing the dialog"); @@ -465,9 +465,6 @@ public class AuthContainerView extends LinearLayout public void onAttachedToWindow() { super.onAttachedToWindow(); - //save the first orientation - mOrientation = getResources().getConfiguration().orientation; - mWakefulnessLifecycle.addObserver(this); if (Utils.isBiometricAllowed(mConfig.mPromptInfo)) { @@ -623,7 +620,7 @@ public class AuthContainerView extends LinearLayout } if (savedState != null) { - mSkipFirstLostFocus = savedState.getBoolean( + mIsOrientationChanged = savedState.getBoolean( AuthDialog.KEY_BIOMETRIC_ORIENTATION_CHANGED); } @@ -717,9 +714,7 @@ public class AuthContainerView extends LinearLayout mBiometricView != null && mCredentialView == null); outState.putBoolean(AuthDialog.KEY_CREDENTIAL_SHOWING, mCredentialView != null); - if (mOrientation != getResources().getConfiguration().orientation) { - outState.putBoolean(AuthDialog.KEY_BIOMETRIC_ORIENTATION_CHANGED, true); - } + outState.putBoolean(AuthDialog.KEY_BIOMETRIC_ORIENTATION_CHANGED, mIsOrientationChanged); if (mBiometricView != null) { mBiometricView.onSaveState(outState); diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java index ff18eeea45a5..eb974dd909be 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java @@ -119,7 +119,7 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks, @Nullable private final FingerprintManager mFingerprintManager; @Nullable private final FaceManager mFaceManager; private final Provider<UdfpsController> mUdfpsControllerFactory; - private final Provider<SidefpsController> mSidefpsControllerFactory; + private final Provider<SideFpsController> mSidefpsControllerFactory; private final Display mDisplay; private float mScaleFactor = 1f; @@ -141,7 +141,7 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks, @NonNull private final DisplayManager mDisplayManager; @Nullable private UdfpsController mUdfpsController; @Nullable private IUdfpsHbmListener mUdfpsHbmListener; - @Nullable private SidefpsController mSidefpsController; + @Nullable private SideFpsController mSideFpsController; @Nullable private IBiometricContextListener mBiometricContextListener; @VisibleForTesting IBiometricSysuiReceiver mReceiver; @VisibleForTesting @NonNull final BiometricDisplayListener mOrientationListener; @@ -316,7 +316,7 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks, mSidefpsProps = !sidefpsProps.isEmpty() ? sidefpsProps : null; if (mSidefpsProps != null) { - mSidefpsController = mSidefpsControllerFactory.get(); + mSideFpsController = mSidefpsControllerFactory.get(); } updateSensorLocations(); @@ -677,7 +677,7 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks, @Nullable FingerprintManager fingerprintManager, @Nullable FaceManager faceManager, Provider<UdfpsController> udfpsControllerFactory, - Provider<SidefpsController> sidefpsControllerFactory, + Provider<SideFpsController> sidefpsControllerFactory, @NonNull DisplayManager displayManager, @NonNull WakefulnessLifecycle wakefulnessLifecycle, @NonNull UserManager userManager, @@ -777,13 +777,25 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks, private void updateUdfpsLocation() { if (mUdfpsController != null) { final FingerprintSensorPropertiesInternal udfpsProp = mUdfpsProps.get(0); + final Rect previousUdfpsBounds = mUdfpsBounds; mUdfpsBounds = udfpsProp.getLocation().getRect(); mUdfpsBounds.scale(mScaleFactor); - mUdfpsController.updateOverlayParams(udfpsProp.sensorId, - new UdfpsOverlayParams(mUdfpsBounds, mCachedDisplayInfo.getNaturalWidth(), - mCachedDisplayInfo.getNaturalHeight(), mScaleFactor, - mCachedDisplayInfo.rotation)); + + final Rect overlayBounds = new Rect( + 0, /* left */ + mCachedDisplayInfo.getNaturalHeight() / 2, /* top */ + mCachedDisplayInfo.getNaturalWidth(), /* right */ + mCachedDisplayInfo.getNaturalHeight() /* bottom */); + + final UdfpsOverlayParams overlayParams = new UdfpsOverlayParams( + mUdfpsBounds, + overlayBounds, + mCachedDisplayInfo.getNaturalWidth(), + mCachedDisplayInfo.getNaturalHeight(), + mScaleFactor, mCachedDisplayInfo.rotation); + + mUdfpsController.updateOverlayParams(udfpsProp, overlayParams); if (!Objects.equals(previousUdfpsBounds, mUdfpsBounds)) { for (Callback cb : mCallbacks) { cb.onUdfpsLocationChanged(); @@ -1054,7 +1066,7 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks, * Whether the passed userId has enrolled SFPS. */ public boolean isSfpsEnrolled(int userId) { - if (mSidefpsController == null) { + if (mSideFpsController == null) { return false; } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt index d03106b4e6bc..1c3dd451a1d3 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt @@ -51,20 +51,25 @@ import com.airbnb.lottie.LottieAnimationView import com.airbnb.lottie.LottieProperty import com.airbnb.lottie.model.KeyPath import com.android.internal.annotations.VisibleForTesting +import com.android.systemui.Dumpable import com.android.systemui.R import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.dump.DumpManager import com.android.systemui.recents.OverviewProxyService import com.android.systemui.util.concurrency.DelayableExecutor +import java.io.PrintWriter import javax.inject.Inject -private const val TAG = "SidefpsController" +private const val TAG = "SideFpsController" /** * Shows and hides the side fingerprint sensor (side-fps) overlay and handles side fps touch events. */ @SysUISingleton -class SidefpsController @Inject constructor( +class SideFpsController +@Inject +constructor( private val context: Context, private val layoutInflater: LayoutInflater, fingerprintManager: FingerprintManager?, @@ -73,29 +78,34 @@ class SidefpsController @Inject constructor( overviewProxyService: OverviewProxyService, displayManager: DisplayManager, @Main private val mainExecutor: DelayableExecutor, - @Main private val handler: Handler -) { + @Main private val handler: Handler, + dumpManager: DumpManager +) : Dumpable { + val requests: HashSet<SideFpsUiRequestSource> = HashSet() + @VisibleForTesting - val sensorProps: FingerprintSensorPropertiesInternal = fingerprintManager - ?.sideFpsSensorProperties - ?: throw IllegalStateException("no side fingerprint sensor") + val sensorProps: FingerprintSensorPropertiesInternal = + fingerprintManager?.sideFpsSensorProperties + ?: throw IllegalStateException("no side fingerprint sensor") @VisibleForTesting - val orientationListener = BiometricDisplayListener( - context, - displayManager, - handler, - BiometricDisplayListener.SensorType.SideFingerprint(sensorProps) - ) { onOrientationChanged() } + val orientationListener = + BiometricDisplayListener( + context, + displayManager, + handler, + BiometricDisplayListener.SensorType.SideFingerprint(sensorProps) + ) { onOrientationChanged() } @VisibleForTesting - val overviewProxyListener = object : OverviewProxyService.OverviewProxyListener { - override fun onTaskbarStatusUpdated(visible: Boolean, stashed: Boolean) { - overlayView?.let { view -> - handler.postDelayed({ updateOverlayVisibility(view) }, 500) + val overviewProxyListener = + object : OverviewProxyService.OverviewProxyListener { + override fun onTaskbarStatusUpdated(visible: Boolean, stashed: Boolean) { + overlayView?.let { view -> + handler.postDelayed({ updateOverlayVisibility(view) }, 500) + } } } - } private val animationDuration = context.resources.getInteger(android.R.integer.config_mediumAnimTime).toLong() @@ -121,19 +131,22 @@ class SidefpsController @Inject constructor( @VisibleForTesting internal var overlayOffsets: SensorLocationInternal = SensorLocationInternal.DEFAULT - private val overlayViewParams = WindowManager.LayoutParams( - WindowManager.LayoutParams.WRAP_CONTENT, - WindowManager.LayoutParams.WRAP_CONTENT, - WindowManager.LayoutParams.TYPE_SYSTEM_ERROR, - Utils.FINGERPRINT_OVERLAY_LAYOUT_PARAM_FLAGS, - PixelFormat.TRANSLUCENT - ).apply { - title = TAG - fitInsetsTypes = 0 // overrides default, avoiding status bars during layout - gravity = Gravity.TOP or Gravity.LEFT - layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS - privateFlags = PRIVATE_FLAG_TRUSTED_OVERLAY or PRIVATE_FLAG_NO_MOVE_ANIMATION - } + private val overlayViewParams = + WindowManager.LayoutParams( + WindowManager.LayoutParams.WRAP_CONTENT, + WindowManager.LayoutParams.WRAP_CONTENT, + WindowManager.LayoutParams.TYPE_SYSTEM_ERROR, + Utils.FINGERPRINT_OVERLAY_LAYOUT_PARAM_FLAGS, + PixelFormat.TRANSLUCENT + ) + .apply { + title = TAG + fitInsetsTypes = 0 // overrides default, avoiding status bars during layout + gravity = Gravity.TOP or Gravity.LEFT + layoutInDisplayCutoutMode = + WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS + privateFlags = PRIVATE_FLAG_TRUSTED_OVERLAY or PRIVATE_FLAG_NO_MOVE_ANIMATION + } init { fingerprintManager?.setSidefpsController( @@ -141,15 +154,23 @@ class SidefpsController @Inject constructor( override fun show( sensorId: Int, @BiometricOverlayConstants.ShowReason reason: Int - ) = if (reason.isReasonToShow(activityTaskManager)) show() else hide() + ) = + if (reason.isReasonToAutoShow(activityTaskManager)) { + show(SideFpsUiRequestSource.AUTO_SHOW) + } else { + hide(SideFpsUiRequestSource.AUTO_SHOW) + } - override fun hide(sensorId: Int) = hide() - }) + override fun hide(sensorId: Int) = hide(SideFpsUiRequestSource.AUTO_SHOW) + } + ) overviewProxyService.addCallback(overviewProxyListener) + dumpManager.registerDumpable(this) } /** Shows the side fps overlay if not already shown. */ - fun show() { + fun show(request: SideFpsUiRequestSource) { + requests.add(request) mainExecutor.execute { if (overlayView == null) { createOverlayForDisplay() @@ -160,8 +181,20 @@ class SidefpsController @Inject constructor( } /** Hides the fps overlay if shown. */ - fun hide() { - mainExecutor.execute { overlayView = null } + fun hide(request: SideFpsUiRequestSource) { + requests.remove(request) + mainExecutor.execute { + if (requests.isEmpty()) { + overlayView = null + } + } + } + + override fun dump(pw: PrintWriter, args: Array<out String>) { + pw.println("requests:") + for (requestSource in requests) { + pw.println(" $requestSource.name") + } } private fun onOrientationChanged() { @@ -174,12 +207,13 @@ class SidefpsController @Inject constructor( val view = layoutInflater.inflate(R.layout.sidefps_view, null, false) overlayView = view val display = context.display!! - val offsets = sensorProps.getLocation(display.uniqueId).let { location -> - if (location == null) { - Log.w(TAG, "No location specified for display: ${display.uniqueId}") + val offsets = + sensorProps.getLocation(display.uniqueId).let { location -> + if (location == null) { + Log.w(TAG, "No location specified for display: ${display.uniqueId}") + } + location ?: sensorProps.location } - location ?: sensorProps.location - } overlayOffsets = offsets val lottie = view.findViewById(R.id.sidefps_animation) as LottieAnimationView @@ -195,21 +229,25 @@ class SidefpsController @Inject constructor( /** * Intercepts TYPE_WINDOW_STATE_CHANGED accessibility event, preventing Talkback from - * speaking @string/accessibility_fingerprint_label twice when sensor location indicator - * is in focus + * speaking @string/accessibility_fingerprint_label twice when sensor location indicator is + * in focus */ - view.setAccessibilityDelegate(object : AccessibilityDelegate() { - override fun dispatchPopulateAccessibilityEvent( - host: View, - event: AccessibilityEvent - ): Boolean { - return if (event.getEventType() === AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) { - true - } else { - super.dispatchPopulateAccessibilityEvent(host, event) + view.setAccessibilityDelegate( + object : AccessibilityDelegate() { + override fun dispatchPopulateAccessibilityEvent( + host: View, + event: AccessibilityEvent + ): Boolean { + return if ( + event.getEventType() === AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED + ) { + true + } else { + super.dispatchPopulateAccessibilityEvent(host, event) + } } } - }) + ) } @VisibleForTesting @@ -220,21 +258,22 @@ class SidefpsController @Inject constructor( val displayHeight = if (isNaturalOrientation) size.height() else size.width() val boundsWidth = if (isNaturalOrientation) bounds.width() else bounds.height() val boundsHeight = if (isNaturalOrientation) bounds.height() else bounds.width() - val sensorBounds = if (overlayOffsets.isYAligned()) { - Rect( - displayWidth - boundsWidth, - overlayOffsets.sensorLocationY, - displayWidth, - overlayOffsets.sensorLocationY + boundsHeight - ) - } else { - Rect( - overlayOffsets.sensorLocationX, - 0, - overlayOffsets.sensorLocationX + boundsWidth, - boundsHeight - ) - } + val sensorBounds = + if (overlayOffsets.isYAligned()) { + Rect( + displayWidth - boundsWidth, + overlayOffsets.sensorLocationY, + displayWidth, + overlayOffsets.sensorLocationY + boundsHeight + ) + } else { + Rect( + overlayOffsets.sensorLocationX, + 0, + overlayOffsets.sensorLocationX + boundsWidth, + boundsHeight + ) + } RotationUtils.rotateBounds( sensorBounds, @@ -254,19 +293,25 @@ class SidefpsController @Inject constructor( // hide after a few seconds if the sensor is oriented down and there are // large overlapping system bars val rotation = context.display?.rotation - if (windowManager.currentWindowMetrics.windowInsets.hasBigNavigationBar() && - ((rotation == Surface.ROTATION_270 && overlayOffsets.isYAligned()) || - (rotation == Surface.ROTATION_180 && !overlayOffsets.isYAligned()))) { - overlayHideAnimator = view.animate() - .alpha(0f) - .setStartDelay(3_000) - .setDuration(animationDuration) - .setListener(object : AnimatorListenerAdapter() { - override fun onAnimationEnd(animation: Animator) { - view.visibility = View.GONE - overlayHideAnimator = null - } - }) + if ( + windowManager.currentWindowMetrics.windowInsets.hasBigNavigationBar() && + ((rotation == Surface.ROTATION_270 && overlayOffsets.isYAligned()) || + (rotation == Surface.ROTATION_180 && !overlayOffsets.isYAligned())) + ) { + overlayHideAnimator = + view + .animate() + .alpha(0f) + .setStartDelay(3_000) + .setDuration(animationDuration) + .setListener( + object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animation: Animator) { + view.visibility = View.GONE + overlayHideAnimator = null + } + } + ) } else { overlayHideAnimator?.cancel() overlayHideAnimator = null @@ -283,32 +328,36 @@ private val FingerprintManager?.sideFpsSensorProperties: FingerprintSensorProper fun FingerprintManager?.hasSideFpsSensor(): Boolean = this?.sideFpsSensorProperties != null @BiometricOverlayConstants.ShowReason -private fun Int.isReasonToShow(activityTaskManager: ActivityTaskManager): Boolean = when (this) { - REASON_AUTH_KEYGUARD -> false - REASON_AUTH_SETTINGS -> when (activityTaskManager.topClass()) { - // TODO(b/186176653): exclude fingerprint overlays from this list view - "com.android.settings.biometrics.fingerprint.FingerprintSettings" -> false +private fun Int.isReasonToAutoShow(activityTaskManager: ActivityTaskManager): Boolean = + when (this) { + REASON_AUTH_KEYGUARD -> false + REASON_AUTH_SETTINGS -> + when (activityTaskManager.topClass()) { + // TODO(b/186176653): exclude fingerprint overlays from this list view + "com.android.settings.biometrics.fingerprint.FingerprintSettings" -> false + else -> true + } else -> true } - else -> true -} private fun ActivityTaskManager.topClass(): String = getTasks(1).firstOrNull()?.topActivity?.className ?: "" @RawRes -private fun Display.asSideFpsAnimation(yAligned: Boolean): Int = when (rotation) { - Surface.ROTATION_0 -> if (yAligned) R.raw.sfps_pulse else R.raw.sfps_pulse_landscape - Surface.ROTATION_180 -> if (yAligned) R.raw.sfps_pulse else R.raw.sfps_pulse_landscape - else -> if (yAligned) R.raw.sfps_pulse_landscape else R.raw.sfps_pulse -} +private fun Display.asSideFpsAnimation(yAligned: Boolean): Int = + when (rotation) { + Surface.ROTATION_0 -> if (yAligned) R.raw.sfps_pulse else R.raw.sfps_pulse_landscape + Surface.ROTATION_180 -> if (yAligned) R.raw.sfps_pulse else R.raw.sfps_pulse_landscape + else -> if (yAligned) R.raw.sfps_pulse_landscape else R.raw.sfps_pulse + } -private fun Display.asSideFpsAnimationRotation(yAligned: Boolean): Float = when (rotation) { - Surface.ROTATION_90 -> if (yAligned) 0f else 180f - Surface.ROTATION_180 -> 180f - Surface.ROTATION_270 -> if (yAligned) 180f else 0f - else -> 0f -} +private fun Display.asSideFpsAnimationRotation(yAligned: Boolean): Float = + when (rotation) { + Surface.ROTATION_90 -> if (yAligned) 0f else 180f + Surface.ROTATION_180 -> 180f + Surface.ROTATION_270 -> if (yAligned) 180f else 0f + else -> 0f + } private fun SensorLocationInternal.isYAligned(): Boolean = sensorLocationY != 0 @@ -322,10 +371,9 @@ private fun LottieAnimationView.addOverlayDynamicColor(context: Context) { fun update() { val c = context.getColor(R.color.biometric_dialog_accent) for (key in listOf(".blue600", ".blue400")) { - addValueCallback( - KeyPath(key, "**"), - LottieProperty.COLOR_FILTER - ) { PorterDuffColorFilter(c, PorterDuff.Mode.SRC_ATOP) } + addValueCallback(KeyPath(key, "**"), LottieProperty.COLOR_FILTER) { + PorterDuffColorFilter(c, PorterDuff.Mode.SRC_ATOP) + } } } @@ -335,3 +383,15 @@ private fun LottieAnimationView.addOverlayDynamicColor(context: Context) { addLottieOnCompositionLoadedListener { update() } } } + +/** + * The source of a request to show the side fps visual indicator. This is distinct from + * [BiometricOverlayConstants] which corrresponds with the reason fingerprint authentication is + * requested. + */ +enum class SideFpsUiRequestSource { + /** see [isReasonToAutoShow] */ + AUTO_SHOW, + /** Pin, pattern or password bouncer */ + PRIMARY_BOUNCER, +} diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java index 65fcd760360c..bc10868e36c8 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java @@ -23,16 +23,17 @@ import static com.android.internal.util.Preconditions.checkNotNull; import static com.android.systemui.classifier.Classifier.LOCK_ICON; import static com.android.systemui.classifier.Classifier.UDFPS_AUTHENTICATION; -import android.annotation.NonNull; -import android.annotation.Nullable; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.graphics.Point; import android.hardware.biometrics.BiometricFingerprintConstants; +import android.hardware.biometrics.SensorProperties; import android.hardware.display.DisplayManager; import android.hardware.fingerprint.FingerprintManager; +import android.hardware.fingerprint.FingerprintSensorProperties; +import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.hardware.fingerprint.IUdfpsOverlayController; import android.hardware.fingerprint.IUdfpsOverlayControllerCallback; import android.os.Handler; @@ -50,10 +51,14 @@ import android.view.VelocityTracker; import android.view.WindowManager; import android.view.accessibility.AccessibilityManager; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.LatencyTracker; import com.android.keyguard.FaceAuthApiRequestReason; import com.android.keyguard.KeyguardUpdateMonitor; +import com.android.systemui.Dumpable; import com.android.systemui.animation.ActivityLaunchAnimator; import com.android.systemui.biometrics.dagger.BiometricsBackground; import com.android.systemui.dagger.SysUISingleton; @@ -62,7 +67,7 @@ import com.android.systemui.doze.DozeReceiver; import com.android.systemui.dump.DumpManager; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.keyguard.ScreenLifecycle; -import com.android.systemui.keyguard.domain.interactor.BouncerInteractor; +import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.shade.ShadeExpansionStateManager; @@ -77,6 +82,8 @@ import com.android.systemui.util.concurrency.DelayableExecutor; import com.android.systemui.util.concurrency.Execution; import com.android.systemui.util.time.SystemClock; +import java.io.PrintWriter; +import java.util.ArrayList; import java.util.HashSet; import java.util.Optional; import java.util.Set; @@ -99,7 +106,7 @@ import kotlin.Unit; */ @SuppressWarnings("deprecation") @SysUISingleton -public class UdfpsController implements DozeReceiver { +public class UdfpsController implements DozeReceiver, Dumpable { private static final String TAG = "UdfpsController"; private static final long AOD_INTERRUPT_TIMEOUT_MILLIS = 1000; @@ -133,11 +140,11 @@ public class UdfpsController implements DozeReceiver { @NonNull private final LatencyTracker mLatencyTracker; @VisibleForTesting @NonNull final BiometricDisplayListener mOrientationListener; @NonNull private final ActivityLaunchAnimator mActivityLaunchAnimator; - @NonNull private final BouncerInteractor mBouncerInteractor; + @NonNull private final PrimaryBouncerInteractor mPrimaryBouncerInteractor; // Currently the UdfpsController supports a single UDFPS sensor. If devices have multiple // sensors, this, in addition to a lot of the code here, will be updated. - @VisibleForTesting int mSensorId; + @VisibleForTesting @NonNull FingerprintSensorPropertiesInternal mSensorProps; @VisibleForTesting @NonNull UdfpsOverlayParams mOverlayParams = new UdfpsOverlayParams(); // TODO(b/229290039): UDFPS controller should manage its dimensions on its own. Remove this. @Nullable private Runnable mAuthControllerUpdateUdfpsLocation; @@ -202,6 +209,11 @@ public class UdfpsController implements DozeReceiver { } }; + @Override + public void dump(@NonNull PrintWriter pw, @NonNull String[] args) { + pw.println("mSensorProps=(" + mSensorProps + ")"); + } + public class UdfpsOverlayController extends IUdfpsOverlayController.Stub { @Override public void showUdfpsOverlay(long requestId, int sensorId, int reason, @@ -217,7 +229,7 @@ public class UdfpsController implements DozeReceiver { mUdfpsDisplayMode, requestId, reason, callback, (view, event, fromUdfpsView) -> onTouch(requestId, event, fromUdfpsView), mActivityLaunchAnimator, mFeatureFlags, - mBouncerInteractor))); + mPrimaryBouncerInteractor))); } @Override @@ -249,7 +261,7 @@ public class UdfpsController implements DozeReceiver { } mAcquiredReceived = true; final UdfpsView view = mOverlay.getOverlayView(); - if (view != null) { + if (view != null && isOptical()) { unconfigureDisplay(view); } if (acquiredGood) { @@ -295,26 +307,27 @@ public class UdfpsController implements DozeReceiver { /** * Updates the overlay parameters and reconstructs or redraws the overlay, if necessary. * - * @param sensorId sensor for which the overlay is getting updated. + * @param sensorProps sensor for which the overlay is getting updated. * @param overlayParams See {@link UdfpsOverlayParams}. */ - public void updateOverlayParams(int sensorId, @NonNull UdfpsOverlayParams overlayParams) { - if (sensorId != mSensorId) { - mSensorId = sensorId; + public void updateOverlayParams(@NonNull FingerprintSensorPropertiesInternal sensorProps, + @NonNull UdfpsOverlayParams overlayParams) { + if (mSensorProps.sensorId != sensorProps.sensorId) { + mSensorProps = sensorProps; Log.w(TAG, "updateUdfpsParams | sensorId has changed"); } if (!mOverlayParams.equals(overlayParams)) { mOverlayParams = overlayParams; - final boolean wasShowingAltAuth = mKeyguardViewManager.isShowingAlternateAuth(); + final boolean wasShowingAltAuth = mKeyguardViewManager.isShowingAlternateBouncer(); // When the bounds change it's always necessary to re-create the overlay's window with // new LayoutParams. If the overlay needs to be shown, this will re-create and show the // overlay with the updated LayoutParams. Otherwise, the overlay will remain hidden. redrawOverlay(); if (wasShowingAltAuth) { - mKeyguardViewManager.showGenericBouncer(true); + mKeyguardViewManager.showBouncer(true); } } } @@ -324,7 +337,7 @@ public class UdfpsController implements DozeReceiver { mAuthControllerUpdateUdfpsLocation = r; } - public void setUdfpsDisplayMode(UdfpsDisplayMode udfpsDisplayMode) { + public void setUdfpsDisplayMode(@Nullable UdfpsDisplayMode udfpsDisplayMode) { mUdfpsDisplayMode = udfpsDisplayMode; } @@ -428,7 +441,6 @@ public class UdfpsController implements DozeReceiver { } final UdfpsView udfpsView = mOverlay.getOverlayView(); - final boolean isDisplayConfigured = udfpsView.isDisplayConfigured(); boolean handled = false; switch (event.getActionMasked()) { case MotionEvent.ACTION_OUTSIDE: @@ -512,15 +524,14 @@ public class UdfpsController implements DozeReceiver { "minor: %.1f, major: %.1f, v: %.1f, exceedsVelocityThreshold: %b", minor, major, v, exceedsVelocityThreshold); final long sinceLastLog = mSystemClock.elapsedRealtime() - mTouchLogTime; - if (!isDisplayConfigured && !mAcquiredReceived - && !exceedsVelocityThreshold) { + if (!mOnFingerDown && !mAcquiredReceived && !exceedsVelocityThreshold) { final float scale = mOverlayParams.getScaleFactor(); float scaledMinor = minor / scale; float scaledMajor = major / scale; - onFingerDown(requestId, scaledTouch.x, scaledTouch.y, scaledMinor, scaledMajor); + Log.v(TAG, "onTouch | finger down: " + touchInfo); mTouchLogTime = mSystemClock.elapsedRealtime(); handled = true; @@ -614,8 +625,8 @@ public class UdfpsController implements DozeReceiver { @NonNull LatencyTracker latencyTracker, @NonNull ActivityLaunchAnimator activityLaunchAnimator, @NonNull Optional<AlternateUdfpsTouchProvider> alternateTouchProvider, - @BiometricsBackground Executor biometricsExecutor, - @NonNull BouncerInteractor bouncerInteractor) { + @NonNull @BiometricsBackground Executor biometricsExecutor, + @NonNull PrimaryBouncerInteractor primaryBouncerInteractor) { mContext = context; mExecution = execution; mVibrator = vibrator; @@ -632,6 +643,7 @@ public class UdfpsController implements DozeReceiver { mDumpManager = dumpManager; mDialogManager = dialogManager; mKeyguardUpdateMonitor = keyguardUpdateMonitor; + mFeatureFlags = featureFlags; mFalsingManager = falsingManager; mPowerManager = powerManager; mAccessibilityManager = accessibilityManager; @@ -644,9 +656,18 @@ public class UdfpsController implements DozeReceiver { mLatencyTracker = latencyTracker; mActivityLaunchAnimator = activityLaunchAnimator; mAlternateTouchProvider = alternateTouchProvider.orElse(null); + mSensorProps = new FingerprintSensorPropertiesInternal( + -1 /* sensorId */, + SensorProperties.STRENGTH_CONVENIENCE, + 0 /* maxEnrollmentsPerUser */, + new ArrayList<>() /* componentInfo */, + FingerprintSensorProperties.TYPE_UNKNOWN, + false /* resetLockoutRequiresHardwareAuthToken */); + mBiometricExecutor = biometricsExecutor; - mFeatureFlags = featureFlags; - mBouncerInteractor = bouncerInteractor; + mPrimaryBouncerInteractor = primaryBouncerInteractor; + + mDumpManager.registerDumpable(TAG, this); mOrientationListener = new BiometricDisplayListener( context, @@ -736,8 +757,8 @@ public class UdfpsController implements DozeReceiver { onFingerUp(mOverlay.getRequestId(), oldView); } final boolean removed = mOverlay.hide(); - if (mKeyguardViewManager.isShowingAlternateAuth()) { - mKeyguardViewManager.resetAlternateAuth(true); + if (mKeyguardViewManager.isShowingAlternateBouncer()) { + mKeyguardViewManager.hideAlternateBouncer(true); } Log.v(TAG, "hideUdfpsOverlay | removing window: " + removed); } else { @@ -777,7 +798,7 @@ public class UdfpsController implements DozeReceiver { Log.v(TAG, "aod lock icon long-press rejected by the falsing manager."); return; } - mKeyguardViewManager.showBouncer(true); + mKeyguardViewManager.showPrimaryBouncer(true); // play the same haptic as the LockIconViewController longpress mVibrator.vibrate( @@ -843,6 +864,10 @@ public class UdfpsController implements DozeReceiver { mIsAodInterruptActive = false; } + private boolean isOptical() { + return mSensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL; + } + public boolean isFingerDown() { return mOnFingerDown; } @@ -859,7 +884,9 @@ public class UdfpsController implements DozeReceiver { + " current: " + mOverlay.getRequestId()); return; } - mLatencyTracker.onActionStart(LatencyTracker.ACTION_UDFPS_ILLUMINATE); + if (isOptical()) { + mLatencyTracker.onActionStart(LatencyTracker.ACTION_UDFPS_ILLUMINATE); + } // Refresh screen timeout and boost process priority if possible. mPowerManager.userActivity(mSystemClock.uptimeMillis(), PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0); @@ -882,11 +909,11 @@ public class UdfpsController implements DozeReceiver { } }); } else { - mFingerprintManager.onPointerDown(requestId, mSensorId, x, y, minor, major); + mFingerprintManager.onPointerDown(requestId, mSensorProps.sensorId, x, y, minor, major); } Trace.endAsyncSection("UdfpsController.e2e.onPointerDown", 0); final UdfpsView view = mOverlay.getOverlayView(); - if (view != null) { + if (view != null && isOptical()) { view.configureDisplay(() -> { if (mAlternateTouchProvider != null) { mBiometricExecutor.execute(() -> { @@ -894,7 +921,7 @@ public class UdfpsController implements DozeReceiver { mLatencyTracker.onActionEnd(LatencyTracker.ACTION_UDFPS_ILLUMINATE); }); } else { - mFingerprintManager.onUiReady(requestId, mSensorId); + mFingerprintManager.onUiReady(requestId, mSensorProps.sensorId); mLatencyTracker.onActionEnd(LatencyTracker.ACTION_UDFPS_ILLUMINATE); } }); @@ -920,15 +947,16 @@ public class UdfpsController implements DozeReceiver { } }); } else { - mFingerprintManager.onPointerUp(requestId, mSensorId); + mFingerprintManager.onPointerUp(requestId, mSensorProps.sensorId); } for (Callback cb : mCallbacks) { cb.onFingerUp(); } } mOnFingerDown = false; - unconfigureDisplay(view); - + if (isOptical()) { + unconfigureDisplay(view); + } } /** diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt index d70861ac5f19..0bb24f8663ec 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt @@ -49,7 +49,7 @@ import com.android.systemui.R import com.android.systemui.animation.ActivityLaunchAnimator import com.android.systemui.dump.DumpManager import com.android.systemui.flags.FeatureFlags -import com.android.systemui.keyguard.domain.interactor.BouncerInteractor +import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.shade.ShadeExpansionStateManager import com.android.systemui.statusbar.LockscreenShadeTransitionController @@ -95,7 +95,7 @@ class UdfpsControllerOverlay @JvmOverloads constructor( private val onTouch: (View, MotionEvent, Boolean) -> Boolean, private val activityLaunchAnimator: ActivityLaunchAnimator, private val featureFlags: FeatureFlags, - private val bouncerInteractor: BouncerInteractor, + private val primaryBouncerInteractor: PrimaryBouncerInteractor, private val isDebuggable: Boolean = Build.IS_DEBUGGABLE ) { /** The view, when [isShowing], or null. */ @@ -252,7 +252,7 @@ class UdfpsControllerOverlay @JvmOverloads constructor( controller, activityLaunchAnimator, featureFlags, - bouncerInteractor + primaryBouncerInteractor ) } REASON_AUTH_BP -> { diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java index 1e359584ceec..3e1c4e543779 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java @@ -20,6 +20,7 @@ import android.animation.Animator; import android.animation.AnimatorSet; import android.animation.ValueAnimator; import android.content.Context; +import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.PointF; @@ -28,6 +29,7 @@ import android.graphics.RectF; import android.graphics.drawable.Drawable; import android.os.Handler; import android.os.Looper; +import android.util.AttributeSet; import android.view.animation.AccelerateDecelerateInterpolator; import androidx.annotation.NonNull; @@ -68,25 +70,29 @@ public class UdfpsEnrollDrawable extends UdfpsDrawable { private boolean mShouldShowTipHint = false; private boolean mShouldShowEdgeHint = false; - UdfpsEnrollDrawable(@NonNull Context context) { + private int mEnrollIcon; + private int mMovingTargetFill; + + UdfpsEnrollDrawable(@NonNull Context context, @Nullable AttributeSet attrs) { super(context); + loadResources(context, attrs); mSensorOutlinePaint = new Paint(0 /* flags */); mSensorOutlinePaint.setAntiAlias(true); - mSensorOutlinePaint.setColor(context.getColor(R.color.udfps_moving_target_fill)); + mSensorOutlinePaint.setColor(mMovingTargetFill); mSensorOutlinePaint.setStyle(Paint.Style.FILL); mBlueFill = new Paint(0 /* flags */); mBlueFill.setAntiAlias(true); - mBlueFill.setColor(context.getColor(R.color.udfps_moving_target_fill)); + mBlueFill.setColor(mMovingTargetFill); mBlueFill.setStyle(Paint.Style.FILL); mMovingTargetFpIcon = context.getResources() .getDrawable(R.drawable.ic_kg_fingerprint, null); - mMovingTargetFpIcon.setTint(context.getColor(R.color.udfps_enroll_icon)); + mMovingTargetFpIcon.setTint(mEnrollIcon); mMovingTargetFpIcon.mutate(); - getFingerprintDrawable().setTint(context.getColor(R.color.udfps_enroll_icon)); + getFingerprintDrawable().setTint(mEnrollIcon); mTargetAnimListener = new Animator.AnimatorListener() { @Override @@ -105,6 +111,16 @@ public class UdfpsEnrollDrawable extends UdfpsDrawable { }; } + void loadResources(Context context, @Nullable AttributeSet attrs) { + final TypedArray ta = context.obtainStyledAttributes(attrs, + R.styleable.BiometricsEnrollView, R.attr.biometricsEnrollStyle, + R.style.BiometricsEnrollStyle); + mEnrollIcon = ta.getColor(R.styleable.BiometricsEnrollView_biometricsEnrollIcon, 0); + mMovingTargetFill = ta.getColor( + R.styleable.BiometricsEnrollView_biometricsMovingTargetFill, 0); + ta.recycle(); + } + void setEnrollHelper(@NonNull UdfpsEnrollHelper helper) { mEnrollHelper = helper; } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java index 49e378e4a76f..97d202c5c738 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java @@ -18,6 +18,7 @@ package com.android.systemui.biometrics; import android.animation.ValueAnimator; import android.content.Context; +import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.ColorFilter; import android.graphics.Paint; @@ -26,6 +27,7 @@ import android.os.Process; import android.os.VibrationAttributes; import android.os.VibrationEffect; import android.os.Vibrator; +import android.util.AttributeSet; import android.view.accessibility.AccessibilityManager; import android.view.animation.DecelerateInterpolator; import android.view.animation.Interpolator; @@ -93,17 +95,25 @@ public class UdfpsEnrollProgressBarDrawable extends Drawable { @Nullable private ValueAnimator mCheckmarkAnimator; @NonNull private final ValueAnimator.AnimatorUpdateListener mCheckmarkUpdateListener; - public UdfpsEnrollProgressBarDrawable(@NonNull Context context) { + private int mMovingTargetFill; + private int mMovingTargetFillError; + private int mEnrollProgress; + private int mEnrollProgressHelp; + private int mEnrollProgressHelpWithTalkback; + + public UdfpsEnrollProgressBarDrawable(@NonNull Context context, @Nullable AttributeSet attrs) { mContext = context; + + loadResources(context, attrs); mStrokeWidthPx = Utils.dpToPixels(context, STROKE_WIDTH_DP); - mProgressColor = context.getColor(R.color.udfps_enroll_progress); + mProgressColor = mEnrollProgress; final AccessibilityManager am = context.getSystemService(AccessibilityManager.class); mIsAccessibilityEnabled = am.isTouchExplorationEnabled(); if (!mIsAccessibilityEnabled) { - mHelpColor = context.getColor(R.color.udfps_enroll_progress_help); - mOnFirstBucketFailedColor = context.getColor(R.color.udfps_moving_target_fill_error); + mHelpColor = mEnrollProgressHelp; + mOnFirstBucketFailedColor = mMovingTargetFillError; } else { - mHelpColor = context.getColor(R.color.udfps_enroll_progress_help_with_talkback); + mHelpColor = mEnrollProgressHelpWithTalkback; mOnFirstBucketFailedColor = mHelpColor; } mCheckmarkDrawable = context.getDrawable(R.drawable.udfps_enroll_checkmark); @@ -112,7 +122,7 @@ public class UdfpsEnrollProgressBarDrawable extends Drawable { mBackgroundPaint = new Paint(); mBackgroundPaint.setStrokeWidth(mStrokeWidthPx); - mBackgroundPaint.setColor(context.getColor(R.color.udfps_moving_target_fill)); + mBackgroundPaint.setColor(mMovingTargetFill); mBackgroundPaint.setAntiAlias(true); mBackgroundPaint.setStyle(Paint.Style.STROKE); mBackgroundPaint.setStrokeCap(Paint.Cap.ROUND); @@ -148,6 +158,23 @@ public class UdfpsEnrollProgressBarDrawable extends Drawable { }; } + void loadResources(Context context, @Nullable AttributeSet attrs) { + final TypedArray ta = context.obtainStyledAttributes(attrs, + R.styleable.BiometricsEnrollView, R.attr.biometricsEnrollStyle, + R.style.BiometricsEnrollStyle); + mMovingTargetFill = ta.getColor( + R.styleable.BiometricsEnrollView_biometricsMovingTargetFill, 0); + mMovingTargetFillError = ta.getColor( + R.styleable.BiometricsEnrollView_biometricsMovingTargetFillError, 0); + mEnrollProgress = ta.getColor( + R.styleable.BiometricsEnrollView_biometricsEnrollProgress, 0); + mEnrollProgressHelp = ta.getColor( + R.styleable.BiometricsEnrollView_biometricsEnrollProgressHelp, 0); + mEnrollProgressHelpWithTalkback = ta.getColor( + R.styleable.BiometricsEnrollView_biometricsEnrollProgressHelpWithTalkback, 0); + ta.recycle(); + } + void onEnrollmentProgress(int remaining, int totalSteps) { mAfterFirstTouch = true; updateState(remaining, totalSteps, false /* showingHelp */); diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java index 69c37b2b9a62..e5c485547382 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java @@ -43,8 +43,8 @@ public class UdfpsEnrollView extends UdfpsAnimationView { public UdfpsEnrollView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); - mFingerprintDrawable = new UdfpsEnrollDrawable(mContext); - mFingerprintProgressDrawable = new UdfpsEnrollProgressBarDrawable(context); + mFingerprintDrawable = new UdfpsEnrollDrawable(mContext, attrs); + mFingerprintProgressDrawable = new UdfpsEnrollProgressBarDrawable(context, attrs); mHandler = new Handler(Looper.getMainLooper()); } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt index 5bae2dc502d6..91967f95c861 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt @@ -31,7 +31,7 @@ import com.android.systemui.animation.Interpolators import com.android.systemui.dump.DumpManager import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags -import com.android.systemui.keyguard.domain.interactor.BouncerInteractor +import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.shade.ShadeExpansionListener @@ -40,9 +40,9 @@ import com.android.systemui.statusbar.LockscreenShadeTransitionController import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.notification.stack.StackStateAnimator import com.android.systemui.statusbar.phone.KeyguardBouncer -import com.android.systemui.statusbar.phone.KeyguardBouncer.BouncerExpansionCallback +import com.android.systemui.statusbar.phone.KeyguardBouncer.PrimaryBouncerExpansionCallback import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager -import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager.AlternateAuthInterceptor +import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager.AlternateBouncer import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager.KeyguardViewManagerCallback import com.android.systemui.statusbar.phone.SystemUIDialogManager import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController @@ -73,7 +73,7 @@ constructor( private val udfpsController: UdfpsController, private val activityLaunchAnimator: ActivityLaunchAnimator, featureFlags: FeatureFlags, - private val bouncerInteractor: BouncerInteractor + private val primaryBouncerInteractor: PrimaryBouncerInteractor ) : UdfpsAnimationViewController<UdfpsKeyguardView>( view, @@ -146,8 +146,8 @@ constructor( } } - private val bouncerExpansionCallback: BouncerExpansionCallback = - object : BouncerExpansionCallback { + private val mPrimaryBouncerExpansionCallback: PrimaryBouncerExpansionCallback = + object : PrimaryBouncerExpansionCallback { override fun onExpansionChanged(expansion: Float) { inputBouncerHiddenAmount = expansion updateAlpha() @@ -180,7 +180,7 @@ constructor( private val shadeExpansionListener = ShadeExpansionListener { (fraction) -> panelExpansionFraction = - if (keyguardViewManager.isBouncerInTransit) { + if (keyguardViewManager.isPrimaryBouncerInTransit) { aboutToShowBouncerProgress(fraction) } else { fraction @@ -237,17 +237,17 @@ constructor( } } - private val alternateAuthInterceptor: AlternateAuthInterceptor = - object : AlternateAuthInterceptor { - override fun showAlternateAuthBouncer(): Boolean { + private val mAlternateBouncer: AlternateBouncer = + object : AlternateBouncer { + override fun showAlternateBouncer(): Boolean { return showUdfpsBouncer(true) } - override fun hideAlternateAuthBouncer(): Boolean { + override fun hideAlternateBouncer(): Boolean { return showUdfpsBouncer(false) } - override fun isShowingAlternateAuthBouncer(): Boolean { + override fun isShowingAlternateBouncer(): Boolean { return showingUdfpsBouncer } @@ -268,7 +268,7 @@ constructor( override fun onInit() { super.onInit() - keyguardViewManager.setAlternateAuthInterceptor(alternateAuthInterceptor) + keyguardViewManager.setAlternateBouncer(mAlternateBouncer) } init { @@ -285,7 +285,7 @@ constructor( @VisibleForTesting internal suspend fun listenForBouncerExpansion(scope: CoroutineScope): Job { return scope.launch { - bouncerInteractor.bouncerExpansion.collect { bouncerExpansion: Float -> + primaryBouncerInteractor.bouncerExpansion.collect { bouncerExpansion: Float -> inputBouncerExpansion = bouncerExpansion updateAlpha() updatePauseAuth() @@ -306,10 +306,10 @@ constructor( qsExpansion = keyguardViewManager.qsExpansion keyguardViewManager.addCallback(statusBarKeyguardViewManagerCallback) if (!isModernBouncerEnabled) { - val bouncer = keyguardViewManager.bouncer + val bouncer = keyguardViewManager.primaryBouncer bouncer?.expansion?.let { - bouncerExpansionCallback.onExpansionChanged(it) - bouncer.addBouncerExpansionCallback(bouncerExpansionCallback) + mPrimaryBouncerExpansionCallback.onExpansionChanged(it) + bouncer.addBouncerExpansionCallback(mPrimaryBouncerExpansionCallback) } updateBouncerHiddenAmount() } @@ -319,7 +319,7 @@ constructor( view.updatePadding() updateAlpha() updatePauseAuth() - keyguardViewManager.setAlternateAuthInterceptor(alternateAuthInterceptor) + keyguardViewManager.setAlternateBouncer(mAlternateBouncer) lockScreenShadeTransitionController.udfpsKeyguardViewController = this activityLaunchAnimator.addListener(activityLaunchAnimatorListener) } @@ -329,7 +329,7 @@ constructor( faceDetectRunning = false keyguardStateController.removeCallback(keyguardStateControllerCallback) statusBarStateController.removeCallback(stateListener) - keyguardViewManager.removeAlternateAuthInterceptor(alternateAuthInterceptor) + keyguardViewManager.removeAlternateAuthInterceptor(mAlternateBouncer) keyguardUpdateMonitor.requestFaceAuthOnOccludingApp(false) configurationController.removeCallback(configurationListener) shadeExpansionStateManager.removeExpansionListener(shadeExpansionListener) @@ -339,7 +339,9 @@ constructor( activityLaunchAnimator.removeListener(activityLaunchAnimatorListener) keyguardViewManager.removeCallback(statusBarKeyguardViewManagerCallback) if (!isModernBouncerEnabled) { - keyguardViewManager.bouncer?.removeBouncerExpansionCallback(bouncerExpansionCallback) + keyguardViewManager.primaryBouncer?.removeBouncerExpansionCallback( + mPrimaryBouncerExpansionCallback + ) } } @@ -442,7 +444,7 @@ constructor( return if (isModernBouncerEnabled) { inputBouncerExpansion == 1f } else { - keyguardViewManager.isBouncerShowing && !keyguardViewManager.isShowingAlternateAuth + keyguardViewManager.isBouncerShowing && !keyguardViewManager.isShowingAlternateBouncer } } @@ -462,7 +464,7 @@ constructor( */ private fun maybeShowInputBouncer() { if (showingUdfpsBouncer && hasUdfpsBouncerShownWithMinTime()) { - keyguardViewManager.showBouncer(true) + keyguardViewManager.showPrimaryBouncer(true) } } @@ -535,8 +537,8 @@ constructor( if (isModernBouncerEnabled) { return } - val altBouncerShowing = keyguardViewManager.isShowingAlternateAuth - if (altBouncerShowing || !keyguardViewManager.bouncerIsOrWillBeShowing()) { + val altBouncerShowing = keyguardViewManager.isShowingAlternateBouncer + if (altBouncerShowing || !keyguardViewManager.primaryBouncerIsOrWillBeShowing()) { inputBouncerHiddenAmount = 1f } else if (keyguardViewManager.isBouncerShowing) { // input bouncer is fully showing diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsOverlayParams.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsOverlayParams.kt index d725dfbfe216..98d4c22d927d 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsOverlayParams.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsOverlayParams.kt @@ -20,6 +20,7 @@ import android.view.Surface.Rotation data class UdfpsOverlayParams( val sensorBounds: Rect = Rect(), + val overlayBounds: Rect = Rect(), val naturalDisplayWidth: Int = 0, val naturalDisplayHeight: Int = 0, val scaleFactor: Float = 1f, diff --git a/packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt b/packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt index 5850c9537ef0..08c7c0fd0b03 100644 --- a/packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt +++ b/packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt @@ -127,7 +127,10 @@ open class UserBroadcastDispatcher( action, userId, { - Trace.beginSection("registerReceiver act=$action user=$userId") + if (Trace.isEnabled()) { + Trace.traceBegin( + Trace.TRACE_TAG_APP, "registerReceiver act=$action user=$userId") + } context.registerReceiverAsUser( this, UserHandle.of(userId), @@ -141,7 +144,11 @@ open class UserBroadcastDispatcher( }, { try { - Trace.beginSection("unregisterReceiver act=$action user=$userId") + if (Trace.isEnabled()) { + Trace.traceBegin( + Trace.TRACE_TAG_APP, + "unregisterReceiver act=$action user=$userId") + } context.unregisterReceiver(this) Trace.endSection() logger.logContextReceiverUnregistered(userId, action) diff --git a/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java index 2245d8462c31..beaccbaf9a70 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java @@ -34,6 +34,8 @@ import com.android.internal.logging.MetricsLogger; import com.android.systemui.classifier.FalsingDataProvider.SessionListener; import com.android.systemui.classifier.HistoryTracker.BeliefListener; import com.android.systemui.dagger.qualifiers.TestHarness; +import com.android.systemui.flags.FeatureFlags; +import com.android.systemui.flags.Flags; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -65,6 +67,7 @@ public class BrightLineFalsingManager implements FalsingManager { private static final double FALSE_BELIEF_THRESHOLD = 0.9; private final FalsingDataProvider mDataProvider; + private final LongTapClassifier mLongTapClassifier; private final SingleTapClassifier mSingleTapClassifier; private final DoubleTapClassifier mDoubleTapClassifier; private final HistoryTracker mHistoryTracker; @@ -73,6 +76,7 @@ public class BrightLineFalsingManager implements FalsingManager { private final boolean mTestHarness; private final MetricsLogger mMetricsLogger; private int mIsFalseTouchCalls; + private FeatureFlags mFeatureFlags; private static final Queue<String> RECENT_INFO_LOG = new ArrayDeque<>(RECENT_INFO_LOG_SIZE + 1); private static final Queue<DebugSwipeRecord> RECENT_SWIPES = @@ -175,19 +179,23 @@ public class BrightLineFalsingManager implements FalsingManager { public BrightLineFalsingManager(FalsingDataProvider falsingDataProvider, MetricsLogger metricsLogger, @Named(BRIGHT_LINE_GESTURE_CLASSIFERS) Set<FalsingClassifier> classifiers, - SingleTapClassifier singleTapClassifier, DoubleTapClassifier doubleTapClassifier, - HistoryTracker historyTracker, KeyguardStateController keyguardStateController, + SingleTapClassifier singleTapClassifier, LongTapClassifier longTapClassifier, + DoubleTapClassifier doubleTapClassifier, HistoryTracker historyTracker, + KeyguardStateController keyguardStateController, AccessibilityManager accessibilityManager, - @TestHarness boolean testHarness) { + @TestHarness boolean testHarness, + FeatureFlags featureFlags) { mDataProvider = falsingDataProvider; mMetricsLogger = metricsLogger; mClassifiers = classifiers; mSingleTapClassifier = singleTapClassifier; + mLongTapClassifier = longTapClassifier; mDoubleTapClassifier = doubleTapClassifier; mHistoryTracker = historyTracker; mKeyguardStateController = keyguardStateController; mAccessibilityManager = accessibilityManager; mTestHarness = testHarness; + mFeatureFlags = featureFlags; mDataProvider.addSessionListener(mSessionListener); mDataProvider.addGestureCompleteListener(mGestureFinalizedListener); @@ -313,6 +321,58 @@ public class BrightLineFalsingManager implements FalsingManager { } @Override + public boolean isFalseLongTap(@Penalty int penalty) { + if (!mFeatureFlags.isEnabled(Flags.FALSING_FOR_LONG_TAPS)) { + return false; + } + + checkDestroyed(); + + if (skipFalsing(GENERIC)) { + mPriorResults = getPassedResult(1); + logDebug("Skipped falsing"); + return false; + } + + double falsePenalty = 0; + switch(penalty) { + case NO_PENALTY: + falsePenalty = 0; + break; + case LOW_PENALTY: + falsePenalty = 0.1; + break; + case MODERATE_PENALTY: + falsePenalty = 0.3; + break; + case HIGH_PENALTY: + falsePenalty = 0.6; + break; + } + + FalsingClassifier.Result longTapResult = + mLongTapClassifier.isTap(mDataProvider.getRecentMotionEvents().isEmpty() + ? mDataProvider.getPriorMotionEvents() + : mDataProvider.getRecentMotionEvents(), falsePenalty); + mPriorResults = Collections.singleton(longTapResult); + + if (!longTapResult.isFalse()) { + if (mDataProvider.isJustUnlockedWithFace()) { + // Immediately pass if a face is detected. + mPriorResults = getPassedResult(1); + logDebug("False Long Tap: false (face detected)"); + } else { + mPriorResults = getPassedResult(0.1); + logDebug("False Long Tap: false (default)"); + } + return false; + } else { + logDebug("False Long Tap: " + longTapResult.isFalse() + " (simple)"); + return longTapResult.isFalse(); + } + } + + @Override public boolean isFalseDoubleTap() { checkDestroyed(); diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java index 5d04b5f77479..c4723e895ee7 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java @@ -139,6 +139,11 @@ public class FalsingManagerProxy implements FalsingManager, Dumpable { } @Override + public boolean isFalseLongTap(int penalty) { + return mInternalFalsingManager.isFalseLongTap(penalty); + } + + @Override public boolean isFalseDoubleTap() { return mInternalFalsingManager.isFalseDoubleTap(); } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingModule.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingModule.java index 7b7f17e1568b..5302af9db836 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingModule.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingModule.java @@ -40,6 +40,7 @@ import dagger.multibindings.ElementsIntoSet; public interface FalsingModule { String BRIGHT_LINE_GESTURE_CLASSIFERS = "bright_line_gesture_classifiers"; String SINGLE_TAP_TOUCH_SLOP = "falsing_single_tap_touch_slop"; + String LONG_TAP_TOUCH_SLOP = "falsing_long_tap_slop"; String DOUBLE_TAP_TOUCH_SLOP = "falsing_double_tap_touch_slop"; String DOUBLE_TAP_TIMEOUT_MS = "falsing_double_tap_timeout_ms"; @@ -81,4 +82,11 @@ public interface FalsingModule { static float providesSingleTapTouchSlop(ViewConfiguration viewConfiguration) { return viewConfiguration.getScaledTouchSlop(); } + + /** */ + @Provides + @Named(LONG_TAP_TOUCH_SLOP) + static float providesLongTapTouchSlop(ViewConfiguration viewConfiguration) { + return viewConfiguration.getScaledTouchSlop() * 1.25f; + } } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/LongTapClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/LongTapClassifier.java new file mode 100644 index 000000000000..1963e69c1547 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/LongTapClassifier.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.classifier; + +import static com.android.systemui.classifier.FalsingModule.LONG_TAP_TOUCH_SLOP; + +import javax.inject.Inject; +import javax.inject.Named; + +/** + * Falsing classifier that accepts or rejects a gesture as a long tap. + */ +public class LongTapClassifier extends TapClassifier{ + + @Inject + LongTapClassifier(FalsingDataProvider dataProvider, + @Named(LONG_TAP_TOUCH_SLOP) float touchSlop) { + super(dataProvider, touchSlop); + } + +} diff --git a/packages/SystemUI/src/com/android/systemui/classifier/SingleTapClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/SingleTapClassifier.java index bd6fbfbd282e..7a7401dfdd22 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/SingleTapClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/SingleTapClassifier.java @@ -18,57 +18,17 @@ package com.android.systemui.classifier; import static com.android.systemui.classifier.FalsingModule.SINGLE_TAP_TOUCH_SLOP; -import android.view.MotionEvent; - -import java.util.List; - import javax.inject.Inject; import javax.inject.Named; /** - * Falsing classifier that accepts or rejects a single gesture as a tap. + * Falsing classifier that accepts or rejects a gesture as a single tap. */ -public class SingleTapClassifier extends FalsingClassifier { - private final float mTouchSlop; +public class SingleTapClassifier extends TapClassifier { @Inject SingleTapClassifier(FalsingDataProvider dataProvider, @Named(SINGLE_TAP_TOUCH_SLOP) float touchSlop) { - super(dataProvider); - mTouchSlop = touchSlop; - } - - @Override - Result calculateFalsingResult( - @Classifier.InteractionType int interactionType, - double historyBelief, double historyConfidence) { - return isTap(getRecentMotionEvents(), 0.5); - } - - /** Given a list of {@link android.view.MotionEvent}'s, returns true if the look like a tap. */ - public Result isTap(List<MotionEvent> motionEvents, double falsePenalty) { - if (motionEvents.isEmpty()) { - return falsed(0, "no motion events"); - } - float downX = motionEvents.get(0).getX(); - float downY = motionEvents.get(0).getY(); - - for (MotionEvent event : motionEvents) { - String reason; - if (Math.abs(event.getX() - downX) >= mTouchSlop) { - reason = "dX too big for a tap: " - + Math.abs(event.getX() - downX) - + "vs " - + mTouchSlop; - return falsed(falsePenalty, reason); - } else if (Math.abs(event.getY() - downY) >= mTouchSlop) { - reason = "dY too big for a tap: " - + Math.abs(event.getY() - downY) - + " vs " - + mTouchSlop; - return falsed(falsePenalty, reason); - } - } - return Result.passed(0); + super(dataProvider, touchSlop); } } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/TapClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/TapClassifier.java new file mode 100644 index 000000000000..e24cfaa0ff8f --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/TapClassifier.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.classifier; + +import android.view.MotionEvent; + +import java.util.List; + +/** + * Falsing classifier that accepts or rejects a gesture as a tap. + */ +public abstract class TapClassifier extends FalsingClassifier{ + private final float mTouchSlop; + + TapClassifier(FalsingDataProvider dataProvider, + float touchSlop) { + super(dataProvider); + mTouchSlop = touchSlop; + } + + @Override + Result calculateFalsingResult( + @Classifier.InteractionType int interactionType, + double historyBelief, double historyConfidence) { + return isTap(getRecentMotionEvents(), 0.5); + } + + /** Given a list of {@link android.view.MotionEvent}'s, returns true if the look like a tap. */ + public Result isTap(List<MotionEvent> motionEvents, double falsePenalty) { + if (motionEvents.isEmpty()) { + return falsed(0, "no motion events"); + } + float downX = motionEvents.get(0).getX(); + float downY = motionEvents.get(0).getY(); + + for (MotionEvent event : motionEvents) { + String reason; + if (Math.abs(event.getX() - downX) >= mTouchSlop) { + reason = "dX too big for a tap: " + + Math.abs(event.getX() - downX) + + "vs " + + mTouchSlop; + return falsed(falsePenalty, reason); + } else if (Math.abs(event.getY() - downY) >= mTouchSlop) { + reason = "dY too big for a tap: " + + Math.abs(event.getY() - downY) + + " vs " + + mTouchSlop; + return falsed(falsePenalty, reason); + } + } + return Result.passed(0); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt index 5e8ce6db971c..b11103a4d27b 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt @@ -20,11 +20,14 @@ import android.app.ActivityOptions import android.content.ComponentName import android.content.Intent import android.os.Bundle +import android.util.Log import android.view.View import android.view.ViewGroup import android.view.ViewStub import android.widget.Button import android.widget.TextView +import android.window.OnBackInvokedCallback +import android.window.OnBackInvokedDispatcher import androidx.activity.ComponentActivity import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.ItemTouchHelper @@ -42,7 +45,7 @@ import javax.inject.Inject /** * Activity for rearranging and removing controls for a given structure */ -class ControlsEditingActivity @Inject constructor( +open class ControlsEditingActivity @Inject constructor( private val controller: ControlsControllerImpl, private val broadcastDispatcher: BroadcastDispatcher, private val customIconCache: CustomIconCache, @@ -50,8 +53,9 @@ class ControlsEditingActivity @Inject constructor( ) : ComponentActivity() { companion object { + private const val DEBUG = false private const val TAG = "ControlsEditingActivity" - private const val EXTRA_STRUCTURE = ControlsFavoritingActivity.EXTRA_STRUCTURE + const val EXTRA_STRUCTURE = ControlsFavoritingActivity.EXTRA_STRUCTURE private val SUBTITLE_ID = R.string.controls_favorite_rearrange private val EMPTY_TEXT_ID = R.string.controls_favorite_removed } @@ -73,6 +77,13 @@ class ControlsEditingActivity @Inject constructor( } } + private val mOnBackInvokedCallback = OnBackInvokedCallback { + if (DEBUG) { + Log.d(TAG, "Predictive Back dispatcher called mOnBackInvokedCallback") + } + onBackPressed() + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -94,11 +105,22 @@ class ControlsEditingActivity @Inject constructor( setUpList() currentUserTracker.startTracking() + + if (DEBUG) { + Log.d(TAG, "Registered onBackInvokedCallback") + } + onBackInvokedDispatcher.registerOnBackInvokedCallback( + OnBackInvokedDispatcher.PRIORITY_DEFAULT, mOnBackInvokedCallback) } override fun onStop() { super.onStop() currentUserTracker.stopTracking() + + if (DEBUG) { + Log.d(TAG, "Unregistered onBackInvokedCallback") + } + onBackInvokedDispatcher.unregisterOnBackInvokedCallback(mOnBackInvokedCallback) } override fun onBackPressed() { diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt index be572c503bda..9b2a72823d86 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt @@ -24,6 +24,7 @@ import android.content.Intent import android.content.res.Configuration import android.os.Bundle import android.text.TextUtils +import android.util.Log import android.view.Gravity import android.view.View import android.view.ViewGroup @@ -32,6 +33,8 @@ import android.widget.Button import android.widget.FrameLayout import android.widget.TextView import android.widget.Toast +import android.window.OnBackInvokedCallback +import android.window.OnBackInvokedDispatcher import androidx.activity.ComponentActivity import androidx.viewpager2.widget.ViewPager2 import com.android.systemui.Prefs @@ -50,7 +53,7 @@ import java.util.concurrent.Executor import java.util.function.Consumer import javax.inject.Inject -class ControlsFavoritingActivity @Inject constructor( +open class ControlsFavoritingActivity @Inject constructor( @Main private val executor: Executor, private val controller: ControlsControllerImpl, private val listingController: ControlsListingController, @@ -59,6 +62,7 @@ class ControlsFavoritingActivity @Inject constructor( ) : ComponentActivity() { companion object { + private const val DEBUG = false private const val TAG = "ControlsFavoritingActivity" // If provided and no structure is available, use as the title @@ -67,7 +71,7 @@ class ControlsFavoritingActivity @Inject constructor( // If provided, show this structure page first const val EXTRA_STRUCTURE = "extra_structure" const val EXTRA_SINGLE_STRUCTURE = "extra_single_structure" - internal const val EXTRA_FROM_PROVIDER_SELECTOR = "extra_from_provider_selector" + const val EXTRA_FROM_PROVIDER_SELECTOR = "extra_from_provider_selector" private const val TOOLTIP_PREFS_KEY = Prefs.Key.CONTROLS_STRUCTURE_SWIPE_TOOLTIP_COUNT private const val TOOLTIP_MAX_SHOWN = 2 } @@ -102,6 +106,13 @@ class ControlsFavoritingActivity @Inject constructor( } } + private val mOnBackInvokedCallback = OnBackInvokedCallback { + if (DEBUG) { + Log.d(TAG, "Predictive Back dispatcher called mOnBackInvokedCallback") + } + onBackPressed() + } + private val listingCallback = object : ControlsListingController.ControlsListingCallback { override fun onServicesUpdated(serviceInfos: List<ControlsServiceInfo>) { @@ -346,13 +357,19 @@ class ControlsFavoritingActivity @Inject constructor( override fun onPause() { super.onPause() mTooltipManager?.hide(false) - } + } override fun onStart() { super.onStart() listingController.addCallback(listingCallback) currentUserTracker.startTracking() + + if (DEBUG) { + Log.d(TAG, "Registered onBackInvokedCallback") + } + onBackInvokedDispatcher.registerOnBackInvokedCallback( + OnBackInvokedDispatcher.PRIORITY_DEFAULT, mOnBackInvokedCallback) } override fun onResume() { @@ -365,13 +382,19 @@ class ControlsFavoritingActivity @Inject constructor( loadControls() isPagerLoaded = true } - } + } override fun onStop() { super.onStop() listingController.removeCallback(listingCallback) currentUserTracker.stopTracking() + + if (DEBUG) { + Log.d(TAG, "Unregistered onBackInvokedCallback") + } + onBackInvokedDispatcher.unregisterOnBackInvokedCallback( + mOnBackInvokedCallback) } override fun onConfigurationChanged(newConfig: Configuration) { diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt index b26615fe4702..47690a7fa487 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt @@ -20,16 +20,18 @@ import android.app.ActivityOptions import android.content.ComponentName import android.content.Intent import android.os.Bundle +import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.view.ViewStub import android.widget.Button import android.widget.TextView +import android.window.OnBackInvokedCallback +import android.window.OnBackInvokedDispatcher import androidx.activity.ComponentActivity import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView -import androidx.recyclerview.widget.RecyclerView.AdapterDataObserver import com.android.systemui.R import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.controls.controller.ControlsController @@ -44,7 +46,7 @@ import javax.inject.Inject /** * Activity to select an application to favorite the [Control] provided by them. */ -class ControlsProviderSelectorActivity @Inject constructor( +open class ControlsProviderSelectorActivity @Inject constructor( @Main private val executor: Executor, @Background private val backExecutor: Executor, private val listingController: ControlsListingController, @@ -54,6 +56,7 @@ class ControlsProviderSelectorActivity @Inject constructor( ) : ComponentActivity() { companion object { + private const val DEBUG = false private const val TAG = "ControlsProviderSelectorActivity" const val BACK_SHOULD_EXIT = "back_should_exit" } @@ -70,6 +73,13 @@ class ControlsProviderSelectorActivity @Inject constructor( } } + private val mOnBackInvokedCallback = OnBackInvokedCallback { + if (DEBUG) { + Log.d(TAG, "Predictive Back dispatcher called mOnBackInvokedCallback") + } + onBackPressed() + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -141,11 +151,22 @@ class ControlsProviderSelectorActivity @Inject constructor( } }) } + + if (DEBUG) { + Log.d(TAG, "Registered onBackInvokedCallback") + } + onBackInvokedDispatcher.registerOnBackInvokedCallback( + OnBackInvokedDispatcher.PRIORITY_DEFAULT, mOnBackInvokedCallback) } override fun onStop() { super.onStop() currentUserTracker.stopTracking() + + if (DEBUG) { + Log.d(TAG, "Unregistered onBackInvokedCallback") + } + onBackInvokedDispatcher.unregisterOnBackInvokedCallback(mOnBackInvokedCallback) } /** diff --git a/packages/SystemUI/src/com/android/systemui/dagger/GlobalRootComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/GlobalRootComponent.java index 9e33ee1faab3..fe89c9a1e3b9 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/GlobalRootComponent.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/GlobalRootComponent.java @@ -27,7 +27,9 @@ import dagger.BindsInstance; import dagger.Component; /** - * Root component for Dagger injection. + * Base root component for Dagger injection. + * + * See {@link ReferenceGlobalRootComponent} for the one actually used by AOSP. */ @Singleton @Component(modules = {GlobalModule.class}) @@ -51,7 +53,7 @@ public interface GlobalRootComponent { WMComponent.Builder getWMComponentBuilder(); /** - * Builder for a {@link SysUIComponent}, which makes it a subcomponent of this class. + * Builder for a {@link ReferenceSysUIComponent}, which makes it a subcomponent of this class. */ SysUIComponent.Builder getSysUIComponent(); diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceGlobalRootComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceGlobalRootComponent.java new file mode 100644 index 000000000000..be93c9fdf395 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceGlobalRootComponent.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.dagger; + +import javax.inject.Singleton; + +import dagger.Component; + +/** + * Root component for Dagger injection used in AOSP. + */ +@Singleton +@Component(modules = {GlobalModule.class}) +public interface ReferenceGlobalRootComponent extends GlobalRootComponent { + + /** + * Builder for a ReferenceGlobalRootComponent. + */ + @Component.Builder + interface Builder extends GlobalRootComponent.Builder { + ReferenceGlobalRootComponent build(); + } + + /** + * Builder for a {@link ReferenceSysUIComponent}, which makes it a subcomponent of this class. + */ + ReferenceSysUIComponent.Builder getSysUIComponent(); +} diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSysUIComponent.java new file mode 100644 index 000000000000..7ab36e84178e --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSysUIComponent.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.dagger; + +import com.android.systemui.statusbar.QsFrameTranslateModule; + +import dagger.Subcomponent; + +/** + * Dagger Subcomponent for Core SysUI used in AOSP. + */ +@SysUISingleton +@Subcomponent(modules = { + DefaultComponentBinder.class, + DependencyProvider.class, + QsFrameTranslateModule.class, + SystemUIBinder.class, + SystemUIModule.class, + SystemUICoreStartableModule.class, + ReferenceSystemUIModule.class}) +public interface ReferenceSysUIComponent extends SysUIComponent { + + /** + * Builder for a ReferenceSysUIComponent. + */ + @SysUISingleton + @Subcomponent.Builder + interface Builder extends SysUIComponent.Builder { + ReferenceSysUIComponent build(); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java index 48bef97c30fb..fd690dfd5dfa 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java @@ -44,6 +44,7 @@ import com.android.systemui.screenshot.ReferenceScreenshotModule; import com.android.systemui.shade.NotificationShadeWindowControllerImpl; import com.android.systemui.shade.ShadeController; import com.android.systemui.shade.ShadeControllerImpl; +import com.android.systemui.shade.ShadeExpansionStateManager; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl; @@ -162,7 +163,8 @@ public abstract class ReferenceSystemUIModule { ConfigurationController configurationController, @Main Handler handler, AccessibilityManagerWrapper accessibilityManagerWrapper, - UiEventLogger uiEventLogger) { + UiEventLogger uiEventLogger, + ShadeExpansionStateManager shadeExpansionStateManager) { return new HeadsUpManagerPhone( context, headsUpManagerLogger, @@ -173,7 +175,8 @@ public abstract class ReferenceSystemUIModule { configurationController, handler, accessibilityManagerWrapper, - uiEventLogger + uiEventLogger, + shadeExpansionStateManager ); } diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java index d05bd5120872..a14b0ee04d8a 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java @@ -40,7 +40,6 @@ import com.android.wm.shell.back.BackAnimation; import com.android.wm.shell.bubbles.Bubbles; import com.android.wm.shell.desktopmode.DesktopMode; import com.android.wm.shell.displayareahelper.DisplayAreaHelper; -import com.android.wm.shell.floating.FloatingTasks; import com.android.wm.shell.onehanded.OneHanded; import com.android.wm.shell.pip.Pip; import com.android.wm.shell.recents.RecentTasks; @@ -58,7 +57,9 @@ import dagger.BindsInstance; import dagger.Subcomponent; /** - * Dagger Subcomponent for Core SysUI. + * An example Dagger Subcomponent for Core SysUI. + * + * See {@link ReferenceSysUIComponent} for the one actually used by AOSP. */ @SysUISingleton @Subcomponent(modules = { @@ -111,9 +112,6 @@ public interface SysUIComponent { Builder setBackAnimation(Optional<BackAnimation> b); @BindsInstance - Builder setFloatingTasks(Optional<FloatingTasks> f); - - @BindsInstance Builder setDesktopMode(Optional<DesktopMode> d); SysUIComponent build(); diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java index 6db562107357..95919c6b2c0d 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java @@ -41,12 +41,14 @@ import com.android.systemui.demomode.dagger.DemoModeModule; import com.android.systemui.doze.dagger.DozeComponent; import com.android.systemui.dreams.dagger.DreamModule; import com.android.systemui.dump.DumpManager; +import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.FlagsModule; import com.android.systemui.fragments.FragmentService; import com.android.systemui.keyguard.data.BouncerViewModule; import com.android.systemui.log.dagger.LogModule; import com.android.systemui.mediaprojection.appselector.MediaProjectionModule; import com.android.systemui.model.SysUiState; +import com.android.systemui.motiontool.MotionToolModule; import com.android.systemui.navigationbar.NavigationBarComponent; import com.android.systemui.notetask.NoteTaskModule; import com.android.systemui.people.PeopleModule; @@ -134,6 +136,7 @@ import dagger.Provides; FooterActionsModule.class, LogModule.class, MediaProjectionModule.class, + MotionToolModule.class, PeopleHubModule.class, PeopleModule.class, PluginModule.class, @@ -240,6 +243,7 @@ public abstract class SystemUIModule { CommonNotifCollection notifCollection, NotifPipeline notifPipeline, SysUiState sysUiState, + FeatureFlags featureFlags, @Main Executor sysuiMainExecutor) { return Optional.ofNullable(BubblesManager.create(context, bubblesOptional, @@ -256,6 +260,7 @@ public abstract class SystemUIModule { notifCollection, notifPipeline, sysUiState, + featureFlags, sysuiMainExecutor)); } diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java index 096f96949382..d756f3a44655 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java @@ -32,7 +32,6 @@ import com.android.wm.shell.dagger.WMShellModule; import com.android.wm.shell.dagger.WMSingleton; import com.android.wm.shell.desktopmode.DesktopMode; import com.android.wm.shell.displayareahelper.DisplayAreaHelper; -import com.android.wm.shell.floating.FloatingTasks; import com.android.wm.shell.onehanded.OneHanded; import com.android.wm.shell.pip.Pip; import com.android.wm.shell.recents.RecentTasks; @@ -111,9 +110,6 @@ public interface WMComponent { @WMSingleton Optional<BackAnimation> getBackAnimation(); - @WMSingleton - Optional<FloatingTasks> getFloatingTasks(); - /** * Optional {@link DesktopMode} component for interacting with desktop mode. */ diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java index 60227ee95fc2..937884c79072 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java @@ -171,7 +171,10 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi @Override public void onSensorChanged(SensorEvent event) { - Trace.beginSection("DozeScreenBrightness.onSensorChanged" + event.values[0]); + if (Trace.isEnabled()) { + Trace.traceBegin( + Trace.TRACE_TAG_APP, "DozeScreenBrightness.onSensorChanged" + event.values[0]); + } try { if (mRegistered) { mLastSensorValue = (int) event.values[0]; diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt new file mode 100644 index 000000000000..d8dd6a21d4c1 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.dreams + +import android.animation.Animator +import android.animation.AnimatorListenerAdapter +import android.animation.AnimatorSet +import android.animation.ValueAnimator +import android.view.View +import androidx.core.animation.doOnEnd +import com.android.systemui.animation.Interpolators +import com.android.systemui.dreams.complication.ComplicationHostViewController +import com.android.systemui.dreams.complication.ComplicationLayoutParams +import com.android.systemui.dreams.dagger.DreamOverlayModule +import com.android.systemui.statusbar.BlurUtils +import java.util.function.Consumer +import javax.inject.Inject +import javax.inject.Named + +/** Controller for dream overlay animations. */ +class DreamOverlayAnimationsController +@Inject +constructor( + private val mBlurUtils: BlurUtils, + private val mComplicationHostViewController: ComplicationHostViewController, + private val mStatusBarViewController: DreamOverlayStatusBarViewController, + private val mOverlayStateController: DreamOverlayStateController, + @Named(DreamOverlayModule.DREAM_IN_BLUR_ANIMATION_DURATION) + private val mDreamInBlurAnimDuration: Int, + @Named(DreamOverlayModule.DREAM_IN_BLUR_ANIMATION_DELAY) private val mDreamInBlurAnimDelay: Int, + @Named(DreamOverlayModule.DREAM_IN_COMPLICATIONS_ANIMATION_DURATION) + private val mDreamInComplicationsAnimDuration: Int, + @Named(DreamOverlayModule.DREAM_IN_TOP_COMPLICATIONS_ANIMATION_DELAY) + private val mDreamInTopComplicationsAnimDelay: Int, + @Named(DreamOverlayModule.DREAM_IN_BOTTOM_COMPLICATIONS_ANIMATION_DELAY) + private val mDreamInBottomComplicationsAnimDelay: Int +) { + + var mEntryAnimations: AnimatorSet? = null + + /** Starts the dream content and dream overlay entry animations. */ + fun startEntryAnimations(view: View) { + cancelRunningEntryAnimations() + + mEntryAnimations = AnimatorSet() + mEntryAnimations?.apply { + playTogether( + buildDreamInBlurAnimator(view), + buildDreamInTopComplicationsAnimator(), + buildDreamInBottomComplicationsAnimator() + ) + doOnEnd { mOverlayStateController.setEntryAnimationsFinished(true) } + start() + } + } + + /** Cancels the dream content and dream overlay animations, if they're currently running. */ + fun cancelRunningEntryAnimations() { + if (mEntryAnimations?.isRunning == true) { + mEntryAnimations?.cancel() + } + mEntryAnimations = null + } + + private fun buildDreamInBlurAnimator(view: View): Animator { + return ValueAnimator.ofFloat(1f, 0f).apply { + duration = mDreamInBlurAnimDuration.toLong() + startDelay = mDreamInBlurAnimDelay.toLong() + interpolator = Interpolators.LINEAR + addUpdateListener { animator: ValueAnimator -> + mBlurUtils.applyBlur( + view.viewRootImpl, + mBlurUtils.blurRadiusOfRatio(animator.animatedValue as Float).toInt(), + false /*opaque*/ + ) + } + } + } + + private fun buildDreamInTopComplicationsAnimator(): Animator { + return ValueAnimator.ofFloat(0f, 1f).apply { + duration = mDreamInComplicationsAnimDuration.toLong() + startDelay = mDreamInTopComplicationsAnimDelay.toLong() + interpolator = Interpolators.LINEAR + addUpdateListener { va: ValueAnimator -> + setTopElementsAlpha(va.animatedValue as Float) + } + } + } + + private fun buildDreamInBottomComplicationsAnimator(): Animator { + return ValueAnimator.ofFloat(0f, 1f).apply { + duration = mDreamInComplicationsAnimDuration.toLong() + startDelay = mDreamInBottomComplicationsAnimDelay.toLong() + interpolator = Interpolators.LINEAR + addUpdateListener { va: ValueAnimator -> + setBottomElementsAlpha(va.animatedValue as Float) + } + addListener( + object : AnimatorListenerAdapter() { + override fun onAnimationStart(animation: Animator) { + mComplicationHostViewController + .getViewsAtPosition(ComplicationLayoutParams.POSITION_BOTTOM) + .forEach(Consumer { v: View -> v.visibility = View.VISIBLE }) + } + } + ) + } + } + + /** Sets alpha of top complications and the status bar. */ + private fun setTopElementsAlpha(alpha: Float) { + mComplicationHostViewController + .getViewsAtPosition(ComplicationLayoutParams.POSITION_TOP) + .forEach(Consumer { v: View -> setAlphaAndEnsureVisible(v, alpha) }) + mStatusBarViewController.setAlpha(alpha) + } + + /** Sets alpha of bottom complications. */ + private fun setBottomElementsAlpha(alpha: Float) { + mComplicationHostViewController + .getViewsAtPosition(ComplicationLayoutParams.POSITION_BOTTOM) + .forEach(Consumer { v: View -> setAlphaAndEnsureVisible(v, alpha) }) + } + + private fun setAlphaAndEnsureVisible(view: View, alpha: Float) { + if (alpha > 0 && view.visibility != View.VISIBLE) { + view.visibility = View.VISIBLE + } + + view.alpha = alpha + } +} diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java index 733a80dd7f69..5c6d24813570 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java @@ -35,7 +35,7 @@ import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dreams.complication.ComplicationHostViewController; import com.android.systemui.dreams.dagger.DreamOverlayComponent; import com.android.systemui.dreams.dagger.DreamOverlayModule; -import com.android.systemui.keyguard.domain.interactor.BouncerCallbackInteractor; +import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor; import com.android.systemui.statusbar.BlurUtils; import com.android.systemui.statusbar.phone.KeyguardBouncer; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; @@ -54,6 +54,8 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve private final DreamOverlayStatusBarViewController mStatusBarViewController; private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; private final BlurUtils mBlurUtils; + private final DreamOverlayAnimationsController mDreamOverlayAnimationsController; + private final DreamOverlayStateController mStateController; private final ComplicationHostViewController mComplicationHostViewController; @@ -74,14 +76,14 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve // Main thread handler used to schedule periodic tasks (e.g. burn-in protection updates). private final Handler mHandler; private final int mDreamOverlayMaxTranslationY; - private final BouncerCallbackInteractor mBouncerCallbackInteractor; + private final PrimaryBouncerCallbackInteractor mPrimaryBouncerCallbackInteractor; private long mJitterStartTimeMillis; private boolean mBouncerAnimating; - private final KeyguardBouncer.BouncerExpansionCallback mBouncerExpansionCallback = - new KeyguardBouncer.BouncerExpansionCallback() { + private final KeyguardBouncer.PrimaryBouncerExpansionCallback mBouncerExpansionCallback = + new KeyguardBouncer.PrimaryBouncerExpansionCallback() { @Override public void onStartingToShow() { @@ -134,12 +136,16 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve @Named(DreamOverlayModule.BURN_IN_PROTECTION_UPDATE_INTERVAL) long burnInProtectionUpdateInterval, @Named(DreamOverlayModule.MILLIS_UNTIL_FULL_JITTER) long millisUntilFullJitter, - BouncerCallbackInteractor bouncerCallbackInteractor) { + PrimaryBouncerCallbackInteractor primaryBouncerCallbackInteractor, + DreamOverlayAnimationsController animationsController, + DreamOverlayStateController stateController) { super(containerView); mDreamOverlayContentView = contentView; mStatusBarViewController = statusBarViewController; mStatusBarKeyguardViewManager = statusBarKeyguardViewManager; mBlurUtils = blurUtils; + mDreamOverlayAnimationsController = animationsController; + mStateController = stateController; mComplicationHostViewController = complicationHostViewController; mDreamOverlayMaxTranslationY = resources.getDimensionPixelSize( @@ -154,7 +160,7 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve mMaxBurnInOffset = maxBurnInOffset; mBurnInProtectionUpdateInterval = burnInProtectionUpdateInterval; mMillisUntilFullJitter = millisUntilFullJitter; - mBouncerCallbackInteractor = bouncerCallbackInteractor; + mPrimaryBouncerCallbackInteractor = primaryBouncerCallbackInteractor; } @Override @@ -167,21 +173,28 @@ public class DreamOverlayContainerViewController extends ViewController<DreamOve protected void onViewAttached() { mJitterStartTimeMillis = System.currentTimeMillis(); mHandler.postDelayed(this::updateBurnInOffsets, mBurnInProtectionUpdateInterval); - final KeyguardBouncer bouncer = mStatusBarKeyguardViewManager.getBouncer(); + final KeyguardBouncer bouncer = mStatusBarKeyguardViewManager.getPrimaryBouncer(); if (bouncer != null) { bouncer.addBouncerExpansionCallback(mBouncerExpansionCallback); } - mBouncerCallbackInteractor.addBouncerExpansionCallback(mBouncerExpansionCallback); + mPrimaryBouncerCallbackInteractor.addBouncerExpansionCallback(mBouncerExpansionCallback); + + // Start dream entry animations. Skip animations for low light clock. + if (!mStateController.isLowLightActive()) { + mDreamOverlayAnimationsController.startEntryAnimations(mView); + } } @Override protected void onViewDetached() { mHandler.removeCallbacks(this::updateBurnInOffsets); - final KeyguardBouncer bouncer = mStatusBarKeyguardViewManager.getBouncer(); + final KeyguardBouncer bouncer = mStatusBarKeyguardViewManager.getPrimaryBouncer(); if (bouncer != null) { bouncer.removeBouncerExpansionCallback(mBouncerExpansionCallback); } - mBouncerCallbackInteractor.removeBouncerExpansionCallback(mBouncerExpansionCallback); + mPrimaryBouncerCallbackInteractor.removeBouncerExpansionCallback(mBouncerExpansionCallback); + + mDreamOverlayAnimationsController.cancelRunningEntryAnimations(); } View getContainerView() { diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java index d1b73685a3f3..8542412f82f8 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java @@ -90,13 +90,15 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ new KeyguardUpdateMonitorCallback() { @Override public void onShadeExpandedChanged(boolean expanded) { - if (mLifecycleRegistry.getCurrentState() != Lifecycle.State.RESUMED - && mLifecycleRegistry.getCurrentState() != Lifecycle.State.STARTED) { - return; - } - - mLifecycleRegistry.setCurrentState( - expanded ? Lifecycle.State.STARTED : Lifecycle.State.RESUMED); + mExecutor.execute(() -> { + if (getCurrentStateLocked() != Lifecycle.State.RESUMED + && getCurrentStateLocked() != Lifecycle.State.STARTED) { + return; + } + + setCurrentStateLocked( + expanded ? Lifecycle.State.STARTED : Lifecycle.State.RESUMED); + }); } }; @@ -146,29 +148,30 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ () -> mExecutor.execute(DreamOverlayService.this::requestExit); mDreamOverlayComponent = dreamOverlayComponentFactory.create(viewModelStore, host); mLifecycleRegistry = mDreamOverlayComponent.getLifecycleRegistry(); - setCurrentState(Lifecycle.State.CREATED); - } - private void setCurrentState(Lifecycle.State state) { - mExecutor.execute(() -> mLifecycleRegistry.setCurrentState(state)); + mExecutor.execute(() -> setCurrentStateLocked(Lifecycle.State.CREATED)); } @Override public void onDestroy() { mKeyguardUpdateMonitor.removeCallback(mKeyguardCallback); - setCurrentState(Lifecycle.State.DESTROYED); - resetCurrentDreamOverlay(); + mExecutor.execute(() -> { + setCurrentStateLocked(Lifecycle.State.DESTROYED); + + resetCurrentDreamOverlayLocked(); + + mDestroyed = true; + }); - mDestroyed = true; super.onDestroy(); } @Override public void onStartDream(@NonNull WindowManager.LayoutParams layoutParams) { - setCurrentState(Lifecycle.State.STARTED); - mExecutor.execute(() -> { + setCurrentStateLocked(Lifecycle.State.STARTED); + mUiEventLogger.log(DreamOverlayEvent.DREAM_OVERLAY_ENTER_START); if (mDestroyed) { @@ -181,7 +184,7 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ // Reset the current dream overlay before starting a new one. This can happen // when two dreams overlap (briefly, for a smoother dream transition) and both // dreams are bound to the dream overlay service. - resetCurrentDreamOverlay(); + resetCurrentDreamOverlayLocked(); } mDreamOverlayContainerViewController = @@ -191,7 +194,7 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ mStateController.setShouldShowComplications(shouldShowComplications()); addOverlayWindowLocked(layoutParams); - setCurrentState(Lifecycle.State.RESUMED); + setCurrentStateLocked(Lifecycle.State.RESUMED); mStateController.setOverlayActive(true); final ComponentName dreamComponent = getDreamComponent(); mStateController.setLowLightActive( @@ -202,6 +205,14 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ }); } + private Lifecycle.State getCurrentStateLocked() { + return mLifecycleRegistry.getCurrentState(); + } + + private void setCurrentStateLocked(Lifecycle.State state) { + mLifecycleRegistry.setCurrentState(state); + } + /** * Inserts {@link Window} to host the dream overlay into the dream's parent window. Must be * called from the main executing thread. The window attributes closely mirror those that are @@ -231,13 +242,13 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ // Make extra sure the container view has been removed from its old parent (otherwise we // risk an IllegalStateException in some cases when setting the container view as the // window's content view and the container view hasn't been properly removed previously). - removeContainerViewFromParent(); + removeContainerViewFromParentLocked(); mWindow.setContentView(mDreamOverlayContainerViewController.getContainerView()); mWindowManager.addView(mWindow.getDecorView(), mWindow.getAttributes()); } - private void removeContainerViewFromParent() { + private void removeContainerViewFromParentLocked() { View containerView = mDreamOverlayContainerViewController.getContainerView(); if (containerView == null) { return; @@ -250,13 +261,14 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ parentView.removeView(containerView); } - private void resetCurrentDreamOverlay() { + private void resetCurrentDreamOverlayLocked() { if (mStarted && mWindow != null) { mWindowManager.removeView(mWindow.getDecorView()); } mStateController.setOverlayActive(false); mStateController.setLowLightActive(false); + mStateController.setEntryAnimationsFinished(false); mDreamOverlayContainerViewController = null; mDreamOverlayTouchMonitor = null; diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java index 72feaca59ace..e80d0beabf2b 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java @@ -51,6 +51,7 @@ public class DreamOverlayStateController implements public static final int STATE_DREAM_OVERLAY_ACTIVE = 1 << 0; public static final int STATE_LOW_LIGHT_ACTIVE = 1 << 1; + public static final int STATE_DREAM_ENTRY_ANIMATIONS_FINISHED = 1 << 2; private static final int OP_CLEAR_STATE = 1; private static final int OP_SET_STATE = 2; @@ -202,6 +203,14 @@ public class DreamOverlayStateController implements return containsState(STATE_LOW_LIGHT_ACTIVE); } + /** + * Returns whether the dream content and dream overlay entry animations are finished. + * @return {@code true} if animations are finished, {@code false} otherwise. + */ + public boolean areEntryAnimationsFinished() { + return containsState(STATE_DREAM_ENTRY_ANIMATIONS_FINISHED); + } + private boolean containsState(int state) { return (mState & state) != 0; } @@ -218,7 +227,7 @@ public class DreamOverlayStateController implements } if (existingState != mState) { - notifyCallbacks(callback -> callback.onStateChanged()); + notifyCallbacks(Callback::onStateChanged); } } @@ -239,6 +248,15 @@ public class DreamOverlayStateController implements } /** + * Sets whether dream content and dream overlay entry animations are finished. + * @param finished {@code true} if entry animations are finished, {@code false} otherwise. + */ + public void setEntryAnimationsFinished(boolean finished) { + modifyState(finished ? OP_SET_STATE : OP_CLEAR_STATE, + STATE_DREAM_ENTRY_ANIMATIONS_FINISHED); + } + + /** * Returns the available complication types. */ @Complication.ComplicationType diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java index bb1c4303041a..d17fbe31c8d2 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java @@ -16,10 +16,6 @@ package com.android.systemui.dreams; -import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN; -import static android.app.StatusBarManager.WINDOW_STATE_HIDING; -import static android.app.StatusBarManager.WINDOW_STATE_SHOWING; - import android.app.AlarmManager; import android.app.StatusBarManager; import android.content.res.Resources; @@ -83,6 +79,9 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve private boolean mIsAttached; + // Whether dream entry animations are finished. + private boolean mEntryAnimationsFinished = false; + private final NetworkRequest mNetworkRequest = new NetworkRequest.Builder() .clearCapabilities() .addTransportType(NetworkCapabilities.TRANSPORT_WIFI).build(); @@ -109,7 +108,9 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve new DreamOverlayStateController.Callback() { @Override public void onStateChanged() { - updateLowLightState(); + mEntryAnimationsFinished = + mDreamOverlayStateController.areEntryAnimationsFinished(); + updateVisibility(); } }; @@ -195,7 +196,6 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve mStatusBarItemsProvider.addCallback(mStatusBarItemsProviderCallback); mDreamOverlayStateController.addCallback(mDreamOverlayStateCallback); - updateLowLightState(); mTouchInsetSession.addViewToTracking(mView); } @@ -216,6 +216,26 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve mIsAttached = false; } + /** + * Sets alpha of the dream overlay status bar. + * + * No-op if the dream overlay status bar should not be shown. + */ + protected void setAlpha(float alpha) { + updateVisibility(); + + if (mView.getVisibility() != View.VISIBLE) { + return; + } + + mView.setAlpha(alpha); + } + + private boolean shouldShowStatusBar() { + return !mDreamOverlayStateController.isLowLightActive() + && !mStatusBarWindowStateController.windowIsShowing(); + } + private void updateWifiUnavailableStatusIcon() { final NetworkCapabilities capabilities = mConnectivityManager.getNetworkCapabilities( @@ -235,13 +255,12 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve hasAlarm ? buildAlarmContentDescription(alarm) : null); } - private void updateLowLightState() { - int visibility = View.VISIBLE; - if (mDreamOverlayStateController.isLowLightActive() - || mStatusBarWindowStateController.windowIsShowing()) { - visibility = View.INVISIBLE; + private void updateVisibility() { + if (shouldShowStatusBar()) { + mView.setVisibility(View.VISIBLE); + } else { + mView.setVisibility(View.INVISIBLE); } - mView.setVisibility(visibility); } private String buildAlarmContentDescription(AlarmManager.AlarmClockInfo alarm) { @@ -298,21 +317,11 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve } private void onSystemStatusBarStateChanged(@StatusBarManager.WindowVisibleState int state) { - mMainExecutor.execute(() -> { - if (!mIsAttached || mDreamOverlayStateController.isLowLightActive()) { - return; - } + if (!mIsAttached || !mEntryAnimationsFinished) { + return; + } - switch (state) { - case WINDOW_STATE_SHOWING: - mView.setVisibility(View.INVISIBLE); - break; - case WINDOW_STATE_HIDING: - case WINDOW_STATE_HIDDEN: - mView.setVisibility(View.VISIBLE); - break; - } - }); + mMainExecutor.execute(this::updateVisibility); } private void onStatusBarItemsChanged(List<StatusBarItem> newItems) { 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 fd6cfc0700ad..100ccc35e638 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationHostViewController.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationHostViewController.java @@ -28,6 +28,7 @@ import android.view.View; import androidx.constraintlayout.widget.ConstraintLayout; import androidx.lifecycle.LifecycleOwner; +import com.android.systemui.dreams.DreamOverlayStateController; import com.android.systemui.util.ViewController; import java.util.Collection; @@ -49,20 +50,34 @@ public class ComplicationHostViewController extends ViewController<ConstraintLay private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private final ComplicationLayoutEngine mLayoutEngine; + private final DreamOverlayStateController mDreamOverlayStateController; private final LifecycleOwner mLifecycleOwner; private final ComplicationCollectionViewModel mComplicationCollectionViewModel; private final HashMap<ComplicationId, Complication.ViewHolder> mComplications = new HashMap<>(); + // Whether dream entry animations are finished. + private boolean mEntryAnimationsFinished = false; + @Inject protected ComplicationHostViewController( @Named(SCOPED_COMPLICATIONS_LAYOUT) ConstraintLayout view, ComplicationLayoutEngine layoutEngine, + DreamOverlayStateController dreamOverlayStateController, LifecycleOwner lifecycleOwner, @Named(SCOPED_COMPLICATIONS_MODEL) ComplicationCollectionViewModel viewModel) { super(view); mLayoutEngine = layoutEngine; mLifecycleOwner = lifecycleOwner; mComplicationCollectionViewModel = viewModel; + mDreamOverlayStateController = dreamOverlayStateController; + + mDreamOverlayStateController.addCallback(new DreamOverlayStateController.Callback() { + @Override + public void onStateChanged() { + mEntryAnimationsFinished = + mDreamOverlayStateController.areEntryAnimationsFinished(); + } + }); } @Override @@ -123,6 +138,11 @@ public class ComplicationHostViewController extends ViewController<ConstraintLay final ComplicationId id = complication.getId(); final Complication.ViewHolder viewHolder = complication.getComplication() .createView(complication); + // Complications to be added before dream entry animations are finished are set + // to invisible and are animated in. + if (!mEntryAnimationsFinished) { + viewHolder.getView().setVisibility(View.INVISIBLE); + } mComplications.put(id, viewHolder); if (viewHolder.getView().getParent() != null) { Log.e(TAG, "View for complication " diff --git a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java index 4fe1622d73a5..cb012fa42e94 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java @@ -47,6 +47,14 @@ public abstract class DreamOverlayModule { public static final String BURN_IN_PROTECTION_UPDATE_INTERVAL = "burn_in_protection_update_interval"; public static final String MILLIS_UNTIL_FULL_JITTER = "millis_until_full_jitter"; + public static final String DREAM_IN_BLUR_ANIMATION_DURATION = "dream_in_blur_anim_duration"; + public static final String DREAM_IN_BLUR_ANIMATION_DELAY = "dream_in_blur_anim_delay"; + public static final String DREAM_IN_COMPLICATIONS_ANIMATION_DURATION = + "dream_in_complications_anim_duration"; + public static final String DREAM_IN_TOP_COMPLICATIONS_ANIMATION_DELAY = + "dream_in_top_complications_anim_delay"; + public static final String DREAM_IN_BOTTOM_COMPLICATIONS_ANIMATION_DELAY = + "dream_in_bottom_complications_anim_delay"; /** */ @Provides @@ -114,6 +122,51 @@ public abstract class DreamOverlayModule { return resources.getInteger(R.integer.config_dreamOverlayMillisUntilFullJitter); } + /** + * Duration in milliseconds of the dream in un-blur animation. + */ + @Provides + @Named(DREAM_IN_BLUR_ANIMATION_DURATION) + static int providesDreamInBlurAnimationDuration(@Main Resources resources) { + return resources.getInteger(R.integer.config_dreamOverlayInBlurDurationMs); + } + + /** + * Delay in milliseconds of the dream in un-blur animation. + */ + @Provides + @Named(DREAM_IN_BLUR_ANIMATION_DELAY) + static int providesDreamInBlurAnimationDelay(@Main Resources resources) { + return resources.getInteger(R.integer.config_dreamOverlayInBlurDelayMs); + } + + /** + * Duration in milliseconds of the dream in complications fade-in animation. + */ + @Provides + @Named(DREAM_IN_COMPLICATIONS_ANIMATION_DURATION) + static int providesDreamInComplicationsAnimationDuration(@Main Resources resources) { + return resources.getInteger(R.integer.config_dreamOverlayInComplicationsDurationMs); + } + + /** + * Delay in milliseconds of the dream in top complications fade-in animation. + */ + @Provides + @Named(DREAM_IN_TOP_COMPLICATIONS_ANIMATION_DELAY) + static int providesDreamInTopComplicationsAnimationDelay(@Main Resources resources) { + return resources.getInteger(R.integer.config_dreamOverlayInTopComplicationsDelayMs); + } + + /** + * Delay in milliseconds of the dream in bottom complications fade-in animation. + */ + @Provides + @Named(DREAM_IN_BOTTOM_COMPLICATIONS_ANIMATION_DELAY) + static int providesDreamInBottomComplicationsAnimationDelay(@Main Resources resources) { + return resources.getInteger(R.integer.config_dreamOverlayInBottomComplicationsDelayMs); + } + @Provides @DreamOverlayComponent.DreamOverlayScope static LifecycleOwner providesLifecycleOwner(Lazy<LifecycleRegistry> lifecycleRegistryLazy) { 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 0dba4ff84c99..92cdcf99f013 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java @@ -116,7 +116,7 @@ public class BouncerSwipeTouchHandler implements DreamTouchHandler { if (mCapture) { // Since the user is dragging the bouncer up, set scrimmed to false. - mStatusBarKeyguardViewManager.showBouncer(false); + mStatusBarKeyguardViewManager.showPrimaryBouncer(false); } } diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.kt b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.kt index fb4fc928c8dc..95e7ad969e35 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.kt @@ -34,9 +34,6 @@ interface FeatureFlags : FlagListenable, Dumpable { fun isEnabled(flag: ResourceBooleanFlag): Boolean /** Returns a boolean value for the given flag. */ - fun isEnabled(flag: DeviceConfigBooleanFlag): Boolean - - /** Returns a boolean value for the given flag. */ fun isEnabled(flag: SysPropBooleanFlag): Boolean /** Returns a string value for the given flag. */ @@ -44,4 +41,10 @@ interface FeatureFlags : FlagListenable, Dumpable { /** Returns a string value for the given flag. */ fun getString(flag: ResourceStringFlag): String + + /** Returns an int value for a given flag/ */ + fun getInt(flag: IntFlag): Int + + /** Returns an int value for a given flag/ */ + fun getInt(flag: ResourceIntFlag): Int } diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java index 20e55a0f0507..ec3fdecb919a 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java +++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java @@ -39,7 +39,6 @@ import androidx.annotation.Nullable; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; -import com.android.systemui.util.DeviceConfigProxy; import com.android.systemui.util.settings.SecureSettings; import org.jetbrains.annotations.NotNull; @@ -76,11 +75,11 @@ public class FeatureFlagsDebug implements FeatureFlags { private final SecureSettings mSecureSettings; private final Resources mResources; private final SystemPropertiesHelper mSystemProperties; - private final DeviceConfigProxy mDeviceConfigProxy; private final ServerFlagReader mServerFlagReader; private final Map<Integer, Flag<?>> mAllFlags; private final Map<Integer, Boolean> mBooleanFlagCache = new TreeMap<>(); private final Map<Integer, String> mStringFlagCache = new TreeMap<>(); + private final Map<Integer, Integer> mIntFlagCache = new TreeMap<>(); private final Restarter mRestarter; private final ServerFlagReader.ChangeListener mOnPropertiesChanged = @@ -98,7 +97,6 @@ public class FeatureFlagsDebug implements FeatureFlags { SecureSettings secureSettings, SystemPropertiesHelper systemProperties, @Main Resources resources, - DeviceConfigProxy deviceConfigProxy, ServerFlagReader serverFlagReader, @Named(ALL_FLAGS) Map<Integer, Flag<?>> allFlags, Restarter restarter) { @@ -107,7 +105,6 @@ public class FeatureFlagsDebug implements FeatureFlags { mSecureSettings = secureSettings; mResources = resources; mSystemProperties = systemProperties; - mDeviceConfigProxy = deviceConfigProxy; mServerFlagReader = serverFlagReader; mAllFlags = allFlags; mRestarter = restarter; @@ -139,7 +136,7 @@ public class FeatureFlagsDebug implements FeatureFlags { int id = flag.getId(); if (!mBooleanFlagCache.containsKey(id)) { mBooleanFlagCache.put(id, - readFlagValue(id, flag.getDefault())); + readBooleanFlagInternal(flag, flag.getDefault())); } return mBooleanFlagCache.get(id); @@ -150,19 +147,7 @@ public class FeatureFlagsDebug implements FeatureFlags { int id = flag.getId(); if (!mBooleanFlagCache.containsKey(id)) { mBooleanFlagCache.put(id, - readFlagValue(id, mResources.getBoolean(flag.getResourceId()))); - } - - return mBooleanFlagCache.get(id); - } - - @Override - public boolean isEnabled(@NonNull DeviceConfigBooleanFlag flag) { - int id = flag.getId(); - if (!mBooleanFlagCache.containsKey(id)) { - boolean deviceConfigValue = mDeviceConfigProxy.getBoolean(flag.getNamespace(), - flag.getName(), flag.getDefault()); - mBooleanFlagCache.put(id, readFlagValue(id, deviceConfigValue)); + readBooleanFlagInternal(flag, mResources.getBoolean(flag.getResourceId()))); } return mBooleanFlagCache.get(id); @@ -178,7 +163,7 @@ public class FeatureFlagsDebug implements FeatureFlags { id, mSystemProperties.getBoolean( flag.getName(), - readFlagValue(id, flag.getDefault()))); + readBooleanFlagInternal(flag, flag.getDefault()))); } return mBooleanFlagCache.get(id); @@ -190,7 +175,7 @@ public class FeatureFlagsDebug implements FeatureFlags { int id = flag.getId(); if (!mStringFlagCache.containsKey(id)) { mStringFlagCache.put(id, - readFlagValue(id, flag.getDefault(), StringFlagSerializer.INSTANCE)); + readFlagValueInternal(id, flag.getDefault(), StringFlagSerializer.INSTANCE)); } return mStringFlagCache.get(id); @@ -202,27 +187,57 @@ public class FeatureFlagsDebug implements FeatureFlags { int id = flag.getId(); if (!mStringFlagCache.containsKey(id)) { mStringFlagCache.put(id, - readFlagValue(id, mResources.getString(flag.getResourceId()), + readFlagValueInternal(id, mResources.getString(flag.getResourceId()), StringFlagSerializer.INSTANCE)); } return mStringFlagCache.get(id); } - /** Specific override for Boolean flags that checks against the teamfood list. */ - private boolean readFlagValue(int id, boolean defaultValue) { - Boolean result = readBooleanFlagOverride(id); - boolean hasServerOverride = mServerFlagReader.hasOverride(id); + + @NonNull + @Override + public int getInt(@NonNull IntFlag flag) { + int id = flag.getId(); + if (!mIntFlagCache.containsKey(id)) { + mIntFlagCache.put(id, + readFlagValueInternal(id, flag.getDefault(), IntFlagSerializer.INSTANCE)); + } + + return mIntFlagCache.get(id); + } + + @NonNull + @Override + public int getInt(@NonNull ResourceIntFlag flag) { + int id = flag.getId(); + if (!mIntFlagCache.containsKey(id)) { + mIntFlagCache.put(id, + readFlagValueInternal(id, mResources.getInteger(flag.getResourceId()), + IntFlagSerializer.INSTANCE)); + } + + return mIntFlagCache.get(id); + } + + /** Specific override for Boolean flags that checks against the teamfood list.*/ + private boolean readBooleanFlagInternal(Flag<Boolean> flag, boolean defaultValue) { + Boolean result = readBooleanFlagOverride(flag.getId()); + boolean hasServerOverride = mServerFlagReader.hasOverride( + flag.getNamespace(), flag.getName()); // Only check for teamfood if the default is false // and there is no server override. - if (!hasServerOverride && !defaultValue && result == null && id != Flags.TEAMFOOD.getId()) { - if (mAllFlags.containsKey(id) && mAllFlags.get(id).getTeamfood()) { - return isEnabled(Flags.TEAMFOOD); - } + if (!hasServerOverride + && !defaultValue + && result == null + && flag.getId() != Flags.TEAMFOOD.getId() + && flag.getTeamfood()) { + return isEnabled(Flags.TEAMFOOD); } - return result == null ? mServerFlagReader.readServerOverride(id, defaultValue) : result; + return result == null ? mServerFlagReader.readServerOverride( + flag.getNamespace(), flag.getName(), defaultValue) : result; } private Boolean readBooleanFlagOverride(int id) { @@ -230,7 +245,8 @@ public class FeatureFlagsDebug implements FeatureFlags { } @NonNull - private <T> T readFlagValue(int id, @NonNull T defaultValue, FlagSerializer<T> serializer) { + private <T> T readFlagValueInternal( + int id, @NonNull T defaultValue, FlagSerializer<T> serializer) { requireNonNull(defaultValue, "defaultValue"); T result = readFlagValueInternal(id, serializer); return result == null ? defaultValue : result; @@ -329,8 +345,6 @@ public class FeatureFlagsDebug implements FeatureFlags { setFlagValue(flag.getId(), value, BooleanFlagSerializer.INSTANCE); } else if (flag instanceof ResourceBooleanFlag) { setFlagValue(flag.getId(), value, BooleanFlagSerializer.INSTANCE); - } else if (flag instanceof DeviceConfigBooleanFlag) { - setFlagValue(flag.getId(), value, BooleanFlagSerializer.INSTANCE); } else if (flag instanceof SysPropBooleanFlag) { // Store SysProp flags in SystemProperties where they can read by outside parties. mSystemProperties.setBoolean(((SysPropBooleanFlag) flag).getName(), value); @@ -351,6 +365,16 @@ public class FeatureFlagsDebug implements FeatureFlags { } } + void setIntFlagInternal(Flag<?> flag, int value) { + if (flag instanceof IntFlag) { + setFlagValue(flag.getId(), value, IntFlagSerializer.INSTANCE); + } else if (flag instanceof ResourceIntFlag) { + setFlagValue(flag.getId(), value, IntFlagSerializer.INSTANCE); + } else { + throw new IllegalArgumentException("Unknown flag type"); + } + } + private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -438,9 +462,6 @@ public class FeatureFlagsDebug implements FeatureFlags { } else if (f instanceof ResourceBooleanFlag) { enabled = isEnabled((ResourceBooleanFlag) f); overridden = readBooleanFlagOverride(f.getId()) != null; - } else if (f instanceof DeviceConfigBooleanFlag) { - enabled = isEnabled((DeviceConfigBooleanFlag) f); - overridden = false; } else if (f instanceof SysPropBooleanFlag) { // TODO(b/223379190): Teamfood not supported for sysprop flags yet. enabled = isEnabled((SysPropBooleanFlag) f); @@ -453,9 +474,11 @@ public class FeatureFlagsDebug implements FeatureFlags { } if (enabled) { - return new ReleasedFlag(f.getId(), teamfood, overridden); + return new ReleasedFlag( + f.getId(), f.getName(), f.getNamespace(), teamfood, overridden); } else { - return new UnreleasedFlag(f.getId(), teamfood, overridden); + return new UnreleasedFlag( + f.getId(), f.getName(), f.getNamespace(), teamfood, overridden); } } }; diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsRelease.java b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsRelease.java index 30cad5faa2de..3c83682210b6 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsRelease.java +++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsRelease.java @@ -101,7 +101,7 @@ public class FeatureFlagsRelease implements FeatureFlags { @Override public boolean isEnabled(@NotNull ReleasedFlag flag) { - return mServerFlagReader.readServerOverride(flag.getId(), true); + return mServerFlagReader.readServerOverride(flag.getNamespace(), flag.getName(), true); } @Override @@ -115,18 +115,6 @@ public class FeatureFlagsRelease implements FeatureFlags { } @Override - public boolean isEnabled(@NonNull DeviceConfigBooleanFlag flag) { - int cacheIndex = mBooleanCache.indexOfKey(flag.getId()); - if (cacheIndex < 0) { - boolean deviceConfigValue = mDeviceConfigProxy.getBoolean(flag.getNamespace(), - flag.getName(), flag.getDefault()); - return isEnabled(flag.getId(), deviceConfigValue); - } - - return mBooleanCache.valueAt(cacheIndex); - } - - @Override public boolean isEnabled(SysPropBooleanFlag flag) { int cacheIndex = mBooleanCache.indexOfKey(flag.getId()); if (cacheIndex < 0) { @@ -165,13 +153,25 @@ public class FeatureFlagsRelease implements FeatureFlags { return defaultValue; } + @NonNull + @Override + public int getInt(@NonNull IntFlag flag) { + return flag.getDefault(); + } + + @NonNull + @Override + public int getInt(@NonNull ResourceIntFlag flag) { + return mResources.getInteger(flag.getResourceId()); + } + @Override public void dump(@NonNull PrintWriter pw, @NonNull String[] args) { pw.println("can override: false"); - Map<Integer, Flag<?>> knownFlags = Flags.collectFlags(); - for (Map.Entry<Integer, Flag<?>> idToFlag : knownFlags.entrySet()) { - int id = idToFlag.getKey(); - Flag<?> flag = idToFlag.getValue(); + Map<String, Flag<?>> knownFlags = FlagsFactory.INSTANCE.getKnownFlags(); + for (Map.Entry<String, Flag<?>> nameToFlag : knownFlags.entrySet()) { + Flag<?> flag = nameToFlag.getValue(); + int id = flag.getId(); boolean def = false; if (mBooleanCache.indexOfKey(flag.getId()) < 0) { if (flag instanceof SysPropBooleanFlag) { diff --git a/packages/SystemUI/src/com/android/systemui/flags/FlagCommand.java b/packages/SystemUI/src/com/android/systemui/flags/FlagCommand.java index 1e93c0b7002d..b7fc0e41ea69 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/FlagCommand.java +++ b/packages/SystemUI/src/com/android/systemui/flags/FlagCommand.java @@ -23,7 +23,6 @@ import androidx.annotation.NonNull; import com.android.systemui.statusbar.commandline.Command; import java.io.PrintWriter; -import java.lang.reflect.Field; import java.util.List; import java.util.Map; @@ -38,6 +37,7 @@ public class FlagCommand implements Command { private final List<String> mOnCommands = List.of("true", "on", "1", "enabled"); private final List<String> mOffCommands = List.of("false", "off", "0", "disable"); + private final List<String> mSetCommands = List.of("set", "put"); private final FeatureFlagsDebug mFeatureFlags; private final Map<Integer, Flag<?>> mAllFlags; @@ -60,12 +60,6 @@ public class FlagCommand implements Command { return; } - if (args.size() > 2) { - pw.println("Invalid number of arguments."); - help(pw); - return; - } - int id = 0; try { id = Integer.parseInt(args.get(0)); @@ -85,48 +79,113 @@ public class FlagCommand implements Command { Flag<?> flag = mAllFlags.get(id); String cmd = ""; - if (args.size() == 2) { + if (args.size() > 1) { cmd = args.get(1).toLowerCase(); } if ("erase".equals(cmd) || "reset".equals(cmd)) { + if (args.size() > 2) { + pw.println("Invalid number of arguments to reset a flag."); + help(pw); + return; + } + mFeatureFlags.eraseFlag(flag); return; } - boolean newValue = true; - if (args.size() == 1 || "toggle".equals(cmd)) { - boolean enabled = isBooleanFlagEnabled(flag); - - if (args.size() == 1) { - pw.println("Flag " + id + " is " + enabled); + boolean shouldSet = true; + if (args.size() == 1) { + shouldSet = false; + } + if (isBooleanFlag(flag)) { + if (args.size() > 2) { + pw.println("Invalid number of arguments for a boolean flag."); + help(pw); return; } - - newValue = !enabled; - } else { - newValue = mOnCommands.contains(cmd); - if (!newValue && !mOffCommands.contains(cmd)) { + boolean newValue = isBooleanFlagEnabled(flag); + if ("toggle".equals(cmd)) { + newValue = !newValue; + } else if (mOnCommands.contains(cmd)) { + newValue = true; + } else if (mOffCommands.contains(cmd)) { + newValue = false; + } else if (shouldSet) { pw.println("Invalid on/off argument supplied"); help(pw); return; } - } - pw.flush(); // Next command will restart sysui, so flush before we do so. - mFeatureFlags.setBooleanFlagInternal(flag, newValue); + pw.println("Flag " + id + " is " + newValue); + pw.flush(); // Next command will restart sysui, so flush before we do so. + if (shouldSet) { + mFeatureFlags.setBooleanFlagInternal(flag, newValue); + } + return; + + } else if (isStringFlag(flag)) { + if (shouldSet) { + if (args.size() != 3) { + pw.println("Invalid number of arguments a StringFlag."); + help(pw); + return; + } else if (!mSetCommands.contains(cmd)) { + pw.println("Unknown command: " + cmd); + help(pw); + return; + } + String value = args.get(2); + pw.println("Setting Flag " + id + " to " + value); + pw.flush(); // Next command will restart sysui, so flush before we do so. + mFeatureFlags.setStringFlagInternal(flag, args.get(2)); + } else { + pw.println("Flag " + id + " is " + getStringFlag(flag)); + } + return; + } else if (isIntFlag(flag)) { + if (shouldSet) { + if (args.size() != 3) { + pw.println("Invalid number of arguments for an IntFlag."); + help(pw); + return; + } else if (!mSetCommands.contains(cmd)) { + pw.println("Unknown command: " + cmd); + help(pw); + return; + } + int value = Integer.parseInt(args.get(2)); + pw.println("Setting Flag " + id + " to " + value); + pw.flush(); // Next command will restart sysui, so flush before we do so. + mFeatureFlags.setIntFlagInternal(flag, value); + } else { + pw.println("Flag " + id + " is " + getIntFlag(flag)); + } + return; + } } @Override public void help(PrintWriter pw) { - pw.println( - "Usage: adb shell cmd statusbar flag <id> " + pw.println("Usage: adb shell cmd statusbar flag <id> [options]"); + pw.println(); + pw.println(" Boolean Flag Options: " + "[true|false|1|0|on|off|enable|disable|toggle|erase|reset]"); + pw.println(" String Flag Options: [set|put \"<value>\"]"); + pw.println(" Int Flag Options: [set|put <value>]"); + pw.println(); pw.println("The id can either be a numeric integer or the corresponding field name"); pw.println( "If no argument is supplied after the id, the flags runtime value is output"); } + private boolean isBooleanFlag(Flag<?> flag) { + return (flag instanceof BooleanFlag) + || (flag instanceof ResourceBooleanFlag) + || (flag instanceof SysPropFlag) + || (flag instanceof DeviceConfigBooleanFlag); + } + private boolean isBooleanFlagEnabled(Flag<?> flag) { if (flag instanceof ReleasedFlag) { return mFeatureFlags.isEnabled((ReleasedFlag) flag); @@ -141,34 +200,51 @@ public class FlagCommand implements Command { return false; } - private int flagNameToId(String flagName) { - List<Field> fields = Flags.getFlagFields(); - for (Field field : fields) { - if (flagName.equals(field.getName())) { - return fieldToId(field); - } + private boolean isStringFlag(Flag<?> flag) { + return (flag instanceof StringFlag) || (flag instanceof ResourceStringFlag); + } + + private String getStringFlag(Flag<?> flag) { + if (flag instanceof StringFlag) { + return mFeatureFlags.getString((StringFlag) flag); + } else if (flag instanceof ResourceStringFlag) { + return mFeatureFlags.getString((ResourceStringFlag) flag); + } + + return ""; + } + + private boolean isIntFlag(Flag<?> flag) { + return (flag instanceof IntFlag) || (flag instanceof ResourceIntFlag); + } + + private int getIntFlag(Flag<?> flag) { + if (flag instanceof IntFlag) { + return mFeatureFlags.getInt((IntFlag) flag); + } else if (flag instanceof ResourceIntFlag) { + return mFeatureFlags.getInt((ResourceIntFlag) flag); } return 0; } - private int fieldToId(Field field) { - try { - Flag<?> flag = (Flag<?>) field.get(null); - return flag.getId(); - } catch (IllegalAccessException e) { - // no-op + private int flagNameToId(String flagName) { + Map<String, Flag<?>> flagFields = FlagsFactory.INSTANCE.getKnownFlags(); + for (String fieldName : flagFields.keySet()) { + if (flagName.equals(fieldName)) { + return flagFields.get(fieldName).getId(); + } } return 0; } private void printKnownFlags(PrintWriter pw) { - List<Field> fields = Flags.getFlagFields(); + Map<String, Flag<?>> fields = FlagsFactory.INSTANCE.getKnownFlags(); int longestFieldName = 0; - for (Field field : fields) { - longestFieldName = Math.max(longestFieldName, field.getName().length()); + for (String fieldName : fields.keySet()) { + longestFieldName = Math.max(longestFieldName, fieldName.length()); } pw.println("Known Flags:"); @@ -176,23 +252,32 @@ public class FlagCommand implements Command { for (int i = 0; i < longestFieldName - "Flag Name".length() + 1; i++) { pw.print(" "); } - pw.println("ID Enabled?"); + pw.println("ID Value"); for (int i = 0; i < longestFieldName; i++) { pw.print("="); } pw.println(" ==== ========"); - for (Field field : fields) { - int id = fieldToId(field); + for (String fieldName : fields.keySet()) { + Flag<?> flag = fields.get(fieldName); + int id = flag.getId(); if (id == 0 || !mAllFlags.containsKey(id)) { continue; } - pw.print(field.getName()); - int fieldWidth = field.getName().length(); + pw.print(fieldName); + int fieldWidth = fieldName.length(); for (int i = 0; i < longestFieldName - fieldWidth + 1; i++) { pw.print(" "); } pw.printf("%-4d ", id); - pw.println(isBooleanFlagEnabled(mAllFlags.get(id))); + if (isBooleanFlag(flag)) { + pw.println(isBooleanFlagEnabled(mAllFlags.get(id))); + } else if (isStringFlag(flag)) { + pw.println(getStringFlag(flag)); + } else if (isIntFlag(flag)) { + pw.println(getIntFlag(flag)); + } else { + pw.println("<unknown flag type>"); + } } } } diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt index 28378c93501b..99dfefa4fa41 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 The Android Open Source Project + * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,7 +18,10 @@ package com.android.systemui.flags import android.provider.DeviceConfig import com.android.internal.annotations.Keep import com.android.systemui.R -import java.lang.reflect.Field +import com.android.systemui.flags.FlagsFactory.releasedFlag +import com.android.systemui.flags.FlagsFactory.resourceBooleanFlag +import com.android.systemui.flags.FlagsFactory.sysPropBooleanFlag +import com.android.systemui.flags.FlagsFactory.unreleasedFlag /** * List of [Flag] objects for use in SystemUI. @@ -33,63 +36,80 @@ import java.lang.reflect.Field * See [FeatureFlagsDebug] for instructions on flipping the flags via adb. */ object Flags { - @JvmField val TEAMFOOD = UnreleasedFlag(1) + @JvmField val TEAMFOOD = unreleasedFlag(1, "teamfood") // 100 - notification // TODO(b/254512751): Tracking Bug - val NOTIFICATION_PIPELINE_DEVELOPER_LOGGING = UnreleasedFlag(103) + val NOTIFICATION_PIPELINE_DEVELOPER_LOGGING = + unreleasedFlag(103, "notification_pipeline_developer_logging") // TODO(b/254512732): Tracking Bug - @JvmField val NSSL_DEBUG_LINES = UnreleasedFlag(105) + @JvmField val NSSL_DEBUG_LINES = unreleasedFlag(105, "nssl_debug_lines") // TODO(b/254512505): Tracking Bug - @JvmField val NSSL_DEBUG_REMOVE_ANIMATION = UnreleasedFlag(106) + @JvmField val NSSL_DEBUG_REMOVE_ANIMATION = unreleasedFlag(106, "nssl_debug_remove_animation") // TODO(b/254512624): Tracking Bug @JvmField val NOTIFICATION_DRAG_TO_CONTENTS = - ResourceBooleanFlag(108, R.bool.config_notificationToContents) + resourceBooleanFlag( + 108, + R.bool.config_notificationToContents, + "notification_drag_to_contents" + ) // TODO(b/254512517): Tracking Bug - val FSI_REQUIRES_KEYGUARD = UnreleasedFlag(110, teamfood = true) + val FSI_REQUIRES_KEYGUARD = unreleasedFlag(110, "fsi_requires_keyguard", teamfood = true) // TODO(b/254512538): Tracking Bug - val INSTANT_VOICE_REPLY = UnreleasedFlag(111, teamfood = true) + val INSTANT_VOICE_REPLY = unreleasedFlag(111, "instant_voice_reply", teamfood = true) // TODO(b/254512425): Tracking Bug - val NOTIFICATION_MEMORY_MONITOR_ENABLED = UnreleasedFlag(112, teamfood = true) + val NOTIFICATION_MEMORY_MONITOR_ENABLED = + releasedFlag(112, "notification_memory_monitor_enabled") // TODO(b/254512731): Tracking Bug - @JvmField val NOTIFICATION_DISMISSAL_FADE = UnreleasedFlag(113, teamfood = true) - val STABILITY_INDEX_FIX = UnreleasedFlag(114, teamfood = true) - val SEMI_STABLE_SORT = UnreleasedFlag(115, teamfood = true) - @JvmField val NOTIFICATION_GROUP_CORNER = UnreleasedFlag(116, teamfood = true) - // next id: 117 + @JvmField + val NOTIFICATION_DISMISSAL_FADE = + unreleasedFlag(113, "notification_dismissal_fade", teamfood = true) + val STABILITY_INDEX_FIX = unreleasedFlag(114, "stability_index_fix", teamfood = true) + val SEMI_STABLE_SORT = unreleasedFlag(115, "semi_stable_sort", teamfood = true) + + @JvmField + val NOTIFICATION_GROUP_CORNER = + unreleasedFlag(116, "notification_group_corner", teamfood = true) + + // TODO(b/257506350): Tracking Bug + val FSI_CHROME = unreleasedFlag(117, "fsi_chrome") + + // next id: 118 // 200 - keyguard/lockscreen // ** Flag retired ** // public static final BooleanFlag KEYGUARD_LAYOUT = // new BooleanFlag(200, true); // TODO(b/254512713): Tracking Bug - @JvmField val LOCKSCREEN_ANIMATIONS = ReleasedFlag(201) + @JvmField val LOCKSCREEN_ANIMATIONS = releasedFlag(201, "lockscreen_animations") // TODO(b/254512750): Tracking Bug - val NEW_UNLOCK_SWIPE_ANIMATION = ReleasedFlag(202) - val CHARGING_RIPPLE = ResourceBooleanFlag(203, R.bool.flag_charging_ripple) + val NEW_UNLOCK_SWIPE_ANIMATION = releasedFlag(202, "new_unlock_swipe_animation") + val CHARGING_RIPPLE = resourceBooleanFlag(203, R.bool.flag_charging_ripple, "charging_ripple") // TODO(b/254512281): Tracking Bug @JvmField - val BOUNCER_USER_SWITCHER = ResourceBooleanFlag(204, R.bool.config_enableBouncerUserSwitcher) + val BOUNCER_USER_SWITCHER = + resourceBooleanFlag(204, R.bool.config_enableBouncerUserSwitcher, "bouncer_user_switcher") // TODO(b/254512676): Tracking Bug - @JvmField val LOCKSCREEN_CUSTOM_CLOCKS = UnreleasedFlag(207, teamfood = true) + @JvmField + val LOCKSCREEN_CUSTOM_CLOCKS = unreleasedFlag(207, "lockscreen_custom_clocks", teamfood = true) /** * Flag to enable the usage of the new bouncer data source. This is a refactor of and eventual * replacement of KeyguardBouncer.java. */ // TODO(b/254512385): Tracking Bug - @JvmField val MODERN_BOUNCER = UnreleasedFlag(208) + @JvmField val MODERN_BOUNCER = releasedFlag(208, "modern_bouncer") /** * Whether the user interactor and repository should use `UserSwitcherController`. @@ -98,7 +118,8 @@ object Flags { * framework APIs. */ // TODO(b/254513286): Tracking Bug - val USER_INTERACTOR_AND_REPO_USE_CONTROLLER = UnreleasedFlag(210) + val USER_INTERACTOR_AND_REPO_USE_CONTROLLER = + unreleasedFlag(210, "user_interactor_and_repo_use_controller") /** * Whether `UserSwitcherController` should use the user interactor. @@ -110,20 +131,24 @@ object Flags { * would created a cycle between controller -> interactor -> controller. */ // TODO(b/254513102): Tracking Bug - val USER_CONTROLLER_USES_INTERACTOR = ReleasedFlag(211) + val USER_CONTROLLER_USES_INTERACTOR = releasedFlag(211, "user_controller_uses_interactor") /** * Whether the clock on a wide lock screen should use the new "stepping" animation for moving * the digits when the clock moves. */ - @JvmField val STEP_CLOCK_ANIMATION = UnreleasedFlag(212) + @JvmField val STEP_CLOCK_ANIMATION = unreleasedFlag(212, "step_clock_animation") /** * Migration from the legacy isDozing/dozeAmount paths to the new KeyguardTransitionRepository * will occur in stages. This is one stage of many to come. */ // TODO(b/255607168): Tracking Bug - @JvmField val DOZING_MIGRATION_1 = UnreleasedFlag(213) + @JvmField val DOZING_MIGRATION_1 = unreleasedFlag(213, "dozing_migration_1") + + @JvmField val NEW_ELLIPSE_DETECTION = unreleasedFlag(214, "new_ellipse_detection") + + @JvmField val NEW_UDFPS_OVERLAY = unreleasedFlag(215, "new_udfps_overlay") /** * Whether to enable the code powering customizable lock screen quick affordances. @@ -131,243 +156,256 @@ object Flags { * Note that this flag does not enable individual implementations of quick affordances like the * new camera quick affordance. Look for individual flags for those. */ - @JvmField val CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES = UnreleasedFlag(214, teamfood = false) + @JvmField + val CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES = + unreleasedFlag(216, "customizable_lock_screen_quick_affordances", teamfood = false) // 300 - power menu // TODO(b/254512600): Tracking Bug - @JvmField val POWER_MENU_LITE = ReleasedFlag(300) + @JvmField val POWER_MENU_LITE = releasedFlag(300, "power_menu_lite") // 400 - smartspace // TODO(b/254513100): Tracking Bug - val SMARTSPACE_SHARED_ELEMENT_TRANSITION_ENABLED = ReleasedFlag(401) - val SMARTSPACE = ResourceBooleanFlag(402, R.bool.flag_smartspace) + val SMARTSPACE_SHARED_ELEMENT_TRANSITION_ENABLED = + releasedFlag(401, "smartspace_shared_element_transition_enabled") + val SMARTSPACE = resourceBooleanFlag(402, R.bool.flag_smartspace, "smartspace") // 500 - quick settings - @Deprecated("Not needed anymore") val NEW_USER_SWITCHER = ReleasedFlag(500) // TODO(b/254512321): Tracking Bug - @JvmField val COMBINED_QS_HEADERS = UnreleasedFlag(501, teamfood = true) - val PEOPLE_TILE = ResourceBooleanFlag(502, R.bool.flag_conversations) + @JvmField val COMBINED_QS_HEADERS = releasedFlag(501, "combined_qs_headers") + val PEOPLE_TILE = resourceBooleanFlag(502, R.bool.flag_conversations, "people_tile") + @JvmField val QS_USER_DETAIL_SHORTCUT = - ResourceBooleanFlag(503, R.bool.flag_lockscreen_qs_user_detail_shortcut) - - // TODO(b/254512699): Tracking Bug - @Deprecated("Not needed anymore") val NEW_FOOTER = ReleasedFlag(504) + resourceBooleanFlag( + 503, + R.bool.flag_lockscreen_qs_user_detail_shortcut, + "qs_user_detail_shortcut" + ) // TODO(b/254512747): Tracking Bug - val NEW_HEADER = UnreleasedFlag(505, teamfood = true) + val NEW_HEADER = releasedFlag(505, "new_header") // TODO(b/254512383): Tracking Bug @JvmField val FULL_SCREEN_USER_SWITCHER = - ResourceBooleanFlag(506, R.bool.config_enableFullscreenUserSwitcher) + resourceBooleanFlag( + 506, + R.bool.config_enableFullscreenUserSwitcher, + "full_screen_user_switcher" + ) // TODO(b/254512678): Tracking Bug - @JvmField val NEW_FOOTER_ACTIONS = ReleasedFlag(507) + @JvmField val NEW_FOOTER_ACTIONS = releasedFlag(507, "new_footer_actions") + + // TODO(b/244064524): Tracking Bug + @JvmField + val QS_SECONDARY_DATA_SUB_INFO = + unreleasedFlag(508, "qs_secondary_data_sub_info", teamfood = true) // 600- status bar // TODO(b/254513246): Tracking Bug - val STATUS_BAR_USER_SWITCHER = ResourceBooleanFlag(602, R.bool.flag_user_switcher_chip) + val STATUS_BAR_USER_SWITCHER = + resourceBooleanFlag(602, R.bool.flag_user_switcher_chip, "status_bar_user_switcher") // TODO(b/254512623): Tracking Bug @Deprecated("Replaced by mobile and wifi specific flags.") - val NEW_STATUS_BAR_PIPELINE_BACKEND = UnreleasedFlag(604, teamfood = false) + val NEW_STATUS_BAR_PIPELINE_BACKEND = + unreleasedFlag(604, "new_status_bar_pipeline_backend", teamfood = false) // TODO(b/254512660): Tracking Bug @Deprecated("Replaced by mobile and wifi specific flags.") - val NEW_STATUS_BAR_PIPELINE_FRONTEND = UnreleasedFlag(605, teamfood = false) + val NEW_STATUS_BAR_PIPELINE_FRONTEND = + unreleasedFlag(605, "new_status_bar_pipeline_frontend", teamfood = false) + + // TODO(b/256614753): Tracking Bug + val NEW_STATUS_BAR_MOBILE_ICONS = unreleasedFlag(606, "new_status_bar_mobile_icons") - val NEW_STATUS_BAR_MOBILE_ICONS = UnreleasedFlag(606) + // TODO(b/256614210): Tracking Bug + val NEW_STATUS_BAR_WIFI_ICON = unreleasedFlag(607, "new_status_bar_wifi_icon") - val NEW_STATUS_BAR_WIFI_ICON = UnreleasedFlag(607) + // TODO(b/256614751): Tracking Bug + val NEW_STATUS_BAR_MOBILE_ICONS_BACKEND = + unreleasedFlag(608, "new_status_bar_mobile_icons_backend") + + // TODO(b/256613548): Tracking Bug + val NEW_STATUS_BAR_WIFI_ICON_BACKEND = unreleasedFlag(609, "new_status_bar_wifi_icon_backend") // 700 - dialer/calls // TODO(b/254512734): Tracking Bug - val ONGOING_CALL_STATUS_BAR_CHIP = ReleasedFlag(700) + val ONGOING_CALL_STATUS_BAR_CHIP = releasedFlag(700, "ongoing_call_status_bar_chip") // TODO(b/254512681): Tracking Bug - val ONGOING_CALL_IN_IMMERSIVE = ReleasedFlag(701) + val ONGOING_CALL_IN_IMMERSIVE = releasedFlag(701, "ongoing_call_in_immersive") // TODO(b/254512753): Tracking Bug - val ONGOING_CALL_IN_IMMERSIVE_CHIP_TAP = ReleasedFlag(702) + val ONGOING_CALL_IN_IMMERSIVE_CHIP_TAP = releasedFlag(702, "ongoing_call_in_immersive_chip_tap") // 800 - general visual/theme - @JvmField val MONET = ResourceBooleanFlag(800, R.bool.flag_monet) + @JvmField val MONET = resourceBooleanFlag(800, R.bool.flag_monet, "monet") // 801 - region sampling // TODO(b/254512848): Tracking Bug - val REGION_SAMPLING = UnreleasedFlag(801) + val REGION_SAMPLING = unreleasedFlag(801, "region_sampling") // 802 - wallpaper rendering // TODO(b/254512923): Tracking Bug - @JvmField val USE_CANVAS_RENDERER = UnreleasedFlag(802, teamfood = true) + @JvmField val USE_CANVAS_RENDERER = unreleasedFlag(802, "use_canvas_renderer") // 803 - screen contents translation // TODO(b/254513187): Tracking Bug - val SCREEN_CONTENTS_TRANSLATION = UnreleasedFlag(803) + val SCREEN_CONTENTS_TRANSLATION = unreleasedFlag(803, "screen_contents_translation") // 804 - monochromatic themes - @JvmField val MONOCHROMATIC_THEMES = UnreleasedFlag(804) + @JvmField + val MONOCHROMATIC_THEMES = + sysPropBooleanFlag(804, "persist.sysui.monochromatic", default = false) // 900 - media // TODO(b/254512697): Tracking Bug - val MEDIA_TAP_TO_TRANSFER = ReleasedFlag(900) + val MEDIA_TAP_TO_TRANSFER = releasedFlag(900, "media_tap_to_transfer") // TODO(b/254512502): Tracking Bug - val MEDIA_SESSION_ACTIONS = UnreleasedFlag(901) + val MEDIA_SESSION_ACTIONS = unreleasedFlag(901, "media_session_actions") // TODO(b/254512726): Tracking Bug - val MEDIA_NEARBY_DEVICES = ReleasedFlag(903) + val MEDIA_NEARBY_DEVICES = releasedFlag(903, "media_nearby_devices") // TODO(b/254512695): Tracking Bug - val MEDIA_MUTE_AWAIT = ReleasedFlag(904) + val MEDIA_MUTE_AWAIT = releasedFlag(904, "media_mute_await") // TODO(b/254512654): Tracking Bug - @JvmField val DREAM_MEDIA_COMPLICATION = UnreleasedFlag(905) + @JvmField val DREAM_MEDIA_COMPLICATION = unreleasedFlag(905, "dream_media_complication") // TODO(b/254512673): Tracking Bug - @JvmField val DREAM_MEDIA_TAP_TO_OPEN = UnreleasedFlag(906) + @JvmField val DREAM_MEDIA_TAP_TO_OPEN = unreleasedFlag(906, "dream_media_tap_to_open") // TODO(b/254513168): Tracking Bug - @JvmField val UMO_SURFACE_RIPPLE = UnreleasedFlag(907) + @JvmField val UMO_SURFACE_RIPPLE = unreleasedFlag(907, "umo_surface_ripple") // 1000 - dock - val SIMULATE_DOCK_THROUGH_CHARGING = ReleasedFlag(1000) + val SIMULATE_DOCK_THROUGH_CHARGING = releasedFlag(1000, "simulate_dock_through_charging") // TODO(b/254512758): Tracking Bug - @JvmField val ROUNDED_BOX_RIPPLE = ReleasedFlag(1002) + @JvmField val ROUNDED_BOX_RIPPLE = releasedFlag(1002, "rounded_box_ripple") // 1100 - windowing - @JvmField @Keep - val WM_ENABLE_SHELL_TRANSITIONS = - SysPropBooleanFlag(1100, "persist.wm.debug.shell_transit", false) - - /** b/170163464: animate bubbles expanded view collapse with home gesture */ @JvmField - @Keep - val BUBBLES_HOME_GESTURE = - SysPropBooleanFlag(1101, "persist.wm.debug.bubbles_home_gesture", true) + val WM_ENABLE_SHELL_TRANSITIONS = + sysPropBooleanFlag(1100, "persist.wm.debug.shell_transit", default = false) // TODO(b/254513207): Tracking Bug - @JvmField @Keep + @JvmField val WM_ENABLE_PARTIAL_SCREEN_SHARING = - DeviceConfigBooleanFlag( + unreleasedFlag( 1102, - "record_task_content", - DeviceConfig.NAMESPACE_WINDOW_MANAGER, - false, + name = "record_task_content", + namespace = DeviceConfig.NAMESPACE_WINDOW_MANAGER, teamfood = true ) // TODO(b/254512674): Tracking Bug - @JvmField @Keep - val HIDE_NAVBAR_WINDOW = SysPropBooleanFlag(1103, "persist.wm.debug.hide_navbar_window", false) - @JvmField - @Keep - val WM_DESKTOP_WINDOWING = SysPropBooleanFlag(1104, "persist.wm.debug.desktop_mode", false) + val HIDE_NAVBAR_WINDOW = + sysPropBooleanFlag(1103, "persist.wm.debug.hide_navbar_window", default = false) - @JvmField @Keep - val WM_CAPTION_ON_SHELL = SysPropBooleanFlag(1105, "persist.wm.debug.caption_on_shell", false) - @JvmField - @Keep - val FLOATING_TASKS_ENABLED = SysPropBooleanFlag(1106, "persist.wm.debug.floating_tasks", false) + val WM_DESKTOP_WINDOWING = + sysPropBooleanFlag(1104, "persist.wm.debug.desktop_mode", default = false) - @JvmField @Keep - val SHOW_FLOATING_TASKS_AS_BUBBLES = - SysPropBooleanFlag(1107, "persist.wm.debug.floating_tasks_as_bubbles", false) - @JvmField + val WM_CAPTION_ON_SHELL = + sysPropBooleanFlag(1105, "persist.wm.debug.caption_on_shell", default = false) + @Keep + @JvmField val ENABLE_FLING_TO_DISMISS_BUBBLE = - SysPropBooleanFlag(1108, "persist.wm.debug.fling_to_dismiss_bubble", true) + sysPropBooleanFlag(1108, "persist.wm.debug.fling_to_dismiss_bubble", default = true) - @JvmField @Keep + @JvmField val ENABLE_FLING_TO_DISMISS_PIP = - SysPropBooleanFlag(1109, "persist.wm.debug.fling_to_dismiss_pip", true) + sysPropBooleanFlag(1109, "persist.wm.debug.fling_to_dismiss_pip", default = true) - @JvmField @Keep + @JvmField val ENABLE_PIP_KEEP_CLEAR_ALGORITHM = - SysPropBooleanFlag(1110, "persist.wm.debug.enable_pip_keep_clear_algorithm", false) + sysPropBooleanFlag( + 1110, + "persist.wm.debug.enable_pip_keep_clear_algorithm", + default = false + ) + + // TODO(b/256873975): Tracking Bug + @JvmField @Keep val WM_BUBBLE_BAR = unreleasedFlag(1111, "wm_bubble_bar") // 1200 - predictive back - @JvmField @Keep + @JvmField val WM_ENABLE_PREDICTIVE_BACK = - SysPropBooleanFlag(1200, "persist.wm.debug.predictive_back", true) + sysPropBooleanFlag(1200, "persist.wm.debug.predictive_back", default = true) - @JvmField @Keep + @JvmField val WM_ENABLE_PREDICTIVE_BACK_ANIM = - SysPropBooleanFlag(1201, "persist.wm.debug.predictive_back_anim", false) + sysPropBooleanFlag(1201, "persist.wm.debug.predictive_back_anim", default = false) - @JvmField @Keep + @JvmField val WM_ALWAYS_ENFORCE_PREDICTIVE_BACK = - SysPropBooleanFlag(1202, "persist.wm.debug.predictive_back_always_enforce", false) + sysPropBooleanFlag(1202, "persist.wm.debug.predictive_back_always_enforce", default = false) // TODO(b/254512728): Tracking Bug - @JvmField val NEW_BACK_AFFORDANCE = UnreleasedFlag(1203, teamfood = false) + @JvmField + val NEW_BACK_AFFORDANCE = unreleasedFlag(1203, "new_back_affordance", teamfood = false) // 1300 - screenshots // TODO(b/254512719): Tracking Bug - @JvmField val SCREENSHOT_REQUEST_PROCESSOR = UnreleasedFlag(1300, true) + @JvmField + val SCREENSHOT_REQUEST_PROCESSOR = + unreleasedFlag(1300, "screenshot_request_processor", teamfood = true) // TODO(b/254513155): Tracking Bug - @JvmField val SCREENSHOT_WORK_PROFILE_POLICY = UnreleasedFlag(1301) + @JvmField + val SCREENSHOT_WORK_PROFILE_POLICY = unreleasedFlag(1301, "screenshot_work_profile_policy") // 1400 - columbus // TODO(b/254512756): Tracking Bug - val QUICK_TAP_IN_PCC = ReleasedFlag(1400) + val QUICK_TAP_IN_PCC = releasedFlag(1400, "quick_tap_in_pcc") // 1500 - chooser // TODO(b/254512507): Tracking Bug - val CHOOSER_UNBUNDLED = UnreleasedFlag(1500, teamfood = true) + val CHOOSER_UNBUNDLED = unreleasedFlag(1500, "chooser_unbundled", teamfood = true) + + // 1600 - accessibility + @JvmField + val A11Y_FLOATING_MENU_FLING_SPRING_ANIMATIONS = + unreleasedFlag(1600, "a11y_floating_menu_fling_spring_animations") // 1700 - clipboard - @JvmField val CLIPBOARD_OVERLAY_REFACTOR = UnreleasedFlag(1700, true) - @JvmField val CLIPBOARD_REMOTE_BEHAVIOR = UnreleasedFlag(1701) + @JvmField + val CLIPBOARD_OVERLAY_REFACTOR = + unreleasedFlag(1700, "clipboard_overlay_refactor", teamfood = true) + @JvmField val CLIPBOARD_REMOTE_BEHAVIOR = unreleasedFlag(1701, "clipboard_remote_behavior") // 1800 - shade container - @JvmField val LEAVE_SHADE_OPEN_FOR_BUGREPORT = UnreleasedFlag(1800, teamfood = true) + @JvmField + val LEAVE_SHADE_OPEN_FOR_BUGREPORT = + unreleasedFlag(1800, "leave_shade_open_for_bugreport", teamfood = true) // 1900 - note task - @JvmField val NOTE_TASKS = SysPropBooleanFlag(1900, "persist.sysui.debug.note_tasks") - - // Pay no attention to the reflection behind the curtain. - // ========================== Curtain ========================== - // | | - // | . . . . . . . . . . . . . . . . . . . | - @JvmStatic - fun collectFlags(): Map<Int, Flag<*>> { - return flagFields - .map { field -> - // field[null] returns the current value of the field. - // See java.lang.Field#get - val flag = field[null] as Flag<*> - flag.id to flag - } - .toMap() - } - - // | . . . . . . . . . . . . . . . . . . . | - @JvmStatic - val flagFields: List<Field> - get() { - return Flags::class.java.fields.filter { f -> - Flag::class.java.isAssignableFrom(f.type) - } - } - // | | - // \_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/ + @JvmField val NOTE_TASKS = sysPropBooleanFlag(1900, "persist.sysui.debug.note_tasks") + + // 2000 - device controls + @Keep @JvmField val USE_APP_PANELS = unreleasedFlag(2000, "use_app_panels", teamfood = true) + + // 2100 - Falsing Manager + @JvmField val FALSING_FOR_LONG_TAPS = releasedFlag(2100, "falsing_for_long_taps") } diff --git a/packages/SystemUI/src/com/android/systemui/flags/FlagsCommonModule.kt b/packages/SystemUI/src/com/android/systemui/flags/FlagsCommonModule.kt index e1f4944741a0..18d7bcf9b3fc 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/FlagsCommonModule.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/FlagsCommonModule.kt @@ -30,7 +30,7 @@ interface FlagsCommonModule { @Provides @Named(ALL_FLAGS) fun providesAllFlags(): Map<Int, Flag<*>> { - return Flags.collectFlags() + return FlagsFactory.knownFlags.map { it.value.id to it.value }.toMap() } @JvmStatic diff --git a/packages/SystemUI/src/com/android/systemui/flags/OWNERS b/packages/SystemUI/src/com/android/systemui/flags/OWNERS new file mode 100644 index 000000000000..c9d2db1d8acb --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/flags/OWNERS @@ -0,0 +1,12 @@ +set noparent + +# Bug component: 1203176 + +mankoff@google.com # send reviews here + +pixel@google.com +juliacr@google.com +cinek@google.com +alexflo@google.com +dsandler@android.com +adamcohen@google.com diff --git a/packages/SystemUI/src/com/android/systemui/flags/ServerFlagReader.kt b/packages/SystemUI/src/com/android/systemui/flags/ServerFlagReader.kt index 694fa01bb4a5..ae05c4656349 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/ServerFlagReader.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/ServerFlagReader.kt @@ -27,11 +27,10 @@ import javax.inject.Inject interface ServerFlagReader { /** Returns true if there is a server-side setting stored. */ - fun hasOverride(flagId: Int): Boolean + fun hasOverride(namespace: String, name: String): Boolean /** Returns any stored server-side setting or the default if not set. */ - fun readServerOverride(flagId: Int, default: Boolean): Boolean - + fun readServerOverride(namespace: String, name: String, default: Boolean): Boolean /** Register a listener for changes to any of the passed in flags. */ fun listenForChanges(values: Collection<Flag<*>>, listener: ChangeListener) @@ -68,19 +67,19 @@ class ServerFlagReaderImpl @Inject constructor( } } - override fun hasOverride(flagId: Int): Boolean = - deviceConfig.getProperty( + override fun hasOverride(namespace: String, name: String): Boolean = + !namespace.isBlank() && !name.isBlank() && deviceConfig.getProperty( namespace, - getServerOverrideName(flagId) + name ) != null - override fun readServerOverride(flagId: Int, default: Boolean): Boolean { - return deviceConfig.getBoolean( + + override fun readServerOverride(namespace: String, name: String, default: Boolean): Boolean = + !namespace.isBlank() && !name.isBlank() && deviceConfig.getBoolean( namespace, - getServerOverrideName(flagId), + name, default ) - } override fun listenForChanges( flags: Collection<Flag<*>>, @@ -121,24 +120,24 @@ interface ServerFlagReaderModule { } class ServerFlagReaderFake : ServerFlagReader { - private val flagMap: MutableMap<Int, Boolean> = mutableMapOf() + private val flagMap: MutableMap<String, Boolean> = mutableMapOf() private val listeners = mutableListOf<Pair<ServerFlagReader.ChangeListener, Collection<Flag<*>>>>() - override fun hasOverride(flagId: Int): Boolean { - return flagMap.containsKey(flagId) + override fun hasOverride(namespace: String, name: String): Boolean { + return flagMap.containsKey(name) } - override fun readServerOverride(flagId: Int, default: Boolean): Boolean { - return flagMap.getOrDefault(flagId, default) + override fun readServerOverride(namespace: String, name: String, default: Boolean): Boolean { + return flagMap.getOrDefault(name, default) } - fun setFlagValue(flagId: Int, value: Boolean) { - flagMap.put(flagId, value) + fun setFlagValue(namespace: String, name: String, value: Boolean) { + flagMap.put(name, value) for ((listener, flags) in listeners) { flagLoop@ for (flag in flags) { - if (flagId == flag.id) { + if (name == flag.name) { listener.onChange() break@flagLoop } @@ -146,8 +145,8 @@ class ServerFlagReaderFake : ServerFlagReader { } } - fun eraseFlag(flagId: Int) { - flagMap.remove(flagId) + fun eraseFlag(namespace: String, name: String) { + flagMap.remove(name) } override fun listenForChanges( diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 6f1ad703b526..7cd3843fd506 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -125,6 +125,7 @@ import com.android.systemui.keyguard.dagger.KeyguardModule; import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.shade.NotificationPanelViewController; +import com.android.systemui.shade.ShadeController; import com.android.systemui.shade.ShadeExpansionStateManager; import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.statusbar.CommandQueue; @@ -266,6 +267,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, private final Executor mUiBgExecutor; private final ScreenOffAnimationController mScreenOffAnimationController; private final Lazy<NotificationShadeDepthController> mNotificationShadeDepthController; + private final Lazy<ShadeController> mShadeController; private boolean mSystemReady; private boolean mBootCompleted; @@ -1149,6 +1151,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, ScreenOnCoordinator screenOnCoordinator, InteractionJankMonitor interactionJankMonitor, DreamOverlayStateController dreamOverlayStateController, + Lazy<ShadeController> shadeControllerLazy, Lazy<NotificationShadeWindowController> notificationShadeWindowControllerLazy, Lazy<ActivityLaunchAnimator> activityLaunchAnimator) { mContext = context; @@ -1164,6 +1167,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, mTrustManager = trustManager; mUserSwitcherController = userSwitcherController; mKeyguardDisplayManager = keyguardDisplayManager; + mShadeController = shadeControllerLazy; dumpManager.registerDumpable(getClass().getName(), this); mDeviceConfig = deviceConfig; mScreenOnCoordinator = screenOnCoordinator; diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java index 546a4093ec7d..450fa1420408 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java @@ -33,6 +33,8 @@ import android.os.Bundle; import android.os.UserHandle; import android.os.UserManager; import android.widget.ImageView; +import android.window.OnBackInvokedCallback; +import android.window.OnBackInvokedDispatcher; import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.R; @@ -61,6 +63,7 @@ public class WorkLockActivity extends Activity { private UserManager mUserManager; private PackageManager mPackageManager; private final BroadcastDispatcher mBroadcastDispatcher; + private final OnBackInvokedCallback mBackCallback = this::onBackInvoked; @Inject public WorkLockActivity(BroadcastDispatcher broadcastDispatcher, UserManager userManager, @@ -95,6 +98,10 @@ public class WorkLockActivity extends Activity { if (badgedIcon != null) { ((ImageView) findViewById(R.id.icon)).setImageDrawable(badgedIcon); } + + getOnBackInvokedDispatcher().registerOnBackInvokedCallback( + OnBackInvokedDispatcher.PRIORITY_DEFAULT, + mBackCallback); } @VisibleForTesting @@ -134,11 +141,16 @@ public class WorkLockActivity extends Activity { @Override public void onDestroy() { unregisterBroadcastReceiver(); + getOnBackInvokedDispatcher().unregisterOnBackInvokedCallback(mBackCallback); super.onDestroy(); } @Override public void onBackPressed() { + onBackInvoked(); + } + + private void onBackInvoked() { // Ignore back presses. } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java index f08463bfd5e9..78a7c9e35eb7 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java @@ -47,6 +47,7 @@ import com.android.systemui.keyguard.data.repository.KeyguardRepositoryModule; import com.android.systemui.keyguard.domain.interactor.StartKeyguardTransitionModule; import com.android.systemui.keyguard.domain.quickaffordance.KeyguardQuickAffordanceModule; import com.android.systemui.navigationbar.NavigationModeController; +import com.android.systemui.shade.ShadeController; import com.android.systemui.statusbar.NotificationShadeDepthController; import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.SysuiStatusBarStateController; @@ -108,6 +109,7 @@ public class KeyguardModule { ScreenOnCoordinator screenOnCoordinator, InteractionJankMonitor interactionJankMonitor, DreamOverlayStateController dreamOverlayStateController, + Lazy<ShadeController> shadeController, Lazy<NotificationShadeWindowController> notificationShadeWindowController, Lazy<ActivityLaunchAnimator> activityLaunchAnimator) { return new KeyguardViewMediator( @@ -135,6 +137,7 @@ public class KeyguardModule { screenOnCoordinator, interactionJankMonitor, dreamOverlayStateController, + shadeController, notificationShadeWindowController, activityLaunchAnimator); } 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 0046256c677b..d4514c5cb7aa 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 @@ -28,7 +28,7 @@ import javax.inject.Inject import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow -/** Encapsulates app state for the lock screen bouncer. */ +/** Encapsulates app state for the lock screen primary and alternate bouncer. */ @SysUISingleton class KeyguardBouncerRepository @Inject @@ -36,12 +36,24 @@ constructor( private val viewMediatorCallback: ViewMediatorCallback, keyguardUpdateMonitor: KeyguardUpdateMonitor, ) { - var bouncerPromptReason: Int? = null - /** Determines if we want to instantaneously show the bouncer instead of translating. */ - private val _isScrimmed = MutableStateFlow(false) - val isScrimmed = _isScrimmed.asStateFlow() + /** Values associated with the PrimaryBouncer (pin/pattern/password) input. */ + private val _primaryBouncerVisible = MutableStateFlow(false) + val primaryBouncerVisible = _primaryBouncerVisible.asStateFlow() + private val _primaryBouncerShow = MutableStateFlow<KeyguardBouncerModel?>(null) + val primaryBouncerShow = _primaryBouncerShow.asStateFlow() + private val _primaryBouncerShowingSoon = MutableStateFlow(false) + val primaryBouncerShowingSoon = _primaryBouncerShowingSoon.asStateFlow() + private val _primaryBouncerHide = MutableStateFlow(false) + val primaryBouncerHide = _primaryBouncerHide.asStateFlow() + private val _primaryBouncerStartingToHide = MutableStateFlow(false) + val primaryBouncerStartingToHide = _primaryBouncerStartingToHide.asStateFlow() + private val _primaryBouncerDisappearAnimation = MutableStateFlow<Runnable?>(null) + val primaryBouncerStartingDisappearAnimation = _primaryBouncerDisappearAnimation.asStateFlow() + /** Determines if we want to instantaneously show the primary bouncer instead of translating. */ + private val _primaryBouncerScrimmed = MutableStateFlow(false) + val primaryBouncerScrimmed = _primaryBouncerScrimmed.asStateFlow() /** - * Set how much of the panel is showing on the screen. + * 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 @@ -49,31 +61,21 @@ constructor( */ private val _panelExpansionAmount = MutableStateFlow(KeyguardBouncer.EXPANSION_HIDDEN) val panelExpansionAmount = _panelExpansionAmount.asStateFlow() - private val _isVisible = MutableStateFlow(false) - val isVisible = _isVisible.asStateFlow() - private val _show = MutableStateFlow<KeyguardBouncerModel?>(null) - val show = _show.asStateFlow() - private val _showingSoon = MutableStateFlow(false) - val showingSoon = _showingSoon.asStateFlow() - private val _hide = MutableStateFlow(false) - val hide = _hide.asStateFlow() - private val _startingToHide = MutableStateFlow(false) - val startingToHide = _startingToHide.asStateFlow() - private val _disappearAnimation = MutableStateFlow<Runnable?>(null) - val startingDisappearAnimation = _disappearAnimation.asStateFlow() private val _keyguardPosition = MutableStateFlow(0f) val keyguardPosition = _keyguardPosition.asStateFlow() - private val _resourceUpdateRequests = MutableStateFlow(false) - val resourceUpdateRequests = _resourceUpdateRequests.asStateFlow() - private val _showMessage = MutableStateFlow<BouncerShowMessageModel?>(null) - val showMessage = _showMessage.asStateFlow() + private val _onScreenTurnedOff = MutableStateFlow(false) + val onScreenTurnedOff = _onScreenTurnedOff.asStateFlow() + private val _isBackButtonEnabled = MutableStateFlow<Boolean?>(null) + val isBackButtonEnabled = _isBackButtonEnabled.asStateFlow() private val _keyguardAuthenticated = MutableStateFlow<Boolean?>(null) /** Determines if user is already unlocked */ val keyguardAuthenticated = _keyguardAuthenticated.asStateFlow() - private val _isBackButtonEnabled = MutableStateFlow<Boolean?>(null) - val isBackButtonEnabled = _isBackButtonEnabled.asStateFlow() - private val _onScreenTurnedOff = MutableStateFlow(false) - val onScreenTurnedOff = _onScreenTurnedOff.asStateFlow() + + var bouncerPromptReason: Int? = null + private val _showMessage = MutableStateFlow<BouncerShowMessageModel?>(null) + val showMessage = _showMessage.asStateFlow() + private val _resourceUpdateRequests = MutableStateFlow(false) + val resourceUpdateRequests = _resourceUpdateRequests.asStateFlow() val bouncerErrorMessage: CharSequence? get() = viewMediatorCallback.consumeCustomMessage() @@ -95,36 +97,36 @@ constructor( keyguardUpdateMonitor.registerCallback(callback) } - fun setScrimmed(isScrimmed: Boolean) { - _isScrimmed.value = isScrimmed + fun setPrimaryScrimmed(isScrimmed: Boolean) { + _primaryBouncerScrimmed.value = isScrimmed } - fun setPanelExpansion(panelExpansion: Float) { - _panelExpansionAmount.value = panelExpansion + fun setPrimaryVisible(isVisible: Boolean) { + _primaryBouncerVisible.value = isVisible } - fun setVisible(isVisible: Boolean) { - _isVisible.value = isVisible + fun setPrimaryShow(keyguardBouncerModel: KeyguardBouncerModel?) { + _primaryBouncerShow.value = keyguardBouncerModel } - fun setShow(keyguardBouncerModel: KeyguardBouncerModel?) { - _show.value = keyguardBouncerModel + fun setPrimaryShowingSoon(showingSoon: Boolean) { + _primaryBouncerShowingSoon.value = showingSoon } - fun setShowingSoon(showingSoon: Boolean) { - _showingSoon.value = showingSoon + fun setPrimaryHide(hide: Boolean) { + _primaryBouncerHide.value = hide } - fun setHide(hide: Boolean) { - _hide.value = hide + fun setPrimaryStartingToHide(startingToHide: Boolean) { + _primaryBouncerStartingToHide.value = startingToHide } - fun setStartingToHide(startingToHide: Boolean) { - _startingToHide.value = startingToHide + fun setPrimaryStartDisappearAnimation(runnable: Runnable?) { + _primaryBouncerDisappearAnimation.value = runnable } - fun setStartDisappearAnimation(runnable: Runnable?) { - _disappearAnimation.value = runnable + fun setPanelExpansion(panelExpansion: Float) { + _panelExpansionAmount.value = panelExpansion } fun setKeyguardPosition(keyguardPosition: Float) { 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 c867c6e9229b..ca25282ec2f0 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 @@ -16,6 +16,7 @@ package com.android.systemui.keyguard.data.repository +import com.android.keyguard.KeyguardUpdateMonitor import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow import com.android.systemui.common.shared.model.Position @@ -123,6 +124,11 @@ interface KeyguardRepository { * Sets the relative offset of the lock-screen clock from its natural position on the screen. */ fun setClockPosition(x: Int, y: Int) + + /** + * Returns whether the keyguard bottom area should be constrained to the top of the lock icon + */ + fun isUdfpsSupported(): Boolean } /** Encapsulates application state for the keyguard. */ @@ -130,11 +136,12 @@ interface KeyguardRepository { class KeyguardRepositoryImpl @Inject constructor( - statusBarStateController: StatusBarStateController, - private val keyguardStateController: KeyguardStateController, - dozeHost: DozeHost, - wakefulnessLifecycle: WakefulnessLifecycle, - biometricUnlockController: BiometricUnlockController, + statusBarStateController: StatusBarStateController, + dozeHost: DozeHost, + wakefulnessLifecycle: WakefulnessLifecycle, + biometricUnlockController: BiometricUnlockController, + private val keyguardStateController: KeyguardStateController, + private val keyguardUpdateMonitor: KeyguardUpdateMonitor, ) : KeyguardRepository { private val _animateBottomAreaDozingTransitions = MutableStateFlow(false) override val animateBottomAreaDozingTransitions = @@ -311,6 +318,8 @@ constructor( _clockPosition.value = Position(x, y) } + override fun isUdfpsSupported(): Boolean = keyguardUpdateMonitor.isUdfpsSupported + private fun statusBarStateIntToObject(value: Int): StatusBarState { return when (value) { 0 -> StatusBarState.SHADE diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBottomAreaInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBottomAreaInteractor.kt index ede50b068de3..d2a7486eed0b 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBottomAreaInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBottomAreaInteractor.kt @@ -48,4 +48,9 @@ constructor( fun setAnimateDozingTransitions(animate: Boolean) { repository.setAnimateDozingTransitions(animate) } + + /** + * Returns whether the keyguard bottom area should be constrained to the top of the lock icon + */ + fun shouldConstrainToTopOfLockIcon(): Boolean = repository.isUdfpsSupported() } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/BouncerCallbackInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerCallbackInteractor.kt index 10c7a3774e09..c5e49c61e581 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/BouncerCallbackInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerCallbackInteractor.kt @@ -24,9 +24,9 @@ import javax.inject.Inject /** Interactor to add and remove callbacks for the bouncer. */ @SysUISingleton -class BouncerCallbackInteractor @Inject constructor() { +class PrimaryBouncerCallbackInteractor @Inject constructor() { private var resetCallbacks = ListenerSet<KeyguardBouncer.KeyguardResetCallback>() - private var expansionCallbacks = ArrayList<KeyguardBouncer.BouncerExpansionCallback>() + private var expansionCallbacks = ArrayList<KeyguardBouncer.PrimaryBouncerExpansionCallback>() /** Add a KeyguardResetCallback. */ fun addKeyguardResetCallback(callback: KeyguardBouncer.KeyguardResetCallback) { resetCallbacks.addIfAbsent(callback) @@ -38,7 +38,7 @@ class BouncerCallbackInteractor @Inject constructor() { } /** Adds a callback to listen to bouncer expansion updates. */ - fun addBouncerExpansionCallback(callback: KeyguardBouncer.BouncerExpansionCallback) { + fun addBouncerExpansionCallback(callback: KeyguardBouncer.PrimaryBouncerExpansionCallback) { if (!expansionCallbacks.contains(callback)) { expansionCallbacks.add(callback) } @@ -48,7 +48,7 @@ class BouncerCallbackInteractor @Inject constructor() { * Removes a previously added callback. If the callback was never added, this method does * nothing. */ - fun removeBouncerExpansionCallback(callback: KeyguardBouncer.BouncerExpansionCallback) { + fun removeBouncerExpansionCallback(callback: KeyguardBouncer.PrimaryBouncerExpansionCallback) { expansionCallbacks.remove(callback) } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/BouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt index dbb0352c2187..c22f4e7a2634 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/BouncerInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt @@ -44,24 +44,27 @@ import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.map -/** Encapsulates business logic for interacting with the lock-screen bouncer. */ +/** + * Encapsulates business logic for interacting with the lock-screen primary (pin/pattern/password) + * bouncer. + */ @SysUISingleton -class BouncerInteractor +class PrimaryBouncerInteractor @Inject constructor( private val repository: KeyguardBouncerRepository, - private val bouncerView: BouncerView, + private val primaryBouncerView: BouncerView, @Main private val mainHandler: Handler, private val keyguardStateController: KeyguardStateController, private val keyguardSecurityModel: KeyguardSecurityModel, - private val callbackInteractor: BouncerCallbackInteractor, + private val primaryBouncerCallbackInteractor: PrimaryBouncerCallbackInteractor, private val falsingCollector: FalsingCollector, private val dismissCallbackRegistry: DismissCallbackRegistry, keyguardBypassController: KeyguardBypassController, keyguardUpdateMonitor: KeyguardUpdateMonitor, ) { /** Whether we want to wait for face auth. */ - private val bouncerFaceDelay = + private val primaryBouncerFaceDelay = keyguardStateController.isFaceAuthEnabled && !keyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible( KeyguardUpdateMonitor.getCurrentUser() @@ -70,38 +73,39 @@ constructor( !keyguardUpdateMonitor.userNeedsStrongAuth() && !keyguardBypassController.bypassEnabled - /** Runnable to show the bouncer. */ + /** Runnable to show the primary bouncer. */ val showRunnable = Runnable { - repository.setVisible(true) - repository.setShow( + repository.setPrimaryVisible(true) + repository.setPrimaryShow( KeyguardBouncerModel( promptReason = repository.bouncerPromptReason ?: 0, errorMessage = repository.bouncerErrorMessage, expansionAmount = repository.panelExpansionAmount.value ) ) - repository.setShowingSoon(false) + repository.setPrimaryShowingSoon(false) } val keyguardAuthenticated: Flow<Boolean> = repository.keyguardAuthenticated.filterNotNull() val screenTurnedOff: Flow<Unit> = repository.onScreenTurnedOff.filter { it }.map {} - val show: Flow<KeyguardBouncerModel> = repository.show.filterNotNull() - val hide: Flow<Unit> = repository.hide.filter { it }.map {} - val startingToHide: Flow<Unit> = repository.startingToHide.filter { it }.map {} - val isVisible: Flow<Boolean> = repository.isVisible + val show: Flow<KeyguardBouncerModel> = repository.primaryBouncerShow.filterNotNull() + val hide: Flow<Unit> = repository.primaryBouncerHide.filter { it }.map {} + val startingToHide: Flow<Unit> = repository.primaryBouncerStartingToHide.filter { it }.map {} + val isVisible: Flow<Boolean> = repository.primaryBouncerVisible val isBackButtonEnabled: Flow<Boolean> = repository.isBackButtonEnabled.filterNotNull() val showMessage: Flow<BouncerShowMessageModel> = repository.showMessage.filterNotNull() val startingDisappearAnimation: Flow<Runnable> = - repository.startingDisappearAnimation.filterNotNull() + repository.primaryBouncerStartingDisappearAnimation.filterNotNull() val resourceUpdateRequests: Flow<Boolean> = repository.resourceUpdateRequests.filter { it } val keyguardPosition: Flow<Float> = repository.keyguardPosition val panelExpansionAmount: Flow<Float> = repository.panelExpansionAmount /** 0f = bouncer fully hidden. 1f = bouncer fully visible. */ - val bouncerExpansion: Flow<Float> = // - combine(repository.panelExpansionAmount, repository.isVisible) { expansionAmount, isVisible - -> - if (isVisible) { - 1f - expansionAmount + val bouncerExpansion: Flow<Float> = + combine(repository.panelExpansionAmount, repository.primaryBouncerVisible) { + panelExpansion, + primaryBouncerVisible -> + if (primaryBouncerVisible) { + 1f - panelExpansion } else { 0f } @@ -116,13 +120,14 @@ constructor( repository.setShowMessage(null) repository.setOnScreenTurnedOff(false) repository.setKeyguardAuthenticated(null) - repository.setHide(false) - repository.setStartingToHide(false) + repository.setPrimaryHide(false) + repository.setPrimaryStartingToHide(false) val resumeBouncer = - (repository.isVisible.value || repository.showingSoon.value) && needsFullscreenBouncer() + (repository.primaryBouncerVisible.value || + repository.primaryBouncerShowingSoon.value) && needsFullscreenBouncer() - if (!resumeBouncer && repository.show.value != null) { + if (!resumeBouncer && repository.primaryBouncerShow.value != null) { // If bouncer is visible, the bouncer is already showing. return } @@ -134,29 +139,29 @@ constructor( } Trace.beginSection("KeyguardBouncer#show") - repository.setScrimmed(isScrimmed) + repository.setPrimaryScrimmed(isScrimmed) if (isScrimmed) { setPanelExpansion(KeyguardBouncer.EXPANSION_VISIBLE) } if (resumeBouncer) { - bouncerView.delegate?.resume() + primaryBouncerView.delegate?.resume() // Bouncer is showing the next security screen and we just need to prompt a resume. return } - if (bouncerView.delegate?.showNextSecurityScreenOrFinish() == true) { + if (primaryBouncerView.delegate?.showNextSecurityScreenOrFinish() == true) { // Keyguard is done. return } - repository.setShowingSoon(true) - if (bouncerFaceDelay) { + repository.setPrimaryShowingSoon(true) + if (primaryBouncerFaceDelay) { mainHandler.postDelayed(showRunnable, 1200L) } else { DejankUtils.postAfterTraversal(showRunnable) } keyguardStateController.notifyBouncerShowing(true) - callbackInteractor.dispatchStartingToShow() + primaryBouncerCallbackInteractor.dispatchStartingToShow() Trace.endSection() } @@ -174,10 +179,10 @@ constructor( falsingCollector.onBouncerHidden() keyguardStateController.notifyBouncerShowing(false /* showing */) cancelShowRunnable() - repository.setShowingSoon(false) - repository.setVisible(false) - repository.setHide(true) - repository.setShow(null) + repository.setPrimaryShowingSoon(false) + repository.setPrimaryVisible(false) + repository.setPrimaryHide(true) + repository.setPrimaryShow(null) Trace.endSection() } @@ -191,7 +196,7 @@ constructor( fun setPanelExpansion(expansion: Float) { val oldExpansion = repository.panelExpansionAmount.value val expansionChanged = oldExpansion != expansion - if (repository.startingDisappearAnimation.value == null) { + if (repository.primaryBouncerStartingDisappearAnimation.value == null) { repository.setPanelExpansion(expansion) } @@ -200,25 +205,25 @@ constructor( oldExpansion != KeyguardBouncer.EXPANSION_VISIBLE ) { falsingCollector.onBouncerShown() - callbackInteractor.dispatchFullyShown() + primaryBouncerCallbackInteractor.dispatchFullyShown() } else if ( expansion == KeyguardBouncer.EXPANSION_HIDDEN && oldExpansion != KeyguardBouncer.EXPANSION_HIDDEN ) { - repository.setVisible(false) - repository.setShow(null) + repository.setPrimaryVisible(false) + repository.setPrimaryShow(null) falsingCollector.onBouncerHidden() - DejankUtils.postAfterTraversal { callbackInteractor.dispatchReset() } - callbackInteractor.dispatchFullyHidden() + DejankUtils.postAfterTraversal { primaryBouncerCallbackInteractor.dispatchReset() } + primaryBouncerCallbackInteractor.dispatchFullyHidden() } else if ( expansion != KeyguardBouncer.EXPANSION_VISIBLE && oldExpansion == KeyguardBouncer.EXPANSION_VISIBLE ) { - callbackInteractor.dispatchStartingToHide() - repository.setStartingToHide(true) + primaryBouncerCallbackInteractor.dispatchStartingToHide() + repository.setPrimaryStartingToHide(true) } if (expansionChanged) { - callbackInteractor.dispatchExpansionChanged(expansion) + primaryBouncerCallbackInteractor.dispatchExpansionChanged(expansion) } } @@ -236,7 +241,7 @@ constructor( onDismissAction: ActivityStarter.OnDismissAction?, cancelAction: Runnable? ) { - bouncerView.delegate?.setDismissAction(onDismissAction, cancelAction) + primaryBouncerView.delegate?.setDismissAction(onDismissAction, cancelAction) } /** Update the resources of the views. */ @@ -266,7 +271,7 @@ constructor( /** Notify that view visibility has changed. */ fun notifyBouncerVisibilityHasChanged(visibility: Int) { - callbackInteractor.dispatchVisibilityChanged(visibility) + primaryBouncerCallbackInteractor.dispatchVisibilityChanged(visibility) } /** Notify that the resources have been updated */ @@ -283,38 +288,39 @@ constructor( fun startDisappearAnimation(runnable: Runnable) { val finishRunnable = Runnable { runnable.run() - repository.setStartDisappearAnimation(null) + repository.setPrimaryStartDisappearAnimation(null) } - repository.setStartDisappearAnimation(finishRunnable) + repository.setPrimaryStartDisappearAnimation(finishRunnable) } /** Returns whether bouncer is fully showing. */ fun isFullyShowing(): Boolean { - return (repository.showingSoon.value || repository.isVisible.value) && + return (repository.primaryBouncerShowingSoon.value || + repository.primaryBouncerVisible.value) && repository.panelExpansionAmount.value == KeyguardBouncer.EXPANSION_VISIBLE && - repository.startingDisappearAnimation.value == null + repository.primaryBouncerStartingDisappearAnimation.value == null } /** Returns whether bouncer is scrimmed. */ fun isScrimmed(): Boolean { - return repository.isScrimmed.value + return repository.primaryBouncerScrimmed.value } /** If bouncer expansion is between 0f and 1f non-inclusive. */ fun isInTransit(): Boolean { - return repository.showingSoon.value || + return repository.primaryBouncerShowingSoon.value || repository.panelExpansionAmount.value != KeyguardBouncer.EXPANSION_HIDDEN && repository.panelExpansionAmount.value != KeyguardBouncer.EXPANSION_VISIBLE } /** Return whether bouncer is animating away. */ fun isAnimatingAway(): Boolean { - return repository.startingDisappearAnimation.value != null + return repository.primaryBouncerStartingDisappearAnimation.value != null } /** Return whether bouncer will dismiss with actions */ fun willDismissWithAction(): Boolean { - return bouncerView.delegate?.willDismissWithActions() == true + return primaryBouncerView.delegate?.willDismissWithActions() == true } /** Returns whether the bouncer should be full screen. */ 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 2c99ca59ba6b..3276b6dd9748 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 @@ -27,6 +27,8 @@ import androidx.core.view.isVisible import androidx.core.view.updateLayoutParams import androidx.lifecycle.Lifecycle import androidx.lifecycle.repeatOnLifecycle +import com.android.keyguard.KeyguardUpdateMonitor +import com.android.keyguard.LockIconViewController import com.android.settingslib.Utils import com.android.systemui.R import com.android.systemui.animation.Expandable @@ -69,6 +71,11 @@ object KeyguardBottomAreaViewBinder { /** Notifies that device configuration has changed. */ fun onConfigurationChanged() + + /** + * Returns whether the keyguard bottom area should be constrained to the top of the lock icon + */ + fun shouldConstrainToTopOfLockIcon(): Boolean } /** Binds the view to the view-model, continuing to update the former based on the latter. */ @@ -208,6 +215,9 @@ object KeyguardBottomAreaViewBinder { override fun onConfigurationChanged() { configurationBasedDimensions.value = loadFromResources(view) } + + override fun shouldConstrainToTopOfLockIcon(): Boolean = + viewModel.shouldConstrainToTopOfLockIcon() } } 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 b6b230441397..227796f43e35 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 @@ -90,6 +90,12 @@ constructor( .distinctUntilChanged() } + /** + * Returns whether the keyguard bottom area should be constrained to the top of the lock icon + */ + fun shouldConstrainToTopOfLockIcon(): Boolean = + bottomAreaInteractor.shouldConstrainToTopOfLockIcon() + private fun button( position: KeyguardQuickAffordancePosition ): Flow<KeyguardQuickAffordanceViewModel> { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModel.kt index 9a9284371074..07816001f45c 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModel.kt @@ -19,7 +19,7 @@ package com.android.systemui.keyguard.ui.viewmodel import android.view.View import com.android.systemui.keyguard.data.BouncerView import com.android.systemui.keyguard.data.BouncerViewDelegate -import com.android.systemui.keyguard.domain.interactor.BouncerInteractor +import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor import com.android.systemui.keyguard.shared.model.BouncerShowMessageModel import com.android.systemui.keyguard.shared.model.KeyguardBouncerModel import com.android.systemui.statusbar.phone.KeyguardBouncer.EXPANSION_VISIBLE @@ -34,7 +34,7 @@ class KeyguardBouncerViewModel @Inject constructor( private val view: BouncerView, - private val interactor: BouncerInteractor, + private val interactor: PrimaryBouncerInteractor, ) { /** Observe on bouncer expansion amount. */ val bouncerExpansionAmount: Flow<Float> = interactor.panelExpansionAmount diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt index be357ee0ff73..ceb48458a1d3 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt @@ -79,8 +79,7 @@ class MediaProjectionAppSelectorActivity( val queryIntent = Intent(Intent.ACTION_MAIN).apply { addCategory(Intent.CATEGORY_LAUNCHER) } intent.putExtra(Intent.EXTRA_INTENT, queryIntent) - // TODO(b/240939253): update copies - val title = getString(R.string.media_projection_dialog_service_title) + val title = getString(R.string.media_projection_permission_app_selector_title) intent.putExtra(Intent.EXTRA_TITLE, title) super.onCreate(bundle) controller.init() diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java index 397bffcaa64c..22f91f359de8 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java +++ b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java @@ -18,6 +18,9 @@ package com.android.systemui.media; import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; +import static com.android.systemui.screenrecord.ScreenShareOptionKt.ENTIRE_SCREEN; +import static com.android.systemui.screenrecord.ScreenShareOptionKt.SINGLE_APP; + import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; @@ -44,6 +47,8 @@ import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; +import com.android.systemui.screenrecord.MediaProjectionPermissionDialog; +import com.android.systemui.screenrecord.ScreenShareOption; import com.android.systemui.statusbar.phone.SystemUIDialog; import com.android.systemui.util.Utils; @@ -102,7 +107,9 @@ public class MediaProjectionPermissionActivity extends Activity CharSequence dialogText = null; CharSequence dialogTitle = null; + String appName = null; if (Utils.isHeadlessRemoteDisplayProvider(packageManager, mPackageName)) { + // TODO(b/253438807): handle special app name dialogText = getString(R.string.media_projection_dialog_service_text); dialogTitle = getString(R.string.media_projection_dialog_service_title); } else { @@ -132,7 +139,7 @@ public class MediaProjectionPermissionActivity extends Activity String unsanitizedAppName = TextUtils.ellipsize(label, paint, MAX_APP_NAME_SIZE_PX, TextUtils.TruncateAt.END).toString(); - String appName = BidiFormatter.getInstance().unicodeWrap(unsanitizedAppName); + appName = BidiFormatter.getInstance().unicodeWrap(unsanitizedAppName); String actionText = getString(R.string.media_projection_dialog_text, appName); SpannableString message = new SpannableString(actionText); @@ -146,27 +153,28 @@ public class MediaProjectionPermissionActivity extends Activity dialogTitle = getString(R.string.media_projection_dialog_title, appName); } - AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this, - R.style.Theme_SystemUI_Dialog) - .setTitle(dialogTitle) - .setIcon(R.drawable.ic_media_projection_permission) - .setMessage(dialogText) - .setPositiveButton(R.string.media_projection_action_text, this) - .setNeutralButton(android.R.string.cancel, this) - .setOnCancelListener(this); - if (isPartialScreenSharingEnabled()) { - // This is a temporary entry point before we have a new permission dialog - // TODO(b/233183090): this activity should be redesigned to have a dropdown selector - dialogBuilder.setNegativeButton("App", this); + mDialog = new MediaProjectionPermissionDialog(this, () -> { + ScreenShareOption selectedOption = + ((MediaProjectionPermissionDialog) mDialog).getSelectedScreenShareOption(); + grantMediaProjectionPermission(selectedOption.getMode()); + }, appName); + } else { + AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this, + R.style.Theme_SystemUI_Dialog) + .setTitle(dialogTitle) + .setIcon(R.drawable.ic_media_projection_permission) + .setMessage(dialogText) + .setPositiveButton(R.string.media_projection_action_text, this) + .setNeutralButton(android.R.string.cancel, this); + mDialog = dialogBuilder.create(); } - mDialog = dialogBuilder.create(); - SystemUIDialog.registerDismissListener(mDialog); SystemUIDialog.applyFlags(mDialog); SystemUIDialog.setDialogSize(mDialog); + mDialog.setOnCancelListener(this); mDialog.create(); mDialog.getButton(DialogInterface.BUTTON_POSITIVE).setFilterTouchesWhenObscured(true); @@ -186,12 +194,17 @@ public class MediaProjectionPermissionActivity extends Activity @Override public void onClick(DialogInterface dialog, int which) { + if (which == AlertDialog.BUTTON_POSITIVE) { + grantMediaProjectionPermission(ENTIRE_SCREEN); + } + } + + private void grantMediaProjectionPermission(int screenShareMode) { try { - if (which == AlertDialog.BUTTON_POSITIVE) { + if (screenShareMode == ENTIRE_SCREEN) { setResult(RESULT_OK, getMediaProjectionIntent(mUid, mPackageName)); } - - if (isPartialScreenSharingEnabled() && which == AlertDialog.BUTTON_NEGATIVE) { + if (isPartialScreenSharingEnabled() && screenShareMode == SINGLE_APP) { IMediaProjection projection = createProjection(mUid, mPackageName); final Intent intent = new Intent(this, MediaProjectionAppSelectorActivity.class); intent.putExtra(MediaProjectionManager.EXTRA_MEDIA_PROJECTION, diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/models/recommendation/SmartspaceMediaDataProvider.kt b/packages/SystemUI/src/com/android/systemui/media/controls/models/recommendation/SmartspaceMediaDataProvider.kt index a7ed69a9ab73..cacb3e2bbe4d 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/models/recommendation/SmartspaceMediaDataProvider.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/models/recommendation/SmartspaceMediaDataProvider.kt @@ -29,7 +29,6 @@ class SmartspaceMediaDataProvider @Inject constructor() : BcSmartspaceDataPlugin private val smartspaceMediaTargetListeners: MutableList<SmartspaceTargetListener> = mutableListOf() - private var smartspaceMediaTargets: List<SmartspaceTarget> = listOf() override fun registerListener(smartspaceTargetListener: SmartspaceTargetListener) { smartspaceMediaTargetListeners.add(smartspaceTargetListener) @@ -41,22 +40,7 @@ class SmartspaceMediaDataProvider @Inject constructor() : BcSmartspaceDataPlugin /** Updates Smartspace data and propagates it to any listeners. */ override fun onTargetsAvailable(targets: List<SmartspaceTarget>) { - // Filter out non-media targets. - val mediaTargets = mutableListOf<SmartspaceTarget>() - for (target in targets) { - val smartspaceTarget = target - if (smartspaceTarget.featureType == SmartspaceTarget.FEATURE_MEDIA) { - mediaTargets.add(smartspaceTarget) - } - } - - if (!mediaTargets.isEmpty()) { - Log.d(TAG, "Forwarding Smartspace media updates $mediaTargets") - } - - smartspaceMediaTargets = mediaTargets - smartspaceMediaTargetListeners.forEach { - it.onSmartspaceTargetsUpdated(smartspaceMediaTargets) - } + Log.d(TAG, "Forwarding Smartspace updates $targets") + smartspaceMediaTargetListeners.forEach { it.onSmartspaceTargetsUpdated(targets) } } } 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 e38c1baaeae9..8aaee81a57dd 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 @@ -610,7 +610,12 @@ constructor( // are // elements in mediaPlayers. if (MediaPlayerData.players().size != mediaContent.childCount) { - Log.wtf(TAG, "Size of players list and number of views in carousel are out of sync") + Log.e( + TAG, + "Size of players list and number of views in carousel are out of sync. " + + "Players size is ${MediaPlayerData.players().size}. " + + "View count is ${mediaContent.childCount}." + ) } return existingPlayer == null } @@ -667,7 +672,12 @@ constructor( // are // elements in mediaPlayers. if (MediaPlayerData.players().size != mediaContent.childCount) { - Log.wtf(TAG, "Size of players list and number of views in carousel are out of sync") + Log.e( + TAG, + "Size of players list and number of views in carousel are out of sync. " + + "Players size is ${MediaPlayerData.players().size}. " + + "View count is ${mediaContent.childCount}." + ) } } 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 5b14cf34827a..215fa03c8c59 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 @@ -373,6 +373,7 @@ public class MediaControlPanel { mMediaViewController.attach(player, MediaViewController.TYPE.PLAYER); vh.getPlayer().setOnLongClickListener(v -> { + if (mFalsingManager.isFalseLongTap(FalsingManager.LOW_PENALTY)) return true; if (!mMediaViewController.isGutsVisible()) { openGuts(); return true; @@ -423,6 +424,7 @@ public class MediaControlPanel { mMediaViewController.attach(recommendations, MediaViewController.TYPE.RECOMMENDATION); mRecommendationViewHolder.getRecommendations().setOnLongClickListener(v -> { + if (mFalsingManager.isFalseLongTap(FalsingManager.LOW_PENALTY)) return true; if (!mMediaViewController.isGutsVisible()) { openGuts(); return true; @@ -1191,6 +1193,7 @@ public class MediaControlPanel { setSmartspaceRecItemOnClickListener(mediaCoverContainer, recommendation, itemIndex); // Bubble up the long-click event to the card. mediaCoverContainer.setOnLongClickListener(v -> { + if (mFalsingManager.isFalseLongTap(FalsingManager.LOW_PENALTY)) return true; View parent = (View) v.getParent(); if (parent != null) { parent.performLongClick(); diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt index 662d059aedcd..8bddffc842f5 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt @@ -45,6 +45,7 @@ import com.android.systemui.temporarydisplay.TemporaryViewInfo import com.android.systemui.util.animation.AnimationUtil.Companion.frames import com.android.systemui.util.concurrency.DelayableExecutor import com.android.systemui.util.view.ViewUtil +import com.android.systemui.util.wakelock.WakeLock import javax.inject.Inject /** @@ -68,6 +69,7 @@ class MediaTttChipControllerReceiver @Inject constructor( private val mediaTttFlags: MediaTttFlags, private val uiEventLogger: MediaTttReceiverUiEventLogger, private val viewUtil: ViewUtil, + wakeLockBuilder: WakeLock.Builder, ) : TemporaryViewDisplayController<ChipReceiverInfo, MediaTttLogger>( context, logger, @@ -77,6 +79,7 @@ class MediaTttChipControllerReceiver @Inject constructor( configurationController, powerManager, R.layout.media_ttt_chip_receiver, + wakeLockBuilder, ) { @SuppressLint("WrongConstant") // We're allowed to use LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS override val windowLayoutParams = commonWindowLayoutParams.apply { diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt index 7fd100fd1398..6c41caab38a8 100644 --- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt +++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt @@ -19,6 +19,7 @@ package com.android.systemui.mediaprojection.appselector import android.app.Activity import android.content.ComponentName import android.content.Context +import com.android.launcher3.icons.IconFactory import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.media.MediaProjectionAppSelectorActivity import com.android.systemui.mediaprojection.appselector.data.ActivityTaskManagerThumbnailLoader @@ -92,6 +93,11 @@ interface MediaProjectionAppSelectorModule { ): ConfigurationController = ConfigurationControllerImpl(activity) @Provides + fun bindIconFactory( + context: Context + ): IconFactory = IconFactory.obtain(context) + + @Provides @MediaProjectionAppSelector @MediaProjectionAppSelectorScope fun provideCoroutineScope(@Application applicationScope: CoroutineScope): CoroutineScope = diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/AppIconLoader.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/AppIconLoader.kt index 0927f3b00724..b85d6285c35b 100644 --- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/AppIconLoader.kt +++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/AppIconLoader.kt @@ -19,13 +19,14 @@ package com.android.systemui.mediaprojection.appselector.data import android.content.ComponentName import android.content.Context import android.content.pm.PackageManager -import android.content.pm.PackageManager.ComponentInfoFlags import android.graphics.drawable.Drawable import android.os.UserHandle import com.android.launcher3.icons.BaseIconFactory.IconOptions import com.android.launcher3.icons.IconFactory import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.shared.system.PackageManagerWrapper import javax.inject.Inject +import javax.inject.Provider import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.withContext @@ -38,14 +39,18 @@ class IconLoaderLibAppIconLoader constructor( @Background private val backgroundDispatcher: CoroutineDispatcher, private val context: Context, - private val packageManager: PackageManager + // Use wrapper to access hidden API that allows to get ActivityInfo for any user id + private val packageManagerWrapper: PackageManagerWrapper, + private val packageManager: PackageManager, + private val iconFactoryProvider: Provider<IconFactory> ) : AppIconLoader { override suspend fun loadIcon(userId: Int, component: ComponentName): Drawable? = withContext(backgroundDispatcher) { - IconFactory.obtain(context).use<IconFactory, Drawable?> { iconFactory -> - val activityInfo = packageManager - .getActivityInfo(component, ComponentInfoFlags.of(0)) + iconFactoryProvider.get().use<IconFactory, Drawable?> { iconFactory -> + val activityInfo = + packageManagerWrapper.getActivityInfo(component, userId) + ?: return@withContext null val icon = activityInfo.loadIcon(packageManager) ?: return@withContext null val userHandler = UserHandle.of(userId) val options = IconOptions().apply { setUser(userHandler) } diff --git a/packages/SystemUI/src/com/android/systemui/motiontool/MotionToolModule.kt b/packages/SystemUI/src/com/android/systemui/motiontool/MotionToolModule.kt new file mode 100644 index 000000000000..1324d2c5c27b --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/motiontool/MotionToolModule.kt @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.motiontool + +import android.view.WindowManagerGlobal +import com.android.app.motiontool.DdmHandleMotionTool +import com.android.app.motiontool.MotionToolManager +import com.android.app.viewcapture.ViewCapture +import com.android.systemui.CoreStartable +import dagger.Binds +import dagger.Module +import dagger.Provides +import dagger.multibindings.ClassKey +import dagger.multibindings.IntoMap + +@Module +interface MotionToolModule { + + companion object { + + @Provides + fun provideDdmHandleMotionTool(motionToolManager: MotionToolManager): DdmHandleMotionTool { + return DdmHandleMotionTool.getInstance(motionToolManager) + } + + @Provides + fun provideMotionToolManager( + viewCapture: ViewCapture, + windowManagerGlobal: WindowManagerGlobal + ): MotionToolManager { + return MotionToolManager.getInstance(viewCapture, windowManagerGlobal) + } + + @Provides + fun provideWindowManagerGlobal(): WindowManagerGlobal = WindowManagerGlobal.getInstance() + + @Provides fun provideViewCapture(): ViewCapture = ViewCapture.getInstance() + } + + @Binds + @IntoMap + @ClassKey(MotionToolStartable::class) + fun bindMotionToolStartable(impl: MotionToolStartable): CoreStartable +} diff --git a/packages/SystemUI/src/com/android/systemui/ChooserSelectorResourceHelper.java b/packages/SystemUI/src/com/android/systemui/motiontool/MotionToolStartable.kt index 7a2de7b6a78d..fbb9538316f7 100644 --- a/packages/SystemUI/src/com/android/systemui/ChooserSelectorResourceHelper.java +++ b/packages/SystemUI/src/com/android/systemui/motiontool/MotionToolStartable.kt @@ -14,18 +14,19 @@ * limitations under the License. */ -package com.android.systemui; +package com.android.systemui.motiontool -import androidx.annotation.StringRes; +import com.android.app.motiontool.DdmHandleMotionTool +import com.android.systemui.CoreStartable +import com.android.systemui.dagger.SysUISingleton +import javax.inject.Inject -import com.android.internal.R; +@SysUISingleton +class MotionToolStartable +@Inject +internal constructor(private val ddmHandleMotionTool: DdmHandleMotionTool) : CoreStartable { -/** Helper class for referencing resources */ -class ChooserSelectorResourceHelper { - - private ChooserSelectorResourceHelper() { + override fun start() { + ddmHandleMotionTool.register() } - - @StringRes - static final int CONFIG_CHOOSER_ACTIVITY = R.string.config_chooserActivity; } diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt index d247f249e2fd..b964b76795b8 100644 --- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt +++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt @@ -22,7 +22,7 @@ import android.os.UserManager import android.view.KeyEvent import com.android.systemui.dagger.SysUISingleton import com.android.systemui.util.kotlin.getOrNull -import com.android.wm.shell.floating.FloatingTasks +import com.android.wm.shell.bubbles.Bubbles import java.util.Optional import javax.inject.Inject @@ -39,7 +39,7 @@ internal class NoteTaskController constructor( private val context: Context, private val intentResolver: NoteTaskIntentResolver, - private val optionalFloatingTasks: Optional<FloatingTasks>, + private val optionalBubbles: Optional<Bubbles>, private val optionalKeyguardManager: Optional<KeyguardManager>, private val optionalUserManager: Optional<UserManager>, @NoteTaskEnabledKey private val isEnabled: Boolean, @@ -54,7 +54,7 @@ constructor( } private fun showNoteTask() { - val floatingTasks = optionalFloatingTasks.getOrNull() ?: return + val bubbles = optionalBubbles.getOrNull() ?: return val keyguardManager = optionalKeyguardManager.getOrNull() ?: return val userManager = optionalUserManager.getOrNull() ?: return val intent = intentResolver.resolveIntent() ?: return @@ -66,7 +66,7 @@ constructor( context.startActivity(intent) } else { // TODO(b/254606432): Should include Intent.EXTRA_FLOATING_WINDOW_MODE parameter. - floatingTasks.showOrSetStashed(intent) + bubbles.showAppBubble(intent) } } } diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInitializer.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInitializer.kt index d84717da3a21..0a5b6008981b 100644 --- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInitializer.kt +++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInitializer.kt @@ -17,7 +17,7 @@ package com.android.systemui.notetask import com.android.systemui.statusbar.CommandQueue -import com.android.wm.shell.floating.FloatingTasks +import com.android.wm.shell.bubbles.Bubbles import dagger.Lazy import java.util.Optional import javax.inject.Inject @@ -26,7 +26,7 @@ import javax.inject.Inject internal class NoteTaskInitializer @Inject constructor( - private val optionalFloatingTasks: Optional<FloatingTasks>, + private val optionalBubbles: Optional<Bubbles>, private val lazyNoteTaskController: Lazy<NoteTaskController>, private val commandQueue: CommandQueue, @NoteTaskEnabledKey private val isEnabled: Boolean, @@ -40,7 +40,7 @@ constructor( } fun initialize() { - if (isEnabled && optionalFloatingTasks.isPresent) { + if (isEnabled && optionalBubbles.isPresent) { commandQueue.addCallback(callbacks) } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/HeaderPrivacyIconsController.kt b/packages/SystemUI/src/com/android/systemui/qs/HeaderPrivacyIconsController.kt index dc79f40ffef6..6f645b562008 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/HeaderPrivacyIconsController.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/HeaderPrivacyIconsController.kt @@ -26,6 +26,7 @@ import java.util.concurrent.Executor import javax.inject.Inject import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.statusbar.policy.DeviceProvisionedController interface ChipVisibilityListener { fun onChipVisibilityRefreshed(visible: Boolean) @@ -54,7 +55,8 @@ class HeaderPrivacyIconsController @Inject constructor( private val activityStarter: ActivityStarter, private val appOpsController: AppOpsController, private val broadcastDispatcher: BroadcastDispatcher, - private val safetyCenterManager: SafetyCenterManager + private val safetyCenterManager: SafetyCenterManager, + private val deviceProvisionedController: DeviceProvisionedController ) { var chipVisibilityListener: ChipVisibilityListener? = null @@ -134,6 +136,8 @@ class HeaderPrivacyIconsController @Inject constructor( fun onParentVisible() { privacyChip.setOnClickListener { + // Do not expand dialog while device is not provisioned + if (!deviceProvisionedController.isDeviceProvisioned) return@setOnClickListener // If the privacy chip is visible, it means there were some indicators uiEventLogger.log(PrivacyChipEvent.ONGOING_INDICATORS_CHIP_CLICK) if (safetyCenterEnabled) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java index ef87fb49752d..dc9dcc295e6e 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java @@ -29,6 +29,7 @@ import android.widget.FrameLayout; import com.android.systemui.Dumpable; import com.android.systemui.R; import com.android.systemui.qs.customize.QSCustomizer; +import com.android.systemui.util.LargeScreenUtils; import java.io.PrintWriter; @@ -52,6 +53,7 @@ public class QSContainerImpl extends FrameLayout implements Dumpable { private boolean mQsDisabled; private int mContentHorizontalPadding = -1; private boolean mClippingEnabled; + private boolean mUseCombinedHeaders; public QSContainerImpl(Context context, AttributeSet attrs) { super(context, attrs); @@ -66,6 +68,10 @@ public class QSContainerImpl extends FrameLayout implements Dumpable { setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO); } + void setUseCombinedHeaders(boolean useCombinedHeaders) { + mUseCombinedHeaders = useCombinedHeaders; + } + @Override public boolean hasOverlappingRendering() { return false; @@ -143,9 +149,15 @@ public class QSContainerImpl extends FrameLayout implements Dumpable { void updateResources(QSPanelController qsPanelController, QuickStatusBarHeaderController quickStatusBarHeaderController) { + int topPadding = QSUtils.getQsHeaderSystemIconsAreaHeight(mContext); + if (mUseCombinedHeaders + && !LargeScreenUtils.shouldUseLargeScreenShadeHeader(mContext.getResources())) { + topPadding = mContext.getResources() + .getDimensionPixelSize(R.dimen.large_screen_shade_header_height); + } mQSPanelContainer.setPaddingRelative( mQSPanelContainer.getPaddingStart(), - QSUtils.getQsHeaderSystemIconsAreaHeight(mContext), + topPadding, mQSPanelContainer.getPaddingEnd(), mQSPanelContainer.getPaddingBottom()); diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImplController.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImplController.java index dea7bb5abd71..28b4c8228d38 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImplController.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImplController.java @@ -22,6 +22,8 @@ import android.content.res.Configuration; import android.view.MotionEvent; import android.view.View; +import com.android.systemui.flags.FeatureFlags; +import com.android.systemui.flags.Flags; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.qs.dagger.QSScope; import com.android.systemui.statusbar.policy.ConfigurationController; @@ -37,7 +39,6 @@ public class QSContainerImplController extends ViewController<QSContainerImpl> { private final ConfigurationController mConfigurationController; private final FalsingManager mFalsingManager; private final NonInterceptingScrollView mQSPanelContainer; - private final ConfigurationController.ConfigurationListener mConfigurationListener = new ConfigurationController.ConfigurationListener() { @Override @@ -65,13 +66,15 @@ public class QSContainerImplController extends ViewController<QSContainerImpl> { QSPanelController qsPanelController, QuickStatusBarHeaderController quickStatusBarHeaderController, ConfigurationController configurationController, - FalsingManager falsingManager) { + FalsingManager falsingManager, + FeatureFlags featureFlags) { super(view); mQsPanelController = qsPanelController; mQuickStatusBarHeaderController = quickStatusBarHeaderController; mConfigurationController = configurationController; mFalsingManager = falsingManager; mQSPanelContainer = mView.getQSPanelContainer(); + view.setUseCombinedHeaders(featureFlags.isEnabled(Flags.COMBINED_QS_HEADERS)); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java index abc0adecbfeb..64962b495c96 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java @@ -237,7 +237,7 @@ public class QSPanelController extends QSPanelControllerBase<QSPanel> { * @return if bouncer is in transit */ public boolean isBouncerInTransit() { - return mStatusBarKeyguardViewManager.isBouncerInTransit(); + return mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit(); } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java index 27d9da6c2e1e..946fe542741f 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java @@ -288,8 +288,15 @@ public class QuickStatusBarHeader extends FrameLayout { } MarginLayoutParams qqsLP = (MarginLayoutParams) mHeaderQsPanel.getLayoutParams(); - qqsLP.topMargin = largeScreenHeaderActive || !mUseCombinedQSHeader ? mContext.getResources() - .getDimensionPixelSize(R.dimen.qqs_layout_margin_top) : qsOffsetHeight; + if (largeScreenHeaderActive) { + qqsLP.topMargin = mContext.getResources() + .getDimensionPixelSize(R.dimen.qqs_layout_margin_top); + } else if (!mUseCombinedQSHeader) { + qqsLP.topMargin = qsOffsetHeight; + } else { + qqsLP.topMargin = mContext.getResources() + .getDimensionPixelSize(R.dimen.large_screen_shade_header_min_height); + } mHeaderQsPanel.setLayoutParams(qqsLP); updateBatteryMode(); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java index 1f92b12c1a83..cd69f4edff63 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java @@ -140,16 +140,21 @@ public class QSIconViewImpl extends QSIconView { iv.setTag(R.id.qs_icon_tag, icon); iv.setTag(R.id.qs_slash_tag, state.slash); iv.setPadding(0, padding, 0, padding); - if (shouldAnimate && d instanceof Animatable2) { + if (d instanceof Animatable2) { Animatable2 a = (Animatable2) d; a.start(); - if (state.isTransient) { - a.registerAnimationCallback(new AnimationCallback() { - @Override - public void onAnimationEnd(Drawable drawable) { - a.start(); - } - }); + if (shouldAnimate) { + if (state.isTransient) { + a.registerAnimationCallback(new AnimationCallback() { + @Override + public void onAnimationEnd(Drawable drawable) { + a.start(); + } + }); + } + } else { + // Sends animator to end of animation. Needs to be called after calling start. + a.stop(); } } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QRCodeScannerTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QRCodeScannerTile.java index b41502213555..376d3d8da8e7 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/QRCodeScannerTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QRCodeScannerTile.java @@ -115,7 +115,7 @@ public class QRCodeScannerTile extends QSTileImpl<QSTile.State> { state.label = mContext.getString(R.string.qr_code_scanner_title); state.contentDescription = state.label; state.icon = ResourceIcon.get(R.drawable.ic_qr_code_scanner); - state.state = mQRCodeScannerController.isEnabledForQuickSettings() ? Tile.STATE_ACTIVE + state.state = mQRCodeScannerController.isEnabledForQuickSettings() ? Tile.STATE_INACTIVE : Tile.STATE_UNAVAILABLE; } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java index f63f0444210b..64a8a146031b 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java @@ -16,6 +16,7 @@ package com.android.systemui.qs.tiles; +import android.app.Dialog; import android.content.Intent; import android.os.Handler; import android.os.Looper; @@ -43,7 +44,6 @@ import com.android.systemui.qs.QSHost; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.screenrecord.RecordingController; -import com.android.systemui.screenrecord.ScreenRecordDialog; import com.android.systemui.statusbar.phone.KeyguardDismissUtil; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -170,9 +170,9 @@ public class ScreenRecordTile extends QSTileImpl<QSTile.BooleanState> mDialogLaunchAnimator.disableAllCurrentDialogsExitAnimations(); getHost().collapsePanels(); }; - ScreenRecordDialog dialog = mController.createScreenRecordDialog(mContext, mFlags, - mDialogLaunchAnimator, mActivityStarter, onStartRecordingClicked); + Dialog dialog = mController.createScreenRecordDialog(mContext, mFlags, + mDialogLaunchAnimator, mActivityStarter, onStartRecordingClicked); ActivityStarter.OnDismissAction dismissAction = () -> { if (shouldAnimateFromView) { mDialogLaunchAnimator.showFromView(dialog, view, new DialogCuj( diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java index 46c4f410d078..ba97297421b3 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java @@ -108,7 +108,6 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; import java.util.Optional; -import java.util.function.BiConsumer; import java.util.function.Supplier; import javax.inject.Inject; @@ -470,8 +469,6 @@ public class OverviewProxyService extends CurrentUserTracker implements }; private final StatusBarWindowCallback mStatusBarWindowCallback = this::onStatusBarStateChanged; - private final BiConsumer<Rect, Rect> mSplitScreenBoundsChangeListener = - this::notifySplitScreenBoundsChanged; // This is the death handler for the binder from the launcher service private final IBinder.DeathRecipient mOverviewServiceDeathRcpt @@ -839,26 +836,6 @@ public class OverviewProxyService extends CurrentUserTracker implements } } - /** - * Notifies the Launcher of split screen size changes - * - * @param secondaryWindowBounds Bounds of the secondary window including the insets - * @param secondaryWindowInsets stable insets received by the secondary window - */ - public void notifySplitScreenBoundsChanged( - Rect secondaryWindowBounds, Rect secondaryWindowInsets) { - try { - if (mOverviewProxy != null) { - mOverviewProxy.onSplitScreenSecondaryBoundsChanged( - secondaryWindowBounds, secondaryWindowInsets); - } else { - Log.e(TAG_OPS, "Failed to get overview proxy for split screen bounds."); - } - } catch (RemoteException e) { - Log.e(TAG_OPS, "Failed to call onSplitScreenSecondaryBoundsChanged()", e); - } - } - private final ScreenLifecycle.Observer mLifecycleObserver = new ScreenLifecycle.Observer() { /** * Notifies the Launcher that screen turned on and ready to use diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/BaseScreenSharePermissionDialog.kt b/packages/SystemUI/src/com/android/systemui/screenrecord/BaseScreenSharePermissionDialog.kt new file mode 100644 index 000000000000..f4d59a8dd6a6 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/screenrecord/BaseScreenSharePermissionDialog.kt @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.screenrecord + +import android.content.Context +import android.os.Bundle +import android.view.Gravity +import android.view.View +import android.view.ViewStub +import android.view.WindowManager +import android.widget.AdapterView +import android.widget.ArrayAdapter +import android.widget.Spinner +import android.widget.TextView +import androidx.annotation.LayoutRes +import androidx.annotation.StringRes +import com.android.systemui.R +import com.android.systemui.statusbar.phone.SystemUIDialog + +/** Base permission dialog for screen share and recording */ +open class BaseScreenSharePermissionDialog( + context: Context?, + private val screenShareOptions: List<ScreenShareOption>, + private val appName: String? +) : SystemUIDialog(context), AdapterView.OnItemSelectedListener { + private lateinit var dialogTitle: TextView + private lateinit var startButton: TextView + private lateinit var warning: TextView + private lateinit var screenShareModeSpinner: Spinner + var selectedScreenShareOption: ScreenShareOption = screenShareOptions.first() + + public override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + window.apply { + addPrivateFlags(WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS) + setGravity(Gravity.CENTER) + } + setContentView(R.layout.screen_share_dialog) + dialogTitle = findViewById(R.id.screen_share_dialog_title) + warning = findViewById(R.id.text_warning) + startButton = findViewById(R.id.button_start) + findViewById<TextView>(R.id.button_cancel).setOnClickListener { dismiss() } + initScreenShareOptions() + createOptionsView(getOptionsViewLayoutId()) + } + + protected fun initScreenShareOptions() { + selectedScreenShareOption = screenShareOptions.first() + warning.text = warningText + initScreenShareSpinner() + } + + private val warningText: String + get() = context.getString(selectedScreenShareOption.warningText, appName) + + private fun initScreenShareSpinner() { + val options = screenShareOptions.map { context.getString(it.spinnerText) }.toTypedArray() + val adapter = + ArrayAdapter(context.applicationContext, android.R.layout.simple_spinner_item, options) + adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) + screenShareModeSpinner = findViewById(R.id.screen_share_mode_spinner) + screenShareModeSpinner.adapter = adapter + screenShareModeSpinner.onItemSelectedListener = this + } + + override fun onItemSelected(adapterView: AdapterView<*>?, view: View, pos: Int, id: Long) { + selectedScreenShareOption = screenShareOptions[pos] + warning.text = warningText + } + + override fun onNothingSelected(parent: AdapterView<*>?) {} + + /** Protected methods for the text updates & functionality */ + protected fun setDialogTitle(@StringRes stringId: Int) { + val title = context.getString(stringId, appName) + dialogTitle.text = title + } + + protected fun setStartButtonText(@StringRes stringId: Int) { + startButton.setText(stringId) + } + + protected fun setStartButtonOnClickListener(listener: View.OnClickListener?) { + startButton.setOnClickListener(listener) + } + + // Create additional options that is shown under the share mode spinner + // Eg. the audio and tap toggles in SysUI Recorder + @LayoutRes protected open fun getOptionsViewLayoutId(): Int? = null + + private fun createOptionsView(@LayoutRes layoutId: Int?) { + if (layoutId == null) return + val stub = findViewById<View>(R.id.options_stub) as ViewStub + stub.layoutResource = layoutId + stub.inflate() + } +} diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/MediaProjectionPermissionDialog.kt b/packages/SystemUI/src/com/android/systemui/screenrecord/MediaProjectionPermissionDialog.kt new file mode 100644 index 000000000000..15b0bc4a356a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/screenrecord/MediaProjectionPermissionDialog.kt @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.screenrecord + +import android.content.Context +import android.os.Bundle +import com.android.systemui.R + +/** Dialog to select screen recording options */ +class MediaProjectionPermissionDialog( + context: Context?, + private val onStartRecordingClicked: Runnable, + appName: String? +) : BaseScreenSharePermissionDialog(context, createOptionList(), appName) { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setDialogTitle(R.string.media_projection_permission_dialog_title) + setStartButtonText(R.string.media_projection_permission_dialog_continue) + setStartButtonOnClickListener { + // Note that it is important to run this callback before dismissing, so that the + // callback can disable the dialog exit animation if it wants to. + onStartRecordingClicked.run() + dismiss() + } + } + + companion object { + private fun createOptionList(): List<ScreenShareOption> { + return listOf( + ScreenShareOption( + SINGLE_APP, + R.string.media_projection_permission_dialog_option_single_app, + R.string.media_projection_permission_dialog_warning_single_app + ), + ScreenShareOption( + ENTIRE_SCREEN, + R.string.media_projection_permission_dialog_option_entire_screen, + R.string.media_projection_permission_dialog_warning_entire_screen + ) + ) + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java index 1083f22164d9..ce4e0ecee914 100644 --- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java +++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java @@ -16,6 +16,7 @@ package com.android.systemui.screenrecord; +import android.app.Dialog; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; @@ -33,6 +34,7 @@ import com.android.systemui.animation.DialogLaunchAnimator; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.flags.FeatureFlags; +import com.android.systemui.flags.Flags; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.settings.UserContextProvider; import com.android.systemui.statusbar.policy.CallbackController; @@ -97,11 +99,15 @@ public class RecordingController } /** Create a dialog to show screen recording options to the user. */ - public ScreenRecordDialog createScreenRecordDialog(Context context, FeatureFlags flags, - DialogLaunchAnimator dialogLaunchAnimator, ActivityStarter activityStarter, - @Nullable Runnable onStartRecordingClicked) { - return new ScreenRecordDialog(context, this, activityStarter, mUserContextProvider, - flags, dialogLaunchAnimator, onStartRecordingClicked); + public Dialog createScreenRecordDialog(Context context, FeatureFlags flags, + DialogLaunchAnimator dialogLaunchAnimator, + ActivityStarter activityStarter, + @Nullable Runnable onStartRecordingClicked) { + return flags.isEnabled(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING) + ? new ScreenRecordPermissionDialog(context, this, activityStarter, + dialogLaunchAnimator, mUserContextProvider, onStartRecordingClicked) + : new ScreenRecordDialog(context, this, activityStarter, + mUserContextProvider, flags, dialogLaunchAnimator, onStartRecordingClicked); } /** diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt new file mode 100644 index 000000000000..cffd28f9fc96 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.screenrecord + +import android.app.Activity +import android.app.PendingIntent +import android.content.Context +import android.content.Intent +import android.os.Bundle +import android.os.Handler +import android.os.Looper +import android.os.ResultReceiver +import android.view.View +import android.widget.AdapterView +import android.widget.AdapterView.OnItemClickListener +import android.widget.ArrayAdapter +import android.widget.Spinner +import android.widget.Switch +import androidx.annotation.LayoutRes +import com.android.systemui.R +import com.android.systemui.animation.DialogLaunchAnimator +import com.android.systemui.media.MediaProjectionAppSelectorActivity +import com.android.systemui.media.MediaProjectionCaptureTarget +import com.android.systemui.plugins.ActivityStarter +import com.android.systemui.settings.UserContextProvider + +/** Dialog to select screen recording options */ +class ScreenRecordPermissionDialog( + context: Context?, + private val controller: RecordingController, + private val activityStarter: ActivityStarter, + private val dialogLaunchAnimator: DialogLaunchAnimator, + private val userContextProvider: UserContextProvider, + private val onStartRecordingClicked: Runnable? +) : BaseScreenSharePermissionDialog(context, createOptionList(), null) { + private lateinit var tapsSwitch: Switch + private lateinit var audioSwitch: Switch + private lateinit var options: Spinner + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setDialogTitle(R.string.screenrecord_start_label) + setStartButtonText(R.string.screenrecord_start_recording) + setStartButtonOnClickListener { v: View? -> + onStartRecordingClicked?.run() + if (selectedScreenShareOption.mode == ENTIRE_SCREEN) { + requestScreenCapture(/* captureTarget= */ null) + } + if (selectedScreenShareOption.mode == SINGLE_APP) { + val intent = Intent(context, MediaProjectionAppSelectorActivity::class.java) + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + + // We can't start activity for result here so we use result receiver to get + // the selected target to capture + intent.putExtra( + MediaProjectionAppSelectorActivity.EXTRA_CAPTURE_REGION_RESULT_RECEIVER, + CaptureTargetResultReceiver() + ) + val animationController = dialogLaunchAnimator.createActivityLaunchController(v!!) + if (animationController == null) { + dismiss() + } + activityStarter.startActivity(intent, /* dismissShade= */ true, animationController) + } + dismiss() + } + initRecordOptionsView() + } + + @LayoutRes override fun getOptionsViewLayoutId(): Int = R.layout.screen_record_options + + private fun initRecordOptionsView() { + audioSwitch = findViewById(R.id.screenrecord_audio_switch) + tapsSwitch = findViewById(R.id.screenrecord_taps_switch) + options = findViewById(R.id.screen_recording_options) + val a: ArrayAdapter<*> = + ScreenRecordingAdapter(context, android.R.layout.simple_spinner_dropdown_item, MODES) + a.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) + options.adapter = a + options.setOnItemClickListenerInt( + OnItemClickListener { _: AdapterView<*>?, _: View?, _: Int, _: Long -> + audioSwitch.isChecked = true + } + ) + } + + /** + * Starts screen capture after some countdown + * @param captureTarget target to capture (could be e.g. a task) or null to record the whole + * screen + */ + private fun requestScreenCapture(captureTarget: MediaProjectionCaptureTarget?) { + val userContext = userContextProvider.userContext + val showTaps = tapsSwitch.isChecked + val audioMode = + if (audioSwitch.isChecked) options.selectedItem as ScreenRecordingAudioSource + else ScreenRecordingAudioSource.NONE + val startIntent = + PendingIntent.getForegroundService( + userContext, + RecordingService.REQUEST_CODE, + RecordingService.getStartIntent( + userContext, + Activity.RESULT_OK, + audioMode.ordinal, + showTaps, + captureTarget + ), + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE + ) + val stopIntent = + PendingIntent.getService( + userContext, + RecordingService.REQUEST_CODE, + RecordingService.getStopIntent(userContext), + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE + ) + controller.startCountdown(DELAY_MS, INTERVAL_MS, startIntent, stopIntent) + } + + private inner class CaptureTargetResultReceiver() : + ResultReceiver(Handler(Looper.getMainLooper())) { + override fun onReceiveResult(resultCode: Int, resultData: Bundle) { + if (resultCode == Activity.RESULT_OK) { + val captureTarget = + resultData.getParcelable( + MediaProjectionAppSelectorActivity.KEY_CAPTURE_TARGET, + MediaProjectionCaptureTarget::class.java + ) + + // Start recording of the selected target + requestScreenCapture(captureTarget) + } + } + } + + companion object { + private val MODES = + listOf( + ScreenRecordingAudioSource.INTERNAL, + ScreenRecordingAudioSource.MIC, + ScreenRecordingAudioSource.MIC_AND_INTERNAL + ) + private const val DELAY_MS: Long = 3000 + private const val INTERVAL_MS: Long = 1000 + private fun createOptionList(): List<ScreenShareOption> { + return listOf( + ScreenShareOption( + SINGLE_APP, + R.string.screenrecord_option_single_app, + R.string.screenrecord_warning_single_app + ), + ScreenShareOption( + ENTIRE_SCREEN, + R.string.screenrecord_option_entire_screen, + R.string.screenrecord_warning_entire_screen + ) + ) + } + } +} diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.aidl b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenShareOption.kt index 1550ab3bed63..914d29a52b53 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.aidl +++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenShareOption.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 The Android Open Source Project + * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,7 +13,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +package com.android.systemui.screenrecord -package com.android.systemui.shared.system; +import androidx.annotation.IntDef +import androidx.annotation.StringRes +import kotlin.annotation.Retention -parcelable RemoteTransitionCompat; +@Retention(AnnotationRetention.SOURCE) +@IntDef(SINGLE_APP, ENTIRE_SCREEN) +annotation class ScreenShareMode + +const val SINGLE_APP = 0 +const val ENTIRE_SCREEN = 1 + +class ScreenShareOption( + @ScreenShareMode val mode: Int, + @StringRes val spinnerText: Int, + @StringRes val warningText: Int +) diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java index 9b5295d1bb3d..d395bd33241d 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java @@ -63,6 +63,7 @@ import android.os.Bundle; import android.os.Process; import android.os.RemoteException; import android.os.UserHandle; +import android.os.UserManager; import android.provider.Settings; import android.util.DisplayMetrics; import android.util.Log; @@ -276,6 +277,7 @@ public class ScreenshotController { mScreenshotNotificationSmartActionsProvider; private final TimeoutHandler mScreenshotHandler; private final ActionIntentExecutor mActionExecutor; + private final UserManager mUserManager; private ScreenshotView mScreenshotView; private Bitmap mScreenBitmap; @@ -314,7 +316,8 @@ public class ScreenshotController { TimeoutHandler timeoutHandler, BroadcastSender broadcastSender, ScreenshotNotificationSmartActionsProvider screenshotNotificationSmartActionsProvider, - ActionIntentExecutor actionExecutor + ActionIntentExecutor actionExecutor, + UserManager userManager ) { mScreenshotSmartActions = screenshotSmartActions; mNotificationsController = screenshotNotificationsController; @@ -345,6 +348,7 @@ public class ScreenshotController { mWindowManager = mContext.getSystemService(WindowManager.class); mFlags = flags; mActionExecutor = actionExecutor; + mUserManager = userManager; mAccessibilityManager = AccessibilityManager.getInstance(mContext); @@ -975,16 +979,25 @@ public class ScreenshotController { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); - mScreenshotView.setChipIntents(imageData); + doPostAnimation(imageData); } }); } else { - mScreenshotView.setChipIntents(imageData); + doPostAnimation(imageData); } }); } } + private void doPostAnimation(ScreenshotController.SavedImageData imageData) { + mScreenshotView.setChipIntents(imageData); + if (mFlags.isEnabled(SCREENSHOT_WORK_PROFILE_POLICY) + && mUserManager.isManagedProfile(imageData.owner.getIdentifier())) { + // TODO: Read app from configuration + mScreenshotView.showWorkProfileMessage("Files"); + } + } + /** * Sets up the action shade and its entrance animation, once we get the Quick Share action data. */ diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java index 27331ae7a389..0a4b550882c9 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java @@ -80,6 +80,7 @@ import android.widget.FrameLayout; import android.widget.HorizontalScrollView; import android.widget.ImageView; import android.widget.LinearLayout; +import android.widget.TextView; import androidx.constraintlayout.widget.ConstraintLayout; @@ -137,6 +138,8 @@ public class ScreenshotView extends FrameLayout implements private ImageView mScrollingScrim; private DraggableConstraintLayout mScreenshotStatic; + private ViewGroup mMessageContainer; + private TextView mMessageContent; private ImageView mScreenshotPreview; private ImageView mScreenshotBadge; private View mScreenshotPreviewBorder; @@ -340,10 +343,26 @@ public class ScreenshotView extends FrameLayout implements } } + /** + * Show a notification under the screenshot view indicating that a work profile screenshot has + * been taken and which app can be used to view it. + * + * @param appName The name of the app to use to view screenshots + */ + void showWorkProfileMessage(String appName) { + mMessageContent.setText( + mContext.getString(R.string.screenshot_work_profile_notification, appName)); + mMessageContainer.setVisibility(VISIBLE); + } + @Override // View protected void onFinishInflate() { mScrollingScrim = requireNonNull(findViewById(R.id.screenshot_scrolling_scrim)); mScreenshotStatic = requireNonNull(findViewById(R.id.screenshot_static)); + mMessageContainer = + requireNonNull(mScreenshotStatic.findViewById(R.id.screenshot_message_container)); + mMessageContent = + requireNonNull(mMessageContainer.findViewById(R.id.screenshot_message_content)); mScreenshotPreview = requireNonNull(findViewById(R.id.screenshot_preview)); mScreenshotPreviewBorder = requireNonNull( diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt index 47bed461e371..28da38b701bc 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt @@ -108,6 +108,7 @@ class UserTrackerImpl internal constructor( val filter = IntentFilter().apply { addAction(Intent.ACTION_USER_SWITCHED) + addAction(Intent.ACTION_USER_INFO_CHANGED) // These get called when a managed profile goes in or out of quiet mode. addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE) addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE) @@ -125,6 +126,7 @@ class UserTrackerImpl internal constructor( Intent.ACTION_USER_SWITCHED -> { handleSwitchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL)) } + Intent.ACTION_USER_INFO_CHANGED, Intent.ACTION_MANAGED_PROFILE_AVAILABLE, Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE, Intent.ACTION_MANAGED_PROFILE_REMOVED, diff --git a/packages/SystemUI/src/com/android/systemui/shade/DebugDrawable.java b/packages/SystemUI/src/com/android/systemui/shade/DebugDrawable.java new file mode 100644 index 000000000000..ae303eb6d203 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/shade/DebugDrawable.java @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.shade; + +import android.annotation.NonNull; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.drawable.Drawable; + +import com.android.keyguard.LockIconViewController; +import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; + +import java.util.HashSet; +import java.util.Set; + +/** + * Drawable for NotificationPanelViewController. + */ +public class DebugDrawable extends Drawable { + + private final NotificationPanelViewController mNotificationPanelViewController; + private final NotificationPanelView mView; + private final NotificationStackScrollLayoutController mNotificationStackScrollLayoutController; + private final LockIconViewController mLockIconViewController; + private final Set<Integer> mDebugTextUsedYPositions; + private final Paint mDebugPaint; + + public DebugDrawable( + NotificationPanelViewController notificationPanelViewController, + NotificationPanelView notificationPanelView, + NotificationStackScrollLayoutController notificationStackScrollLayoutController, + LockIconViewController lockIconViewController + ) { + mNotificationPanelViewController = notificationPanelViewController; + mView = notificationPanelView; + mNotificationStackScrollLayoutController = notificationStackScrollLayoutController; + mLockIconViewController = lockIconViewController; + mDebugTextUsedYPositions = new HashSet<>(); + mDebugPaint = new Paint(); + } + + @Override + public void draw(@androidx.annotation.NonNull @NonNull Canvas canvas) { + mDebugTextUsedYPositions.clear(); + + mDebugPaint.setColor(Color.RED); + mDebugPaint.setStrokeWidth(2); + mDebugPaint.setStyle(Paint.Style.STROKE); + mDebugPaint.setTextSize(24); + String headerDebugInfo = mNotificationPanelViewController.getHeaderDebugInfo(); + if (headerDebugInfo != null) canvas.drawText(headerDebugInfo, 50, 100, mDebugPaint); + + drawDebugInfo(canvas, mNotificationPanelViewController.getMaxPanelHeight(), + Color.RED, "getMaxPanelHeight()"); + drawDebugInfo(canvas, (int) mNotificationPanelViewController.getExpandedHeight(), + Color.BLUE, "getExpandedHeight()"); + drawDebugInfo(canvas, mNotificationPanelViewController.calculatePanelHeightQsExpanded(), + Color.GREEN, "calculatePanelHeightQsExpanded()"); + drawDebugInfo(canvas, mNotificationPanelViewController.calculatePanelHeightQsExpanded(), + Color.YELLOW, "calculatePanelHeightShade()"); + drawDebugInfo(canvas, + (int) mNotificationPanelViewController.calculateNotificationsTopPadding(), + Color.MAGENTA, "calculateNotificationsTopPadding()"); + drawDebugInfo(canvas, mNotificationPanelViewController.getClockPositionResult().clockY, + Color.GRAY, "mClockPositionResult.clockY"); + drawDebugInfo(canvas, (int) mLockIconViewController.getTop(), Color.GRAY, + "mLockIconViewController.getTop()"); + + if (mNotificationPanelViewController.getKeyguardShowing()) { + // Notifications have the space between those two lines. + drawDebugInfo(canvas, + mNotificationStackScrollLayoutController.getTop() + + (int) mNotificationPanelViewController + .getKeyguardNotificationTopPadding(), + Color.RED, "NSSL.getTop() + mKeyguardNotificationTopPadding"); + + drawDebugInfo(canvas, mNotificationStackScrollLayoutController.getBottom() + - (int) mNotificationPanelViewController + .getKeyguardNotificationBottomPadding(), + Color.RED, "NSSL.getBottom() - mKeyguardNotificationBottomPadding"); + } + + mDebugPaint.setColor(Color.CYAN); + canvas.drawLine(0, + mNotificationPanelViewController.getClockPositionResult().stackScrollerPadding, + mView.getWidth(), mNotificationStackScrollLayoutController.getTopPadding(), + mDebugPaint); + } + + private void drawDebugInfo(Canvas canvas, int y, int color, String label) { + mDebugPaint.setColor(color); + canvas.drawLine(/* startX= */ 0, /* startY= */ y, /* stopX= */ mView.getWidth(), + /* stopY= */ y, mDebugPaint); + canvas.drawText(label + " = " + y + "px", /* x= */ 0, + /* y= */ computeDebugYTextPosition(y), mDebugPaint); + } + + private int computeDebugYTextPosition(int lineY) { + if (lineY - mDebugPaint.getTextSize() < 0) { + // Avoiding drawing out of bounds + lineY += mDebugPaint.getTextSize(); + } + int textY = lineY; + while (mDebugTextUsedYPositions.contains(textY)) { + textY = (int) (textY + mDebugPaint.getTextSize()); + } + mDebugTextUsedYPositions.add(textY); + return textY; + } + + @Override + public void setAlpha(int alpha) { + + } + + @Override + public void setColorFilter(ColorFilter colorFilter) { + + } + + @Override + public int getOpacity() { + return PixelFormat.UNKNOWN; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt index 6b540aa9f392..63d0d169e874 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt @@ -246,6 +246,8 @@ class LargeScreenShadeHeaderController @Inject constructor( qsCarrierGroup.updateTextAppearance(R.style.TextAppearance_QS_Status_Carriers) if (header is MotionLayout) { loadConstraints() + header.minHeight = resources + .getDimensionPixelSize(R.dimen.large_screen_shade_header_min_height) lastInsets?.let { updateConstraintsForInsets(header, it) } } updateResources() diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java index 92f5c851f208..cfc1178bd097 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java @@ -56,15 +56,10 @@ import android.app.StatusBarManager; import android.content.ContentResolver; import android.content.res.Resources; import android.database.ContentObserver; -import android.graphics.Canvas; import android.graphics.Color; -import android.graphics.ColorFilter; import android.graphics.Insets; -import android.graphics.Paint; -import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.Region; -import android.graphics.drawable.Drawable; import android.hardware.biometrics.SensorLocationInternal; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.os.Bundle; @@ -123,6 +118,7 @@ import com.android.keyguard.dagger.KeyguardStatusBarViewComponent; import com.android.keyguard.dagger.KeyguardStatusViewComponent; import com.android.keyguard.dagger.KeyguardUserSwitcherComponent; import com.android.systemui.DejankUtils; +import com.android.systemui.Dumpable; import com.android.systemui.R; import com.android.systemui.animation.ActivityLaunchAnimator; import com.android.systemui.animation.Interpolators; @@ -134,6 +130,7 @@ import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.dagger.qualifiers.DisplayId; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.doze.DozeLog; +import com.android.systemui.dump.DumpManager; import com.android.systemui.dump.DumpsysTableLogger; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; @@ -229,17 +226,15 @@ import com.android.wm.shell.animation.FlingAnimationUtils; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collections; -import java.util.HashSet; import java.util.List; import java.util.Optional; -import java.util.Set; import java.util.function.Consumer; import javax.inject.Inject; import javax.inject.Provider; @CentralSurfacesComponent.CentralSurfacesScope -public final class NotificationPanelViewController { +public final class NotificationPanelViewController implements Dumpable { public static final String TAG = NotificationPanelView.class.getSimpleName(); public static final float FLING_MAX_LENGTH_SECONDS = 0.6f; @@ -455,7 +450,6 @@ public final class NotificationPanelViewController { * need to take this into account in our panel height calculation. */ private boolean mQsAnimatorExpand; - private boolean mIsLaunchTransitionFinished; private ValueAnimator mQsSizeChangeAnimator; private boolean mQsScrimEnabled = true; private boolean mQsTouchAboveFalsingThreshold; @@ -751,7 +745,8 @@ public final class NotificationPanelViewController { SystemClock systemClock, CameraGestureHelper cameraGestureHelper, KeyguardBottomAreaViewModel keyguardBottomAreaViewModel, - KeyguardBottomAreaInteractor keyguardBottomAreaInteractor) { + KeyguardBottomAreaInteractor keyguardBottomAreaInteractor, + DumpManager dumpManager) { keyguardStateController.addCallback(new KeyguardStateController.Callback() { @Override public void onKeyguardFadingAwayChanged() { @@ -900,7 +895,8 @@ public final class NotificationPanelViewController { mView.setOnApplyWindowInsetsListener((v, insets) -> onApplyShadeWindowInsets(insets)); if (DEBUG_DRAWABLE) { - mView.getOverlay().add(new DebugDrawable()); + mView.getOverlay().add(new DebugDrawable(this, mView, + mNotificationStackScrollLayoutController, mLockIconViewController)); } mKeyguardUnfoldTransition = unfoldComponent.map( @@ -930,6 +926,7 @@ public final class NotificationPanelViewController { }); mCameraGestureHelper = cameraGestureHelper; mKeyguardBottomAreaInteractor = keyguardBottomAreaInteractor; + dumpManager.registerDumpable(this); } private void unlockAnimationFinished() { @@ -1153,8 +1150,15 @@ public final class NotificationPanelViewController { mLargeScreenShadeHeaderHeight = mResources.getDimensionPixelSize(R.dimen.large_screen_shade_header_height); - mQuickQsHeaderHeight = mUseLargeScreenShadeHeader ? mLargeScreenShadeHeaderHeight : - SystemBarUtils.getQuickQsOffsetHeight(mView.getContext()); + // TODO: When the flag is eventually removed, it means that we have a single view that is + // the same height in QQS and in Large Screen (large_screen_shade_header_height). Eventually + // the concept of largeScreenHeader or quickQsHeader will disappear outside of the class + // that controls the view as the offset needs to be the same regardless. + if (mUseLargeScreenShadeHeader || mFeatureFlags.isEnabled(Flags.COMBINED_QS_HEADERS)) { + mQuickQsHeaderHeight = mLargeScreenShadeHeaderHeight; + } else { + mQuickQsHeaderHeight = SystemBarUtils.getQuickQsOffsetHeight(mView.getContext()); + } int topMargin = mUseLargeScreenShadeHeader ? mLargeScreenShadeHeaderHeight : mResources.getDimensionPixelSize(R.dimen.notification_panel_margin_top); mLargeScreenShadeHeaderController.setLargeScreenActive(mUseLargeScreenShadeHeader); @@ -1309,7 +1313,11 @@ public final class NotificationPanelViewController { } private void initBottomArea() { - mKeyguardBottomArea.init(mKeyguardBottomAreaViewModel, mFalsingManager); + mKeyguardBottomArea.init( + mKeyguardBottomAreaViewModel, + mFalsingManager, + mLockIconViewController + ); } @VisibleForTesting @@ -1506,6 +1514,10 @@ public final class NotificationPanelViewController { updateClock(); } + public KeyguardClockPositionAlgorithm.Result getClockPositionResult() { + return mClockPositionResult; + } + @ClockSize private int computeDesiredClockSize() { if (mSplitShadeEnabled) { @@ -1753,7 +1765,6 @@ public final class NotificationPanelViewController { } public void resetViews(boolean animate) { - mIsLaunchTransitionFinished = false; mCentralSurfaces.getGutsManager().closeAndSaveGuts(true /* leavebehind */, true /* force */, true /* controls */, -1 /* x */, -1 /* y */, true /* resetMenu */); if (animate && !isFullyCollapsed()) { @@ -2971,7 +2982,7 @@ public final class NotificationPanelViewController { } } - private float calculateNotificationsTopPadding() { + float calculateNotificationsTopPadding() { if (mSplitShadeEnabled) { return mKeyguardShowing ? getKeyguardNotificationStaticPadding() : 0; } @@ -3005,6 +3016,18 @@ public final class NotificationPanelViewController { } } + public boolean getKeyguardShowing() { + return mKeyguardShowing; + } + + public float getKeyguardNotificationTopPadding() { + return mKeyguardNotificationTopPadding; + } + + public float getKeyguardNotificationBottomPadding() { + return mKeyguardNotificationBottomPadding; + } + /** Returns the topPadding of notifications when on keyguard not respecting QS expansion. */ private int getKeyguardNotificationStaticPadding() { if (!mKeyguardShowing) { @@ -3274,7 +3297,6 @@ public final class NotificationPanelViewController { return !mSplitShadeEnabled && (isInSettings() || mIsPanelCollapseOnQQS); } - @VisibleForTesting int getMaxPanelHeight() { int min = mStatusBarMinHeight; if (!(mBarState == KEYGUARD) @@ -3372,11 +3394,7 @@ public final class NotificationPanelViewController { boolean isExpanded = !isFullyCollapsed() || mExpectingSynthesizedDown; if (mPanelExpanded != isExpanded) { mPanelExpanded = isExpanded; - - mHeadsUpManager.setIsPanelExpanded(isExpanded); - mStatusBarTouchableRegionManager.setPanelExpanded(isExpanded); - mCentralSurfaces.setPanelExpanded(isExpanded); - + mShadeExpansionStateManager.onShadeExpansionFullyChanged(isExpanded); if (!isExpanded && mQs != null && mQs.isCustomizing()) { mQs.closeCustomizer(); } @@ -3400,7 +3418,7 @@ public final class NotificationPanelViewController { } } - private int calculatePanelHeightQsExpanded() { + int calculatePanelHeightQsExpanded() { float notificationHeight = mNotificationStackScrollLayoutController.getHeight() @@ -3779,10 +3797,6 @@ public final class NotificationPanelViewController { mQs.closeCustomizer(); } - public boolean isLaunchTransitionFinished() { - return mIsLaunchTransitionFinished; - } - public void setIsLaunchAnimationRunning(boolean running) { boolean wasRunning = mIsLaunchAnimationRunning; mIsLaunchAnimationRunning = running; @@ -4273,29 +4287,185 @@ public final class NotificationPanelViewController { mBlockingExpansionForCurrentTouch = mTracking; } + @Override public void dump(PrintWriter pw, String[] args) { - pw.println(String.format("[PanelView(%s): expandedHeight=%f maxPanelHeight=%d closing=%s" - + " tracking=%s timeAnim=%s%s " - + "touchDisabled=%s" + "]", - this.getClass().getSimpleName(), getExpandedHeight(), getMaxPanelHeight(), - mClosing ? "T" : "f", mTracking ? "T" : "f", mHeightAnimator, - ((mHeightAnimator != null && mHeightAnimator.isStarted()) ? " (started)" : ""), - mTouchDisabled ? "T" : "f")); + pw.println(TAG + ":"); IndentingPrintWriter ipw = asIndenting(pw); ipw.increaseIndent(); + + ipw.print("mDownTime="); ipw.println(mDownTime); + ipw.print("mTouchSlopExceededBeforeDown="); ipw.println(mTouchSlopExceededBeforeDown); + ipw.print("mIsLaunchAnimationRunning="); ipw.println(mIsLaunchAnimationRunning); + ipw.print("mOverExpansion="); ipw.println(mOverExpansion); + ipw.print("mExpandedHeight="); ipw.println(mExpandedHeight); + ipw.print("mTracking="); ipw.println(mTracking); + ipw.print("mHintAnimationRunning="); ipw.println(mHintAnimationRunning); + ipw.print("mExpanding="); ipw.println(mExpanding); + ipw.print("mSplitShadeEnabled="); ipw.println(mSplitShadeEnabled); + ipw.print("mKeyguardNotificationBottomPadding="); + ipw.println(mKeyguardNotificationBottomPadding); + ipw.print("mKeyguardNotificationTopPadding="); ipw.println(mKeyguardNotificationTopPadding); + ipw.print("mMaxAllowedKeyguardNotifications="); + ipw.println(mMaxAllowedKeyguardNotifications); + ipw.print("mAnimateNextPositionUpdate="); ipw.println(mAnimateNextPositionUpdate); + ipw.print("mQuickQsHeaderHeight="); ipw.println(mQuickQsHeaderHeight); + ipw.print("mQsTrackingPointer="); ipw.println(mQsTrackingPointer); + ipw.print("mQsTracking="); ipw.println(mQsTracking); + ipw.print("mConflictingQsExpansionGesture="); ipw.println(mConflictingQsExpansionGesture); + ipw.print("mPanelExpanded="); ipw.println(mPanelExpanded); + ipw.print("mQsExpanded="); ipw.println(mQsExpanded); + ipw.print("mQsExpandedWhenExpandingStarted="); ipw.println(mQsExpandedWhenExpandingStarted); + ipw.print("mQsFullyExpanded="); ipw.println(mQsFullyExpanded); + ipw.print("mKeyguardShowing="); ipw.println(mKeyguardShowing); + ipw.print("mKeyguardQsUserSwitchEnabled="); ipw.println(mKeyguardQsUserSwitchEnabled); + ipw.print("mKeyguardUserSwitcherEnabled="); ipw.println(mKeyguardUserSwitcherEnabled); + ipw.print("mDozing="); ipw.println(mDozing); + ipw.print("mDozingOnDown="); ipw.println(mDozingOnDown); + ipw.print("mBouncerShowing="); ipw.println(mBouncerShowing); + ipw.print("mBarState="); ipw.println(mBarState); + ipw.print("mInitialHeightOnTouch="); ipw.println(mInitialHeightOnTouch); + ipw.print("mInitialTouchX="); ipw.println(mInitialTouchX); + ipw.print("mInitialTouchY="); ipw.println(mInitialTouchY); + ipw.print("mQsExpansionHeight="); ipw.println(mQsExpansionHeight); + ipw.print("mQsMinExpansionHeight="); ipw.println(mQsMinExpansionHeight); + ipw.print("mQsMaxExpansionHeight="); ipw.println(mQsMaxExpansionHeight); + ipw.print("mQsPeekHeight="); ipw.println(mQsPeekHeight); + ipw.print("mStackScrollerOverscrolling="); ipw.println(mStackScrollerOverscrolling); + ipw.print("mQsExpansionFromOverscroll="); ipw.println(mQsExpansionFromOverscroll); + ipw.print("mLastOverscroll="); ipw.println(mLastOverscroll); + ipw.print("mQsExpansionEnabledPolicy="); ipw.println(mQsExpansionEnabledPolicy); + ipw.print("mQsExpansionEnabledAmbient="); ipw.println(mQsExpansionEnabledAmbient); + ipw.print("mStatusBarMinHeight="); ipw.println(mStatusBarMinHeight); + ipw.print("mStatusBarHeaderHeightKeyguard="); ipw.println(mStatusBarHeaderHeightKeyguard); + ipw.print("mOverStretchAmount="); ipw.println(mOverStretchAmount); + ipw.print("mDownX="); ipw.println(mDownX); + ipw.print("mDownY="); ipw.println(mDownY); + ipw.print("mDisplayTopInset="); ipw.println(mDisplayTopInset); + ipw.print("mDisplayRightInset="); ipw.println(mDisplayRightInset); + ipw.print("mLargeScreenShadeHeaderHeight="); ipw.println(mLargeScreenShadeHeaderHeight); + ipw.print("mSplitShadeNotificationsScrimMarginBottom="); + ipw.println(mSplitShadeNotificationsScrimMarginBottom); + ipw.print("mIsExpanding="); ipw.println(mIsExpanding); + ipw.print("mQsExpandImmediate="); ipw.println(mQsExpandImmediate); + ipw.print("mTwoFingerQsExpandPossible="); ipw.println(mTwoFingerQsExpandPossible); + ipw.print("mHeaderDebugInfo="); ipw.println(mHeaderDebugInfo); + ipw.print("mQsAnimatorExpand="); ipw.println(mQsAnimatorExpand); + ipw.print("mQsScrimEnabled="); ipw.println(mQsScrimEnabled); + ipw.print("mQsTouchAboveFalsingThreshold="); ipw.println(mQsTouchAboveFalsingThreshold); + ipw.print("mQsFalsingThreshold="); ipw.println(mQsFalsingThreshold); + ipw.print("mHeadsUpStartHeight="); ipw.println(mHeadsUpStartHeight); + ipw.print("mListenForHeadsUp="); ipw.println(mListenForHeadsUp); + ipw.print("mNavigationBarBottomHeight="); ipw.println(mNavigationBarBottomHeight); + ipw.print("mExpandingFromHeadsUp="); ipw.println(mExpandingFromHeadsUp); + ipw.print("mCollapsedOnDown="); ipw.println(mCollapsedOnDown); + ipw.print("mClosingWithAlphaFadeOut="); ipw.println(mClosingWithAlphaFadeOut); + ipw.print("mHeadsUpAnimatingAway="); ipw.println(mHeadsUpAnimatingAway); + ipw.print("mLaunchingAffordance="); ipw.println(mLaunchingAffordance); + ipw.print("mShowIconsWhenExpanded="); ipw.println(mShowIconsWhenExpanded); + ipw.print("mIndicationBottomPadding="); ipw.println(mIndicationBottomPadding); + ipw.print("mAmbientIndicationBottomPadding="); ipw.println(mAmbientIndicationBottomPadding); + ipw.print("mIsFullWidth="); ipw.println(mIsFullWidth); + ipw.print("mBlockingExpansionForCurrentTouch="); + ipw.println(mBlockingExpansionForCurrentTouch); + ipw.print("mExpectingSynthesizedDown="); ipw.println(mExpectingSynthesizedDown); + ipw.print("mLastEventSynthesizedDown="); ipw.println(mLastEventSynthesizedDown); + ipw.print("mInterpolatedDarkAmount="); ipw.println(mInterpolatedDarkAmount); + ipw.print("mLinearDarkAmount="); ipw.println(mLinearDarkAmount); + ipw.print("mPulsing="); ipw.println(mPulsing); + ipw.print("mHideIconsDuringLaunchAnimation="); ipw.println(mHideIconsDuringLaunchAnimation); + ipw.print("mStackScrollerMeasuringPass="); ipw.println(mStackScrollerMeasuringPass); + ipw.print("mPanelAlpha="); ipw.println(mPanelAlpha); + ipw.print("mBottomAreaShadeAlpha="); ipw.println(mBottomAreaShadeAlpha); + ipw.print("mHeadsUpInset="); ipw.println(mHeadsUpInset); + ipw.print("mHeadsUpPinnedMode="); ipw.println(mHeadsUpPinnedMode); + ipw.print("mAllowExpandForSmallExpansion="); ipw.println(mAllowExpandForSmallExpansion); + ipw.print("mLockscreenNotificationQSPadding="); + ipw.println(mLockscreenNotificationQSPadding); + ipw.print("mTransitioningToFullShadeProgress="); + ipw.println(mTransitioningToFullShadeProgress); + ipw.print("mTransitionToFullShadeQSPosition="); + ipw.println(mTransitionToFullShadeQSPosition); + ipw.print("mDistanceForQSFullShadeTransition="); + ipw.println(mDistanceForQSFullShadeTransition); + ipw.print("mQsTranslationForFullShadeTransition="); + ipw.println(mQsTranslationForFullShadeTransition); + ipw.print("mMaxOverscrollAmountForPulse="); ipw.println(mMaxOverscrollAmountForPulse); + ipw.print("mAnimateNextNotificationBounds="); ipw.println(mAnimateNextNotificationBounds); + ipw.print("mNotificationBoundsAnimationDelay="); + ipw.println(mNotificationBoundsAnimationDelay); + ipw.print("mNotificationBoundsAnimationDuration="); + ipw.println(mNotificationBoundsAnimationDuration); + ipw.print("mIsPanelCollapseOnQQS="); ipw.println(mIsPanelCollapseOnQQS); + ipw.print("mAnimatingQS="); ipw.println(mAnimatingQS); + ipw.print("mIsQsTranslationResetAnimator="); ipw.println(mIsQsTranslationResetAnimator); + ipw.print("mIsPulseExpansionResetAnimator="); ipw.println(mIsPulseExpansionResetAnimator); + ipw.print("mKeyguardOnlyContentAlpha="); ipw.println(mKeyguardOnlyContentAlpha); + ipw.print("mKeyguardOnlyTransitionTranslationY="); + ipw.println(mKeyguardOnlyTransitionTranslationY); + ipw.print("mUdfpsMaxYBurnInOffset="); ipw.println(mUdfpsMaxYBurnInOffset); + ipw.print("mIsGestureNavigation="); ipw.println(mIsGestureNavigation); + ipw.print("mOldLayoutDirection="); ipw.println(mOldLayoutDirection); + ipw.print("mScrimCornerRadius="); ipw.println(mScrimCornerRadius); + ipw.print("mScreenCornerRadius="); ipw.println(mScreenCornerRadius); + ipw.print("mQSAnimatingHiddenFromCollapsed="); ipw.println(mQSAnimatingHiddenFromCollapsed); + ipw.print("mUseLargeScreenShadeHeader="); ipw.println(mUseLargeScreenShadeHeader); + ipw.print("mEnableQsClipping="); ipw.println(mEnableQsClipping); + ipw.print("mQsClipTop="); ipw.println(mQsClipTop); + ipw.print("mQsClipBottom="); ipw.println(mQsClipBottom); + ipw.print("mQsVisible="); ipw.println(mQsVisible); + ipw.print("mMinFraction="); ipw.println(mMinFraction); + ipw.print("mStatusViewCentered="); ipw.println(mStatusViewCentered); + ipw.print("mSplitShadeFullTransitionDistance="); + ipw.println(mSplitShadeFullTransitionDistance); + ipw.print("mSplitShadeScrimTransitionDistance="); + ipw.println(mSplitShadeScrimTransitionDistance); + ipw.print("mMinExpandHeight="); ipw.println(mMinExpandHeight); + ipw.print("mPanelUpdateWhenAnimatorEnds="); ipw.println(mPanelUpdateWhenAnimatorEnds); + ipw.print("mHasVibratedOnOpen="); ipw.println(mHasVibratedOnOpen); + ipw.print("mFixedDuration="); ipw.println(mFixedDuration); + ipw.print("mPanelFlingOvershootAmount="); ipw.println(mPanelFlingOvershootAmount); + ipw.print("mLastGesturedOverExpansion="); ipw.println(mLastGesturedOverExpansion); + ipw.print("mIsSpringBackAnimation="); ipw.println(mIsSpringBackAnimation); + ipw.print("mInSplitShade="); ipw.println(mInSplitShade); + ipw.print("mHintDistance="); ipw.println(mHintDistance); + ipw.print("mInitialOffsetOnTouch="); ipw.println(mInitialOffsetOnTouch); + ipw.print("mCollapsedAndHeadsUpOnDown="); ipw.println(mCollapsedAndHeadsUpOnDown); + ipw.print("mExpandedFraction="); ipw.println(mExpandedFraction); + ipw.print("mExpansionDragDownAmountPx="); ipw.println(mExpansionDragDownAmountPx); + ipw.print("mPanelClosedOnDown="); ipw.println(mPanelClosedOnDown); + ipw.print("mHasLayoutedSinceDown="); ipw.println(mHasLayoutedSinceDown); + ipw.print("mUpdateFlingVelocity="); ipw.println(mUpdateFlingVelocity); + ipw.print("mUpdateFlingOnLayout="); ipw.println(mUpdateFlingOnLayout); + ipw.print("mClosing="); ipw.println(mClosing); + ipw.print("mTouchSlopExceeded="); ipw.println(mTouchSlopExceeded); + ipw.print("mTrackingPointer="); ipw.println(mTrackingPointer); + ipw.print("mTouchSlop="); ipw.println(mTouchSlop); + ipw.print("mSlopMultiplier="); ipw.println(mSlopMultiplier); + ipw.print("mTouchAboveFalsingThreshold="); ipw.println(mTouchAboveFalsingThreshold); + ipw.print("mTouchStartedInEmptyArea="); ipw.println(mTouchStartedInEmptyArea); + ipw.print("mMotionAborted="); ipw.println(mMotionAborted); + ipw.print("mUpwardsWhenThresholdReached="); ipw.println(mUpwardsWhenThresholdReached); + ipw.print("mAnimatingOnDown="); ipw.println(mAnimatingOnDown); + ipw.print("mHandlingPointerUp="); ipw.println(mHandlingPointerUp); + ipw.print("mInstantExpanding="); ipw.println(mInstantExpanding); + ipw.print("mAnimateAfterExpanding="); ipw.println(mAnimateAfterExpanding); + ipw.print("mIsFlinging="); ipw.println(mIsFlinging); + ipw.print("mViewName="); ipw.println(mViewName); + ipw.print("mInitialExpandY="); ipw.println(mInitialExpandY); + ipw.print("mInitialExpandX="); ipw.println(mInitialExpandX); + ipw.print("mTouchDisabled="); ipw.println(mTouchDisabled); + ipw.print("mInitialTouchFromKeyguard="); ipw.println(mInitialTouchFromKeyguard); + ipw.print("mNextCollapseSpeedUpFactor="); ipw.println(mNextCollapseSpeedUpFactor); + ipw.print("mGestureWaitForTouchSlop="); ipw.println(mGestureWaitForTouchSlop); + ipw.print("mIgnoreXTouchSlop="); ipw.println(mIgnoreXTouchSlop); + ipw.print("mExpandLatencyTracking="); ipw.println(mExpandLatencyTracking); + ipw.print("mExpandLatencyTracking="); ipw.println(mExpandLatencyTracking); ipw.println("gestureExclusionRect:" + calculateGestureExclusionRect()); - ipw.println("applyQSClippingImmediately: top(" + mQsClipTop + ") bottom(" + mQsClipBottom - + ")"); - ipw.println("qsVisible:" + mQsVisible); new DumpsysTableLogger( TAG, NPVCDownEventState.TABLE_HEADERS, mLastDownEvents.toList() ).printTableData(ipw); - ipw.decreaseIndent(); - if (mKeyguardStatusBarViewController != null) { - mKeyguardStatusBarViewController.dump(pw, args); - } } @@ -4368,6 +4538,10 @@ public final class NotificationPanelViewController { if (DEBUG_DRAWABLE) mHeaderDebugInfo = text; } + public String getHeaderDebugInfo() { + return mHeaderDebugInfo; + } + public void onThemeChanged() { mConfigurationListener.onThemeChanged(); } @@ -4643,7 +4817,7 @@ public final class NotificationPanelViewController { mUpdateFlingVelocity = vel; } } else if (!mCentralSurfaces.isBouncerShowing() - && !mStatusBarKeyguardViewManager.isShowingAlternateAuth() + && !mStatusBarKeyguardViewManager.isShowingAlternateBouncer() && !mKeyguardStateController.isKeyguardGoingAway()) { onEmptySpaceClick(); onTrackingStopped(true); @@ -4817,7 +4991,6 @@ public final class NotificationPanelViewController { setExpandedHeight(getMaxPanelTransitionDistance() * frac); } - @VisibleForTesting float getExpandedHeight() { return mExpandedHeight; } @@ -5519,89 +5692,6 @@ public final class NotificationPanelViewController { } } - private final class DebugDrawable extends Drawable { - private final Set<Integer> mDebugTextUsedYPositions = new HashSet<>(); - private final Paint mDebugPaint = new Paint(); - - @Override - public void draw(@NonNull Canvas canvas) { - mDebugTextUsedYPositions.clear(); - - mDebugPaint.setColor(Color.RED); - mDebugPaint.setStrokeWidth(2); - mDebugPaint.setStyle(Paint.Style.STROKE); - mDebugPaint.setTextSize(24); - if (mHeaderDebugInfo != null) canvas.drawText(mHeaderDebugInfo, 50, 100, mDebugPaint); - - drawDebugInfo(canvas, getMaxPanelHeight(), Color.RED, "getMaxPanelHeight()"); - drawDebugInfo(canvas, (int) getExpandedHeight(), Color.BLUE, "getExpandedHeight()"); - drawDebugInfo(canvas, calculatePanelHeightQsExpanded(), Color.GREEN, - "calculatePanelHeightQsExpanded()"); - drawDebugInfo(canvas, calculatePanelHeightShade(), Color.YELLOW, - "calculatePanelHeightShade()"); - drawDebugInfo(canvas, (int) calculateNotificationsTopPadding(), Color.MAGENTA, - "calculateNotificationsTopPadding()"); - drawDebugInfo(canvas, mClockPositionResult.clockY, Color.GRAY, - "mClockPositionResult.clockY"); - drawDebugInfo(canvas, (int) mLockIconViewController.getTop(), Color.GRAY, - "mLockIconViewController.getTop()"); - - if (mKeyguardShowing) { - // Notifications have the space between those two lines. - drawDebugInfo(canvas, - mNotificationStackScrollLayoutController.getTop() + - (int) mKeyguardNotificationTopPadding, - Color.RED, - "NSSL.getTop() + mKeyguardNotificationTopPadding"); - - drawDebugInfo(canvas, mNotificationStackScrollLayoutController.getBottom() - - (int) mKeyguardNotificationBottomPadding, - Color.RED, - "NSSL.getBottom() - mKeyguardNotificationBottomPadding"); - } - - mDebugPaint.setColor(Color.CYAN); - canvas.drawLine(0, mClockPositionResult.stackScrollerPadding, mView.getWidth(), - mNotificationStackScrollLayoutController.getTopPadding(), mDebugPaint); - } - - private void drawDebugInfo(Canvas canvas, int y, int color, String label) { - mDebugPaint.setColor(color); - canvas.drawLine(/* startX= */ 0, /* startY= */ y, /* stopX= */ mView.getWidth(), - /* stopY= */ y, mDebugPaint); - canvas.drawText(label + " = " + y + "px", /* x= */ 0, - /* y= */ computeDebugYTextPosition(y), mDebugPaint); - } - - private int computeDebugYTextPosition(int lineY) { - if (lineY - mDebugPaint.getTextSize() < 0) { - // Avoiding drawing out of bounds - lineY += mDebugPaint.getTextSize(); - } - int textY = lineY; - while (mDebugTextUsedYPositions.contains(textY)) { - textY = (int) (textY + mDebugPaint.getTextSize()); - } - mDebugTextUsedYPositions.add(textY); - return textY; - } - - @Override - public void setAlpha(int alpha) { - - } - - @Override - public void setColorFilter(ColorFilter colorFilter) { - - } - - @Override - public int getOpacity() { - return PixelFormat.UNKNOWN; - } - } - @NonNull private WindowInsets onApplyShadeWindowInsets(WindowInsets insets) { // the same types of insets that are handled in NotificationShadeWindowView @@ -6111,7 +6201,7 @@ public final class NotificationPanelViewController { == AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD.getId() || action == AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_UP.getId()) { - mStatusBarKeyguardViewManager.showBouncer(true); + mStatusBarKeyguardViewManager.showPrimaryBouncer(true); return true; } return super.performAccessibilityAction(host, action, args); diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java index 66a22f4ddc0d..b719177f702a 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java @@ -44,6 +44,7 @@ import android.view.WindowManager; import android.view.WindowManager.LayoutParams; import android.view.WindowManagerGlobal; +import com.android.internal.annotations.VisibleForTesting; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.Dumpable; import com.android.systemui.R; @@ -158,6 +159,7 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW SysuiStatusBarStateController.RANK_STATUS_BAR_WINDOW_CONTROLLER); configurationController.addCallback(this); shadeExpansionStateManager.addQsExpansionListener(this::onQsExpansionChanged); + shadeExpansionStateManager.addFullExpansionListener(this::onShadeExpansionFullyChanged); float desiredPreferredRefreshRate = context.getResources() .getInteger(R.integer.config_keyguardRefreshRate); @@ -204,6 +206,14 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW } } + @VisibleForTesting + void onShadeExpansionFullyChanged(Boolean isExpanded) { + if (mCurrentState.mPanelExpanded != isExpanded) { + mCurrentState.mPanelExpanded = isExpanded; + apply(mCurrentState); + } + } + /** * Register a listener to monitor scrims visibility * @param listener A listener to monitor scrims visibility @@ -699,15 +709,6 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW } @Override - public void setPanelExpanded(boolean isExpanded) { - if (mCurrentState.mPanelExpanded == isExpanded) { - return; - } - mCurrentState.mPanelExpanded = isExpanded; - apply(mCurrentState); - } - - @Override public void onRemoteInputActive(boolean remoteInputActive) { mCurrentState.mRemoteInputActive = remoteInputActive; apply(mCurrentState); diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java index 1e63b2dd134f..bb67280c07b8 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java @@ -284,7 +284,7 @@ public class NotificationShadeWindowViewController { return true; } - if (mStatusBarKeyguardViewManager.isShowingAlternateAuth()) { + if (mStatusBarKeyguardViewManager.isShowingAlternateBouncer()) { // capture all touches if the alt auth bouncer is showing return true; } @@ -322,7 +322,7 @@ public class NotificationShadeWindowViewController { handled = !mService.isPulsing(); } - if (mStatusBarKeyguardViewManager.isShowingAlternateAuth()) { + if (mStatusBarKeyguardViewManager.isShowingAlternateBouncer()) { // eat the touch handled = true; } diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt b/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt index 73c6d507f035..85b259e54f37 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.android.systemui.shade import android.view.View diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt index 667392c9796e..a1767cc5888d 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt @@ -34,6 +34,7 @@ import javax.inject.Inject class ShadeExpansionStateManager @Inject constructor() : ShadeStateEvents { private val expansionListeners = CopyOnWriteArrayList<ShadeExpansionListener>() + private val fullExpansionListeners = CopyOnWriteArrayList<ShadeFullExpansionListener>() private val qsExpansionListeners = CopyOnWriteArrayList<ShadeQsExpansionListener>() private val stateListeners = CopyOnWriteArrayList<ShadeStateListener>() private val shadeStateEventsListeners = CopyOnWriteArrayList<ShadeStateEventsListener>() @@ -62,6 +63,15 @@ class ShadeExpansionStateManager @Inject constructor() : ShadeStateEvents { expansionListeners.remove(listener) } + fun addFullExpansionListener(listener: ShadeFullExpansionListener) { + fullExpansionListeners.add(listener) + listener.onShadeExpansionFullyChanged(qsExpanded) + } + + fun removeFullExpansionListener(listener: ShadeFullExpansionListener) { + fullExpansionListeners.remove(listener) + } + fun addQsExpansionListener(listener: ShadeQsExpansionListener) { qsExpansionListeners.add(listener) listener.onQsExpansionChanged(qsExpanded) @@ -156,6 +166,13 @@ class ShadeExpansionStateManager @Inject constructor() : ShadeStateEvents { qsExpansionListeners.forEach { it.onQsExpansionChanged(qsExpanded) } } + fun onShadeExpansionFullyChanged(isExpanded: Boolean) { + this.expanded = isExpanded + + debugLog("expanded=$isExpanded") + fullExpansionListeners.forEach { it.onShadeExpansionFullyChanged(isExpanded) } + } + /** Updates the panel state if necessary. */ fun updateState(@PanelState state: Int) { debugLog( diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/floating/IFloatingTasks.aidl b/packages/SystemUI/src/com/android/systemui/shade/ShadeFullExpansionListener.kt index f79ca1039865..6d13e1972255 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/floating/IFloatingTasks.aidl +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeFullExpansionListener.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 The Android Open Source Project + * Copyright (c) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,15 +14,10 @@ * limitations under the License. */ -package com.android.wm.shell.floating; - -import android.content.Intent; - -/** - * Interface that is exposed to remote callers to manipulate floating task features. - */ -interface IFloatingTasks { - - void showTask(in Intent intent) = 1; +package com.android.systemui.shade +/** A listener interface to be notified of expansion events for the notification shade. */ +fun interface ShadeFullExpansionListener { + /** Invoked whenever the shade expansion changes, when it is fully collapsed or expanded */ + fun onShadeExpansionFullyChanged(isExpanded: Boolean) } diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt index 761530101061..40ed40a767e5 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.android.systemui.shade import android.view.MotionEvent diff --git a/packages/SystemUI/src/com/android/systemui/shade/transition/NoOpOverScroller.kt b/packages/SystemUI/src/com/android/systemui/shade/transition/NoOpOverScroller.kt index f4db3ab9289b..8847dbd0b0c0 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/transition/NoOpOverScroller.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/transition/NoOpOverScroller.kt @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.android.systemui.shade.transition import javax.inject.Inject diff --git a/packages/SystemUI/src/com/android/systemui/shade/transition/ScrimShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/shade/transition/ScrimShadeTransitionController.kt index a77c21a8da57..218e897794fc 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/transition/ScrimShadeTransitionController.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/transition/ScrimShadeTransitionController.kt @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.android.systemui.shade.transition import android.content.res.Configuration diff --git a/packages/SystemUI/src/com/android/systemui/shade/transition/ShadeOverScroller.kt b/packages/SystemUI/src/com/android/systemui/shade/transition/ShadeOverScroller.kt index 22e847deb7b2..a4642e060a22 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/transition/ShadeOverScroller.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/transition/ShadeOverScroller.kt @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.android.systemui.shade.transition import com.android.systemui.shade.PanelState diff --git a/packages/SystemUI/src/com/android/systemui/shade/transition/ShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/shade/transition/ShadeTransitionController.kt index 1e8208f52fdc..1054aa59db61 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/transition/ShadeTransitionController.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/transition/ShadeTransitionController.kt @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.android.systemui.shade.transition import android.content.Context diff --git a/packages/SystemUI/src/com/android/systemui/shade/transition/SplitShadeOverScroller.kt b/packages/SystemUI/src/com/android/systemui/shade/transition/SplitShadeOverScroller.kt index 8c57194c0950..fde08ee859e0 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/transition/SplitShadeOverScroller.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/transition/SplitShadeOverScroller.kt @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.android.systemui.shade.transition import android.animation.Animator diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java index 073ab8b16864..3670d0987a03 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java @@ -21,6 +21,7 @@ import static android.app.admin.DevicePolicyResources.Strings.SystemUi.KEYGUARD_ import static android.app.admin.DevicePolicyResources.Strings.SystemUi.KEYGUARD_NAMED_MANAGEMENT_DISCLOSURE; import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_TOO_DARK; import static android.hardware.biometrics.BiometricSourceType.FACE; +import static android.hardware.biometrics.BiometricSourceType.FINGERPRINT; import static android.view.View.GONE; import static android.view.View.VISIBLE; @@ -50,7 +51,6 @@ import android.content.pm.UserInfo; import android.content.res.ColorStateList; import android.content.res.Resources; import android.graphics.Color; -import android.hardware.biometrics.BiometricFaceConstants; import android.hardware.biometrics.BiometricSourceType; import android.hardware.face.FaceManager; import android.hardware.fingerprint.FingerprintManager; @@ -74,12 +74,12 @@ import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IBatteryStats; import com.android.internal.widget.LockPatternUtils; -import com.android.internal.widget.ViewClippingUtil; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.settingslib.Utils; import com.android.settingslib.fuelgauge.BatteryStatus; import com.android.systemui.R; +import com.android.systemui.biometrics.AuthController; import com.android.systemui.biometrics.FaceHelpMessageDeferral; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dagger.SysUISingleton; @@ -138,6 +138,7 @@ public class KeyguardIndicationController { private final KeyguardStateController mKeyguardStateController; protected final StatusBarStateController mStatusBarStateController; private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; + private final AuthController mAuthController; private ViewGroup mIndicationArea; private KeyguardIndicationTextView mTopIndicationView; private KeyguardIndicationTextView mLockScreenIndicationView; @@ -188,14 +189,7 @@ public class KeyguardIndicationController { private KeyguardUpdateMonitorCallback mUpdateMonitorCallback; private boolean mDozing; - private final ViewClippingUtil.ClippingParameters mClippingParams = - new ViewClippingUtil.ClippingParameters() { - @Override - public boolean shouldFinish(View view) { - return view == mIndicationArea; - } - }; - private ScreenLifecycle mScreenLifecycle; + private final ScreenLifecycle mScreenLifecycle; private final ScreenLifecycle.Observer mScreenObserver = new ScreenLifecycle.Observer() { @Override @@ -209,6 +203,7 @@ public class KeyguardIndicationController { } } }; + private boolean mFaceLockedOutThisAuthSession; /** * Creates a new KeyguardIndicationController and registers callbacks. @@ -229,6 +224,7 @@ public class KeyguardIndicationController { @Main DelayableExecutor executor, @Background DelayableExecutor bgExecutor, FalsingManager falsingManager, + AuthController authController, LockPatternUtils lockPatternUtils, ScreenLifecycle screenLifecycle, KeyguardBypassController keyguardBypassController, @@ -248,6 +244,7 @@ public class KeyguardIndicationController { mExecutor = executor; mBackgroundExecutor = bgExecutor; mLockPatternUtils = lockPatternUtils; + mAuthController = authController; mFalsingManager = falsingManager; mKeyguardBypassController = keyguardBypassController; mAccessibilityManager = accessibilityManager; @@ -619,7 +616,6 @@ public class KeyguardIndicationController { if (mFalsingManager.isFalseTap(LOW_PENALTY)) { return; } - int currentUserId = getCurrentUser(); mDevicePolicyManager.logoutUser(); }) .build(), @@ -676,7 +672,7 @@ public class KeyguardIndicationController { hideTransientIndication(); } updateDeviceEntryIndication(false); - } else if (!visible) { + } else { // If we unlock and return to keyguard quickly, previous error should not be shown hideTransientIndication(); } @@ -764,7 +760,7 @@ public class KeyguardIndicationController { * logic. */ private void showBiometricMessage(CharSequence biometricMessage, - CharSequence biometricMessageFollowUp) { + @Nullable CharSequence biometricMessageFollowUp) { if (TextUtils.equals(biometricMessage, mBiometricMessage)) { return; } @@ -929,7 +925,7 @@ public class KeyguardIndicationController { } if (mStatusBarKeyguardViewManager.isBouncerShowing()) { - if (mStatusBarKeyguardViewManager.isShowingAlternateAuth()) { + if (mStatusBarKeyguardViewManager.isShowingAlternateBouncer()) { return; // udfps affordance is highlighted, no need to show action to unlock } else if (mKeyguardUpdateMonitor.isFaceEnrolled()) { String message = mContext.getString(R.string.keyguard_retry); @@ -1072,17 +1068,12 @@ public class KeyguardIndicationController { && msgId != BIOMETRIC_HELP_FACE_NOT_RECOGNIZED; final boolean faceAuthFailed = biometricSourceType == FACE && msgId == BIOMETRIC_HELP_FACE_NOT_RECOGNIZED; // ran through matcher & failed - final boolean isUnlockWithFingerprintPossible = - mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible( - getCurrentUser()); + final boolean isUnlockWithFingerprintPossible = canUnlockWithFingerprint(); final boolean isCoExFaceAcquisitionMessage = faceAuthSoftError && isUnlockWithFingerprintPossible; if (isCoExFaceAcquisitionMessage && !mCoExFaceAcquisitionMsgIdsToShow.contains(msgId)) { - if (DEBUG) { - Log.d(TAG, "skip showing msgId=" + msgId + " helpString=" + helpString - + ", due to co-ex logic"); - } - return; + debugLog("skip showing msgId=" + msgId + " helpString=" + helpString + + ", due to co-ex logic"); } else if (mStatusBarKeyguardViewManager.isBouncerShowing()) { mStatusBarKeyguardViewManager.setKeyguardMessage(helpString, mInitialTextColorState); @@ -1120,74 +1111,45 @@ public class KeyguardIndicationController { } @Override + public void onLockedOutStateChanged(BiometricSourceType biometricSourceType) { + if (biometricSourceType == FACE && !mKeyguardUpdateMonitor.isFaceLockedOut()) { + mFaceLockedOutThisAuthSession = false; + } + } + + @Override public void onBiometricError(int msgId, String errString, BiometricSourceType biometricSourceType) { - CharSequence deferredFaceMessage = null; if (biometricSourceType == FACE) { - if (msgId == BiometricFaceConstants.FACE_ERROR_TIMEOUT) { - deferredFaceMessage = mFaceAcquiredMessageDeferral.getDeferredMessage(); - if (DEBUG) { - Log.d(TAG, "showDeferredFaceMessage msgId=" + deferredFaceMessage); - } - } - mFaceAcquiredMessageDeferral.reset(); + onFaceAuthError(msgId, errString); + } else if (biometricSourceType == FINGERPRINT) { + onFingerprintAuthError(msgId, errString); } + } - if (shouldSuppressBiometricError(msgId, biometricSourceType, mKeyguardUpdateMonitor)) { - if (DEBUG) { - Log.d(TAG, "suppressingBiometricError msgId=" + msgId - + " source=" + biometricSourceType); - } - } else if (biometricSourceType == FACE && msgId == FaceManager.FACE_ERROR_TIMEOUT) { - // Co-ex: show deferred message OR nothing - if (mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible( - KeyguardUpdateMonitor.getCurrentUser())) { - // if we're on the lock screen (bouncer isn't showing), show the deferred msg - if (deferredFaceMessage != null - && !mStatusBarKeyguardViewManager.isBouncerShowing()) { - showBiometricMessage( - deferredFaceMessage, - mContext.getString(R.string.keyguard_suggest_fingerprint) - ); - return; - } - - // otherwise, don't show any message - if (DEBUG) { - Log.d(TAG, "skip showing FACE_ERROR_TIMEOUT due to co-ex logic"); - } - return; - } - - // Face-only: The face timeout message is not very actionable, let's ask the user to - // manually retry. - if (deferredFaceMessage != null) { - showBiometricMessage( - deferredFaceMessage, - mContext.getString(R.string.keyguard_unlock) - ); - } else { - // suggest swiping up to unlock (try face auth again or swipe up to bouncer) - showActionToUnlock(); - } - } else if (mStatusBarKeyguardViewManager.isBouncerShowing()) { - mStatusBarKeyguardViewManager.setKeyguardMessage(errString, mInitialTextColorState); - } else if (mScreenLifecycle.getScreenState() == SCREEN_ON) { - showBiometricMessage(errString); + private void onFaceAuthError(int msgId, String errString) { + CharSequence deferredFaceMessage = mFaceAcquiredMessageDeferral.getDeferredMessage(); + mFaceAcquiredMessageDeferral.reset(); + if (shouldSuppressFaceError(msgId, mKeyguardUpdateMonitor)) { + debugLog("suppressingFaceError msgId=" + msgId + " errString= " + errString); + return; + } + if (msgId == FaceManager.FACE_ERROR_TIMEOUT) { + handleFaceAuthTimeoutError(deferredFaceMessage); + } else if (isLockoutError(msgId)) { + handleFaceLockoutError(errString); } else { - mBiometricErrorMessageToShowOnScreenOn = errString; + showErrorMessageNowOrLater(errString, null); } } - private boolean shouldSuppressBiometricError(int msgId, - BiometricSourceType biometricSourceType, KeyguardUpdateMonitor updateMonitor) { - if (biometricSourceType == BiometricSourceType.FINGERPRINT) { - return shouldSuppressFingerprintError(msgId, updateMonitor); - } - if (biometricSourceType == FACE) { - return shouldSuppressFaceError(msgId, updateMonitor); + private void onFingerprintAuthError(int msgId, String errString) { + if (shouldSuppressFingerprintError(msgId, mKeyguardUpdateMonitor)) { + debugLog("suppressingFingerprintError msgId=" + msgId + + " errString= " + errString); + } else { + showErrorMessageNowOrLater(errString, null); } - return false; } private boolean shouldSuppressFingerprintError(int msgId, @@ -1197,7 +1159,7 @@ public class KeyguardIndicationController { // pass true for isStrongBiometric to isUnlockingWithBiometricAllowed() to bypass the // check of whether non-strong biometric is allowed return ((!updateMonitor.isUnlockingWithBiometricAllowed(true /* isStrongBiometric */) - && msgId != FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT) + && !isLockoutError(msgId)) || msgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED || msgId == FingerprintManager.FINGERPRINT_ERROR_USER_CANCELED || msgId == FingerprintManager.BIOMETRIC_ERROR_POWER_PRESSED); @@ -1286,7 +1248,82 @@ public class KeyguardIndicationController { } } - private StatusBarStateController.StateListener mStatusBarStateListener = + private void handleFaceLockoutError(String errString) { + int followupMsgId = canUnlockWithFingerprint() ? R.string.keyguard_suggest_fingerprint + : R.string.keyguard_unlock; + String followupMessage = mContext.getString(followupMsgId); + // Lockout error can happen multiple times in a session because we trigger face auth + // even when it is locked out so that the user is aware that face unlock would have + // triggered but didn't because it is locked out. + + // On first lockout we show the error message from FaceManager, which tells the user they + // had too many unsuccessful attempts. + if (!mFaceLockedOutThisAuthSession) { + mFaceLockedOutThisAuthSession = true; + showErrorMessageNowOrLater(errString, followupMessage); + } else if (!mAuthController.isUdfpsFingerDown()) { + // On subsequent lockouts, we show a more generic locked out message. + showBiometricMessage(mContext.getString(R.string.keyguard_face_unlock_unavailable), + followupMessage); + } + } + + private static boolean isLockoutError(int msgId) { + return msgId == FaceManager.FACE_ERROR_LOCKOUT_PERMANENT + || msgId == FaceManager.FACE_ERROR_LOCKOUT; + } + + private void handleFaceAuthTimeoutError(@Nullable CharSequence deferredFaceMessage) { + debugLog("showDeferredFaceMessage msgId=" + deferredFaceMessage); + if (canUnlockWithFingerprint()) { + // Co-ex: show deferred message OR nothing + // if we're on the lock screen (bouncer isn't showing), show the deferred msg + if (deferredFaceMessage != null + && !mStatusBarKeyguardViewManager.isBouncerShowing()) { + showBiometricMessage( + deferredFaceMessage, + mContext.getString(R.string.keyguard_suggest_fingerprint) + ); + } else { + // otherwise, don't show any message + debugLog("skip showing FACE_ERROR_TIMEOUT due to co-ex logic"); + } + } else if (deferredFaceMessage != null) { + // Face-only: The face timeout message is not very actionable, let's ask the + // user to manually retry. + showBiometricMessage( + deferredFaceMessage, + mContext.getString(R.string.keyguard_unlock) + ); + } else { + // Face-only + // suggest swiping up to unlock (try face auth again or swipe up to bouncer) + showActionToUnlock(); + } + } + + private boolean canUnlockWithFingerprint() { + return mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible( + KeyguardUpdateMonitor.getCurrentUser()); + } + + private void debugLog(String logMsg) { + if (DEBUG) { + Log.d(TAG, logMsg); + } + } + + private void showErrorMessageNowOrLater(String errString, @Nullable String followUpMsg) { + if (mStatusBarKeyguardViewManager.isBouncerShowing()) { + mStatusBarKeyguardViewManager.setKeyguardMessage(errString, mInitialTextColorState); + } else if (mScreenLifecycle.getScreenState() == SCREEN_ON) { + showBiometricMessage(errString, followUpMsg); + } else { + mBiometricErrorMessageToShowOnScreenOn = errString; + } + } + + private final StatusBarStateController.StateListener mStatusBarStateListener = new StatusBarStateController.StateListener() { @Override public void onStateChanged(int newState) { @@ -1307,7 +1344,7 @@ public class KeyguardIndicationController { } }; - private KeyguardStateController.Callback mKeyguardStateCallback = + private final KeyguardStateController.Callback mKeyguardStateCallback = new KeyguardStateController.Callback() { @Override public void onUnlockedChanged() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java index e21acb7e0f68..0b1807dd2d70 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java @@ -123,9 +123,6 @@ public interface NotificationShadeWindowController extends RemoteInputController /** Sets whether the window was collapsed by force or not. */ default void setForceWindowCollapsed(boolean force) {} - /** Sets whether panel is expanded or not. */ - default void setPanelExpanded(boolean isExpanded) {} - /** Gets whether the panel is expanded or not. */ default boolean getPanelExpanded() { return false; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java index 408293cffd99..815b86e0adb8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java @@ -805,7 +805,7 @@ public class NotificationShelf extends ActivatableNotificationView implements iconState.hidden = isAppearing || (view instanceof ExpandableNotificationRow && ((ExpandableNotificationRow) view).isLowPriority() - && mShelfIcons.hasMaxNumDot()) + && mShelfIcons.areIconsOverflowing()) || (transitionAmount == 0.0f && !iconState.isAnimating(icon)) || row.isAboveShelf() || row.showingPulsing() diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java index c04bc8289f81..186e6dc92f93 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java @@ -54,6 +54,7 @@ import com.android.systemui.animation.Interpolators; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dump.DumpManager; import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener; +import com.android.systemui.shade.ShadeExpansionStateManager; import com.android.systemui.statusbar.notification.stack.StackStateAnimator; import com.android.systemui.statusbar.policy.CallbackController; @@ -153,13 +154,18 @@ public class StatusBarStateControllerImpl implements private Interpolator mDozeInterpolator = Interpolators.FAST_OUT_SLOW_IN; @Inject - public StatusBarStateControllerImpl(UiEventLogger uiEventLogger, DumpManager dumpManager, - InteractionJankMonitor interactionJankMonitor) { + public StatusBarStateControllerImpl( + UiEventLogger uiEventLogger, + DumpManager dumpManager, + InteractionJankMonitor interactionJankMonitor, + ShadeExpansionStateManager shadeExpansionStateManager + ) { mUiEventLogger = uiEventLogger; mInteractionJankMonitor = interactionJankMonitor; for (int i = 0; i < HISTORY_SIZE; i++) { mHistoricalRecords[i] = new HistoricalState(); } + shadeExpansionStateManager.addFullExpansionListener(this::onShadeExpansionFullyChanged); dumpManager.registerDumpable(this); } @@ -263,21 +269,6 @@ public class StatusBarStateControllerImpl implements } @Override - public boolean setPanelExpanded(boolean expanded) { - if (mIsExpanded == expanded) { - return false; - } - mIsExpanded = expanded; - String tag = getClass().getSimpleName() + "#setIsExpanded"; - DejankUtils.startDetectingBlockingIpcs(tag); - for (RankedListener rl : new ArrayList<>(mListeners)) { - rl.mListener.onExpandedChanged(mIsExpanded); - } - DejankUtils.stopDetectingBlockingIpcs(tag); - return true; - } - - @Override public float getInterpolatedDozeAmount() { return mDozeInterpolator.getInterpolation(mDozeAmount); } @@ -325,6 +316,18 @@ public class StatusBarStateControllerImpl implements } } + private void onShadeExpansionFullyChanged(Boolean isExpanded) { + if (mIsExpanded != isExpanded) { + mIsExpanded = isExpanded; + String tag = getClass().getSimpleName() + "#setIsExpanded"; + DejankUtils.startDetectingBlockingIpcs(tag); + for (RankedListener rl : new ArrayList<>(mListeners)) { + rl.mListener.onExpandedChanged(mIsExpanded); + } + DejankUtils.stopDetectingBlockingIpcs(tag); + } + } + private void startDozeAnimation() { if (mDozeAmount == 0f || mDozeAmount == 1f) { mDozeInterpolator = mIsDozing diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java index 2cc77384fb2a..e0cf812a11e3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java @@ -109,13 +109,6 @@ public interface SysuiStatusBarStateController extends StatusBarStateController void setAndInstrumentDozeAmount(View view, float dozeAmount, boolean animated); /** - * Update the expanded state from {@link CentralSurfaces}'s perspective - * @param expanded are we expanded? - * @return {@code true} if the state changed, else {@code false} - */ - boolean setPanelExpanded(boolean expanded); - - /** * Sets whether to leave status bar open when hiding keyguard */ void setLeaveOpenOnKeyguardHide(boolean leaveOpen); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java index eacb18e3c50c..14d0d7e032d5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java @@ -300,7 +300,7 @@ public interface CentralSurfacesDependenciesModule { @Override public boolean isShowingAlternateAuthOnUnlock() { - return statusBarKeyguardViewManager.get().shouldShowAltAuth(); + return statusBarKeyguardViewManager.get().canShowAlternateBouncer(); } }; return new DialogLaunchAnimator(callback, interactionJankMonitor); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt index 470cbcb842c4..5dbb4f9d70df 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt @@ -33,6 +33,7 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.plugga import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender.OnEndLifetimeExtensionCallback +import com.android.systemui.statusbar.notification.collection.provider.LaunchFullScreenIntentProvider import com.android.systemui.statusbar.notification.collection.render.NodeController import com.android.systemui.statusbar.notification.dagger.IncomingHeader import com.android.systemui.statusbar.notification.interruption.HeadsUpViewBinder @@ -68,6 +69,7 @@ class HeadsUpCoordinator @Inject constructor( private val mHeadsUpViewBinder: HeadsUpViewBinder, private val mNotificationInterruptStateProvider: NotificationInterruptStateProvider, private val mRemoteInputManager: NotificationRemoteInputManager, + private val mLaunchFullScreenIntentProvider: LaunchFullScreenIntentProvider, @IncomingHeader private val mIncomingHeaderController: NodeController, @Main private val mExecutor: DelayableExecutor, ) : Coordinator { @@ -380,6 +382,12 @@ class HeadsUpCoordinator @Inject constructor( * Notification was just added and if it should heads up, bind the view and then show it. */ override fun onEntryAdded(entry: NotificationEntry) { + // First check whether this notification should launch a full screen intent, and + // launch it if needed. + if (mNotificationInterruptStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry)) { + mLaunchFullScreenIntentProvider.launchFullScreenIntent(entry) + } + // shouldHeadsUp includes check for whether this notification should be filtered val shouldHeadsUpEver = mNotificationInterruptStateProvider.shouldHeadsUp(entry) mPostedEntries[entry.key] = PostedEntry( diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/LaunchFullScreenIntentProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/LaunchFullScreenIntentProvider.kt new file mode 100644 index 000000000000..74ff78e25a2f --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/LaunchFullScreenIntentProvider.kt @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.collection.provider + +import android.util.Log +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.statusbar.notification.collection.NotificationEntry +import com.android.systemui.util.ListenerSet +import javax.inject.Inject + +/** + * A class that enables communication of decisions to launch a notification's full screen intent. + */ +@SysUISingleton +class LaunchFullScreenIntentProvider @Inject constructor() { + companion object { + private const val TAG = "LaunchFullScreenIntentProvider" + } + private val listeners = ListenerSet<Listener>() + + /** + * Registers a listener with this provider. These listeners will be alerted whenever a full + * screen intent should be launched for a notification entry. + */ + fun registerListener(listener: Listener) { + listeners.addIfAbsent(listener) + } + + /** Removes the specified listener. */ + fun removeListener(listener: Listener) { + listeners.remove(listener) + } + + /** + * Sends a request to launch full screen intent for the given notification entry to all + * registered listeners. + */ + fun launchFullScreenIntent(entry: NotificationEntry) { + if (listeners.isEmpty()) { + // This should never happen, but we should definitely know if it does because having + // no listeners would indicate that FSIs are getting entirely dropped on the floor. + Log.wtf(TAG, "no listeners found when launchFullScreenIntent requested") + } + for (listener in listeners) { + listener.onFullScreenIntentRequested(entry) + } + } + + /** Listener interface for passing full screen intent launch decisions. */ + fun interface Listener { + /** + * Invoked whenever a full screen intent launch is requested for the given notification + * entry. + */ + fun onFullScreenIntentRequested(entry: NotificationEntry) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java index ff6389141575..df2de560b5b9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java @@ -34,6 +34,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.settings.UserContextProvider; import com.android.systemui.shade.ShadeController; import com.android.systemui.shade.ShadeEventsModule; +import com.android.systemui.shade.ShadeExpansionStateManager; import com.android.systemui.statusbar.NotificationListener; import com.android.systemui.statusbar.notification.AssistantFeedbackController; import com.android.systemui.statusbar.notification.collection.NotifInflaterImpl; @@ -160,6 +161,7 @@ public interface NotificationsModule { NotificationVisibilityProvider visibilityProvider, NotifPipeline notifPipeline, StatusBarStateController statusBarStateController, + ShadeExpansionStateManager shadeExpansionStateManager, NotificationLogger.ExpansionStateLogger expansionStateLogger, NotificationPanelLogger notificationPanelLogger) { return new NotificationLogger( @@ -169,6 +171,7 @@ public interface NotificationsModule { visibilityProvider, notifPipeline, statusBarStateController, + shadeExpansionStateManager, expansionStateLogger, notificationPanelLogger); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java index 639187790ae0..58f59be1db6f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java @@ -36,6 +36,7 @@ import com.android.internal.statusbar.NotificationVisibility; import com.android.systemui.dagger.qualifiers.UiBackground; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener; +import com.android.systemui.shade.ShadeExpansionStateManager; import com.android.systemui.statusbar.NotificationListener; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.notification.collection.NotifLiveDataStore; @@ -92,25 +93,6 @@ public class NotificationLogger implements StateListener { private Boolean mPanelExpanded = null; // Use null to indicate state is not yet known private boolean mLogging = false; - protected final OnChildLocationsChangedListener mNotificationLocationsChangedListener = - new OnChildLocationsChangedListener() { - @Override - public void onChildLocationsChanged() { - if (mHandler.hasCallbacks(mVisibilityReporter)) { - // Visibilities will be reported when the existing - // callback is executed. - return; - } - // Calculate when we're allowed to run the visibility - // reporter. Note that this timestamp might already have - // passed. That's OK, the callback will just be executed - // ASAP. - long nextReportUptimeMs = - mLastVisibilityReportUptimeMs + VISIBILITY_REPORT_MIN_DELAY_MS; - mHandler.postAtTime(mVisibilityReporter, nextReportUptimeMs); - } - }; - // Tracks notifications currently visible in mNotificationStackScroller and // emits visibility events via NoMan on changes. protected Runnable mVisibilityReporter = new Runnable() { @@ -219,6 +201,7 @@ public class NotificationLogger implements StateListener { NotificationVisibilityProvider visibilityProvider, NotifPipeline notifPipeline, StatusBarStateController statusBarStateController, + ShadeExpansionStateManager shadeExpansionStateManager, ExpansionStateLogger expansionStateLogger, NotificationPanelLogger notificationPanelLogger) { mNotificationListener = notificationListener; @@ -232,6 +215,7 @@ public class NotificationLogger implements StateListener { mNotificationPanelLogger = notificationPanelLogger; // Not expected to be destroyed, don't need to unsubscribe statusBarStateController.addCallback(this); + shadeExpansionStateManager.addFullExpansionListener(this::onShadeExpansionFullyChanged); registerNewPipelineListener(); } @@ -278,14 +262,14 @@ public class NotificationLogger implements StateListener { if (DEBUG) { Log.i(TAG, "startNotificationLogging"); } - mListContainer.setChildLocationsChangedListener(mNotificationLocationsChangedListener); + mListContainer.setChildLocationsChangedListener(this::onChildLocationsChanged); // Some transitions like mVisibleToUser=false -> mVisibleToUser=true don't // cause the scroller to emit child location events. Hence generate // one ourselves to guarantee that we're reporting visible // notifications. // (Note that in cases where the scroller does emit events, this // additional event doesn't break anything.) - mNotificationLocationsChangedListener.onChildLocationsChanged(); + onChildLocationsChanged(); } } @@ -411,21 +395,6 @@ public class NotificationLogger implements StateListener { } /** - * Called by CentralSurfaces to notify the logger that the panel expansion has changed. - * The panel may be showing any of the normal notification panel, the AOD, or the bouncer. - * @param isExpanded True if the panel is expanded. - */ - public void onPanelExpandedChanged(boolean isExpanded) { - if (DEBUG) { - Log.i(TAG, "onPanelExpandedChanged: new=" + isExpanded); - } - mPanelExpanded = isExpanded; - synchronized (mDozingLock) { - maybeUpdateLoggingStatus(); - } - } - - /** * Called when the notification is expanded / collapsed. */ public void onExpansionChanged(String key, boolean isUserAction, boolean isExpanded) { @@ -434,6 +403,36 @@ public class NotificationLogger implements StateListener { } @VisibleForTesting + void onShadeExpansionFullyChanged(Boolean isExpanded) { + // mPanelExpanded is initialized as null + if (mPanelExpanded == null || !mPanelExpanded.equals(isExpanded)) { + if (DEBUG) { + Log.i(TAG, "onPanelExpandedChanged: new=" + isExpanded); + } + mPanelExpanded = isExpanded; + synchronized (mDozingLock) { + maybeUpdateLoggingStatus(); + } + } + } + + @VisibleForTesting + void onChildLocationsChanged() { + if (mHandler.hasCallbacks(mVisibilityReporter)) { + // Visibilities will be reported when the existing + // callback is executed. + return; + } + // Calculate when we're allowed to run the visibility + // reporter. Note that this timestamp might already have + // passed. That's OK, the callback will just be executed + // ASAP. + long nextReportUptimeMs = + mLastVisibilityReportUptimeMs + VISIBILITY_REPORT_MIN_DELAY_MS; + mHandler.postAtTime(mVisibilityReporter, nextReportUptimeMs); + } + + @VisibleForTesting public void setVisibilityReporter(Runnable visibilityReporter) { mVisibilityReporter = visibilityReporter; } 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 96dc5c8db9ef..3021414847c0 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 @@ -1341,21 +1341,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView return mOnKeyguard; } - public void removeAllChildren() { - List<ExpandableNotificationRow> notificationChildren = - mChildrenContainer.getAttachedChildren(); - ArrayList<ExpandableNotificationRow> clonedList = new ArrayList<>(notificationChildren); - for (int i = 0; i < clonedList.size(); i++) { - ExpandableNotificationRow row = clonedList.get(i); - if (row.keepInParent()) { - continue; - } - mChildrenContainer.removeNotification(row); - row.setIsChildInGroup(false, null); - } - onAttachedChildrenCountChanged(); - } - @Override public void dismiss(boolean refocusOnDismiss) { super.dismiss(refocusOnDismiss); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java index b2628e40e77e..6f4d6d944033 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java @@ -719,7 +719,7 @@ public class AmbientState implements Dumpable { */ public boolean isBouncerInTransit() { return mStatusBarKeyguardViewManager != null - && mStatusBarKeyguardViewManager.isBouncerInTransit(); + && mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit(); } /** 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 6e68079706f4..f72f1bcdcb1b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java @@ -480,7 +480,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp break; case MODE_SHOW_BOUNCER: Trace.beginSection("MODE_SHOW_BOUNCER"); - mKeyguardViewController.showBouncer(true); + mKeyguardViewController.showPrimaryBouncer(true); Trace.endSection(); break; case MODE_WAKE_AND_UNLOCK_FROM_DREAM: @@ -560,7 +560,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp return MODE_WAKE_AND_UNLOCK_FROM_DREAM; } if (mKeyguardStateController.isShowing()) { - if (mKeyguardViewController.bouncerIsOrWillBeShowing() && unlockingAllowed) { + if (mKeyguardViewController.primaryBouncerIsOrWillBeShowing() && unlockingAllowed) { return MODE_DISMISS_BOUNCER; } else if (unlockingAllowed) { return MODE_UNLOCK_COLLAPSING; @@ -603,7 +603,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp return MODE_UNLOCK_COLLAPSING; } if (mKeyguardStateController.isShowing()) { - if ((mKeyguardViewController.bouncerIsOrWillBeShowing() + if ((mKeyguardViewController.primaryBouncerIsOrWillBeShowing() || mKeyguardBypassController.getAltBouncerShowing()) && unlockingAllowed) { return MODE_DISMISS_BOUNCER; } else if (unlockingAllowed && (bypass || mAuthController.isUdfpsFingerDown())) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java index dc370821dc95..bd0678fb5988 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java @@ -258,8 +258,6 @@ public interface CentralSurfaces extends Dumpable, ActivityStarter, LifecycleOwn void onKeyguardViewManagerStatesUpdated(); - void setPanelExpanded(boolean isExpanded); - ViewGroup getNotificationScrollLayout(); boolean isPulsing(); @@ -456,7 +454,11 @@ public interface CentralSurfaces extends Dumpable, ActivityStarter, LifecycleOwn void setTransitionToFullShadeProgress(float transitionToFullShadeProgress); - void setBouncerHiddenFraction(float expansion); + /** + * Sets the amount of progress to the bouncer being fully hidden/visible. 1 means the bouncer + * is fully hidden, while 0 means the bouncer is visible. + */ + void setPrimaryBouncerHiddenFraction(float expansion); @VisibleForTesting void updateScrimController(); 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 15cc086586da..37027ea13321 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java @@ -848,6 +848,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { mScreenOffAnimationController = screenOffAnimationController; mShadeExpansionStateManager.addExpansionListener(this::onPanelExpansionChanged); + mShadeExpansionStateManager.addFullExpansionListener(this::onShadeExpansionFullyChanged); mBubbleExpandListener = (isExpanding, key) -> mContext.getMainExecutor().execute(this::updateScrimController); @@ -1376,6 +1377,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { private void onPanelExpansionChanged(ShadeExpansionChangeEvent event) { float fraction = event.getFraction(); boolean tracking = event.getTracking(); + boolean isExpanded = event.getExpanded(); dispatchPanelExpansionForKeyguardDismiss(fraction, tracking); if (fraction == 0 || fraction == 1) { @@ -1388,6 +1390,23 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { } } + @VisibleForTesting + void onShadeExpansionFullyChanged(Boolean isExpanded) { + if (mPanelExpanded != isExpanded) { + mPanelExpanded = isExpanded; + if (isExpanded && mStatusBarStateController.getState() != StatusBarState.KEYGUARD) { + if (DEBUG) { + Log.v(TAG, "clearing notification effects from Height"); + } + clearNotificationEffects(); + } + + if (!isExpanded) { + mRemoteInputManager.onPanelCollapsed(); + } + } + } + @NonNull @Override public Lifecycle getLifecycle() { @@ -1793,27 +1812,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { } @Override - public void setPanelExpanded(boolean isExpanded) { - if (mPanelExpanded != isExpanded) { - mNotificationLogger.onPanelExpandedChanged(isExpanded); - } - mPanelExpanded = isExpanded; - mStatusBarHideIconsForBouncerManager.setPanelExpandedAndTriggerUpdate(isExpanded); - mNotificationShadeWindowController.setPanelExpanded(isExpanded); - mStatusBarStateController.setPanelExpanded(isExpanded); - if (isExpanded && mStatusBarStateController.getState() != StatusBarState.KEYGUARD) { - if (DEBUG) { - Log.v(TAG, "clearing notification effects from Height"); - } - clearNotificationEffects(); - } - - if (!isExpanded) { - mRemoteInputManager.onPanelCollapsed(); - } - } - - @Override public ViewGroup getNotificationScrollLayout() { return mStackScroller; } @@ -2267,13 +2265,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { } pw.println(" Panels: "); - if (mNotificationPanelViewController != null) { - pw.println(" mNotificationPanel=" - + mNotificationPanelViewController.getView() + " params=" - + mNotificationPanelViewController.getView().getLayoutParams().debug("")); - pw.print (" "); - mNotificationPanelViewController.dump(pw, args); - } pw.println(" mStackScroller: " + mStackScroller + " (dump moved)"); pw.println(" Theme:"); String nightMode = mUiModeManager == null ? "null" : mUiModeManager.getNightMode() + ""; @@ -2569,12 +2560,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { // ordering. mMainExecutor.execute(mShadeController::runPostCollapseRunnables); } - } else if (mNotificationPanelViewController.isLaunchTransitionFinished()) { - // We are not dismissing the shade, but the launch transition is already - // finished, - // so nobody will call readyForKeyguardDone anymore. Post it such that - // keyguardDonePending gets called first. - mMainExecutor.execute(mStatusBarKeyguardViewManager::readyForKeyguardDone); } return deferred; } @@ -3328,8 +3313,8 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { // lock screen where users can use the UDFPS affordance to enter the device mStatusBarKeyguardViewManager.reset(true); } else if (mState == StatusBarState.KEYGUARD - && !mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing()) { - mStatusBarKeyguardViewManager.showGenericBouncer(true /* scrimmed */); + && !mStatusBarKeyguardViewManager.primaryBouncerIsOrWillBeShowing()) { + mStatusBarKeyguardViewManager.showBouncer(true /* scrimmed */); } } } @@ -3811,7 +3796,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { * is fully hidden, while 0 means the bouncer is visible. */ @Override - public void setBouncerHiddenFraction(float expansion) { + public void setPrimaryBouncerHiddenFraction(float expansion) { mScrimController.setBouncerHiddenFraction(expansion); } @@ -3833,7 +3818,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { mNotificationPanelViewController.isLaunchingAffordanceWithPreview(); mScrimController.setLaunchingAffordanceWithPreview(launchingAffordanceWithPreview); - if (mStatusBarKeyguardViewManager.isShowingAlternateAuth()) { + if (mStatusBarKeyguardViewManager.isShowingAlternateBouncer()) { if (mState == StatusBarState.SHADE || mState == StatusBarState.SHADE_LOCKED || mTransitionToFullShadeProgress > 0f) { mScrimController.transitionTo(ScrimState.AUTH_SCRIMMED_SHADE); @@ -3844,7 +3829,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { // Bouncer needs the front scrim when it's on top of an activity, // tapping on a notification, editing QS or being dismissed by // FLAG_DISMISS_KEYGUARD_ACTIVITY. - ScrimState state = mStatusBarKeyguardViewManager.bouncerNeedsScrimming() + ScrimState state = mStatusBarKeyguardViewManager.primaryBouncerNeedsScrimming() ? ScrimState.BOUNCER_SCRIMMED : ScrimState.BOUNCER; mScrimController.transitionTo(state); } else if (launchingAffordanceWithPreview) { @@ -4153,7 +4138,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { */ @Override public boolean isBouncerShowingScrimmed() { - return isBouncerShowing() && mStatusBarKeyguardViewManager.bouncerNeedsScrimming(); + return isBouncerShowing() && mStatusBarKeyguardViewManager.primaryBouncerNeedsScrimming(); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java index 38c3f93dc6ad..dcf53271db11 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java @@ -34,6 +34,7 @@ import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener; +import com.android.systemui.shade.ShadeExpansionStateManager; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.provider.OnReorderingAllowedListener; @@ -111,7 +112,8 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, ConfigurationController configurationController, @Main Handler handler, AccessibilityManagerWrapper accessibilityManagerWrapper, - UiEventLogger uiEventLogger) { + UiEventLogger uiEventLogger, + ShadeExpansionStateManager shadeExpansionStateManager) { super(context, logger, handler, accessibilityManagerWrapper, uiEventLogger); Resources resources = mContext.getResources(); mExtensionTime = resources.getInteger(R.integer.ambient_notification_extension_time); @@ -132,6 +134,8 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, updateResources(); } }); + + shadeExpansionStateManager.addFullExpansionListener(this::onShadeExpansionFullyChanged); } public void setAnimationStateHandler(AnimationStateHandler handler) { @@ -220,13 +224,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, mTrackingHeadsUp = trackingHeadsUp; } - /** - * Notify that the status bar panel gets expanded or collapsed. - * - * @param isExpanded True to notify expanded, false to notify collapsed. - * TODO(b/237811427) replace with a listener - */ - public void setIsPanelExpanded(boolean isExpanded) { + private void onShadeExpansionFullyChanged(Boolean isExpanded) { if (isExpanded != mIsExpanded) { mIsExpanded = isExpanded; if (isExpanded) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.kt index 4897c529dd51..78b28d203629 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.kt @@ -23,6 +23,8 @@ import android.view.ViewGroup import android.view.ViewPropertyAnimator import android.view.WindowInsets import android.widget.FrameLayout +import com.android.keyguard.KeyguardUpdateMonitor +import com.android.keyguard.LockIconViewController import com.android.systemui.R import com.android.systemui.keyguard.ui.binder.KeyguardBottomAreaViewBinder import com.android.systemui.keyguard.ui.binder.KeyguardBottomAreaViewBinder.bind @@ -51,13 +53,20 @@ constructor( private var ambientIndicationArea: View? = null private lateinit var binding: KeyguardBottomAreaViewBinder.Binding + private lateinit var lockIconViewController: LockIconViewController /** Initializes the view. */ fun init( viewModel: KeyguardBottomAreaViewModel, falsingManager: FalsingManager, + lockIconViewController: LockIconViewController, ) { - binding = bind(this, viewModel, falsingManager) + binding = bind( + this, + viewModel, + falsingManager, + ) + this.lockIconViewController = lockIconViewController } /** @@ -114,4 +123,29 @@ constructor( } return insets } + + override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) { + super.onLayout(changed, left, top, right, bottom) + findViewById<View>(R.id.ambient_indication_container)?.let { + val (ambientLeft, ambientTop) = it.locationOnScreen + if (binding.shouldConstrainToTopOfLockIcon()) { + //make top of ambient indication view the bottom of the lock icon + it.layout( + ambientLeft, + lockIconViewController.bottom.toInt(), + right - ambientLeft, + ambientTop + it.measuredHeight + ) + } else { + //make bottom of ambient indication view the top of the lock icon + val lockLocationTop = lockIconViewController.top + it.layout( + ambientLeft, + lockLocationTop.toInt() - it.measuredHeight, + right - ambientLeft, + lockLocationTop.toInt() + ) + } + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java index b2a9509a03b7..532b8b839fdc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java @@ -55,13 +55,13 @@ import java.util.List; import javax.inject.Inject; /** - * A class which manages the bouncer on the lockscreen. + * A class which manages the primary (pin/pattern/password) bouncer on the lockscreen. * @deprecated Use KeyguardBouncerRepository */ @Deprecated public class KeyguardBouncer { - private static final String TAG = "KeyguardBouncer"; + private static final String TAG = "PrimaryKeyguardBouncer"; static final long BOUNCER_FACE_DELAY = 1200; public static final float ALPHA_EXPANSION_THRESHOLD = 0.95f; /** @@ -78,7 +78,7 @@ public class KeyguardBouncer { private final FalsingCollector mFalsingCollector; private final DismissCallbackRegistry mDismissCallbackRegistry; private final Handler mHandler; - private final List<BouncerExpansionCallback> mExpansionCallbacks = new ArrayList<>(); + private final List<PrimaryBouncerExpansionCallback> mExpansionCallbacks = new ArrayList<>(); private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; private final KeyguardStateController mKeyguardStateController; private final KeyguardSecurityModel mKeyguardSecurityModel; @@ -126,7 +126,7 @@ public class KeyguardBouncer { private KeyguardBouncer(Context context, ViewMediatorCallback callback, ViewGroup container, DismissCallbackRegistry dismissCallbackRegistry, FalsingCollector falsingCollector, - BouncerExpansionCallback expansionCallback, + PrimaryBouncerExpansionCallback expansionCallback, KeyguardStateController keyguardStateController, KeyguardUpdateMonitor keyguardUpdateMonitor, KeyguardBypassController keyguardBypassController, @Main Handler handler, @@ -571,37 +571,37 @@ public class KeyguardBouncer { } private void dispatchFullyShown() { - for (BouncerExpansionCallback callback : mExpansionCallbacks) { + for (PrimaryBouncerExpansionCallback callback : mExpansionCallbacks) { callback.onFullyShown(); } } private void dispatchStartingToHide() { - for (BouncerExpansionCallback callback : mExpansionCallbacks) { + for (PrimaryBouncerExpansionCallback callback : mExpansionCallbacks) { callback.onStartingToHide(); } } private void dispatchStartingToShow() { - for (BouncerExpansionCallback callback : mExpansionCallbacks) { + for (PrimaryBouncerExpansionCallback callback : mExpansionCallbacks) { callback.onStartingToShow(); } } private void dispatchFullyHidden() { - for (BouncerExpansionCallback callback : mExpansionCallbacks) { + for (PrimaryBouncerExpansionCallback callback : mExpansionCallbacks) { callback.onFullyHidden(); } } private void dispatchExpansionChanged() { - for (BouncerExpansionCallback callback : mExpansionCallbacks) { + for (PrimaryBouncerExpansionCallback callback : mExpansionCallbacks) { callback.onExpansionChanged(mExpansion); } } private void dispatchVisibilityChanged() { - for (BouncerExpansionCallback callback : mExpansionCallbacks) { + for (PrimaryBouncerExpansionCallback callback : mExpansionCallbacks) { callback.onVisibilityChanged(mContainer.getVisibility() == View.VISIBLE); } } @@ -647,7 +647,7 @@ public class KeyguardBouncer { /** * Adds a callback to listen to bouncer expansion updates. */ - public void addBouncerExpansionCallback(BouncerExpansionCallback callback) { + public void addBouncerExpansionCallback(PrimaryBouncerExpansionCallback callback) { if (!mExpansionCallbacks.contains(callback)) { mExpansionCallbacks.add(callback); } @@ -657,11 +657,14 @@ public class KeyguardBouncer { * Removes a previously added callback. If the callback was never added, this methood * does nothing. */ - public void removeBouncerExpansionCallback(BouncerExpansionCallback callback) { + public void removeBouncerExpansionCallback(PrimaryBouncerExpansionCallback callback) { mExpansionCallbacks.remove(callback); } - public interface BouncerExpansionCallback { + /** + * Callback updated when the primary bouncer's show and hide states change. + */ + public interface PrimaryBouncerExpansionCallback { /** * Invoked when the bouncer expansion reaches {@link KeyguardBouncer#EXPANSION_VISIBLE}. * This is NOT called each time the bouncer is shown, but rather only when the fully @@ -745,7 +748,7 @@ public class KeyguardBouncer { * Construct a KeyguardBouncer that will exist in the given container. */ public KeyguardBouncer create(ViewGroup container, - BouncerExpansionCallback expansionCallback) { + PrimaryBouncerExpansionCallback expansionCallback) { return new KeyguardBouncer(mContext, mCallback, container, mDismissCallbackRegistry, mFalsingCollector, expansionCallback, mKeyguardStateController, mKeyguardUpdateMonitor, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java index c189acec2930..4ee2de11abdf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java @@ -141,7 +141,6 @@ public class NotificationIconContainer extends ViewGroup { /* Maximum number of icons in short shelf on lockscreen when also showing overflow dot. */ public static final int MAX_ICONS_ON_LOCKSCREEN = 3; public static final int MAX_STATIC_ICONS = 4; - private static final int MAX_DOTS = 1; private boolean mIsStaticLayout = true; private final HashMap<View, IconState> mIconStates = new HashMap<>(); @@ -166,8 +165,7 @@ public class NotificationIconContainer extends ViewGroup { private IconState mLastVisibleIconState; private IconState mFirstVisibleIconState; private float mVisualOverflowStart; - // Keep track of overflow in range [0, 3] - private int mNumDots; + private boolean mIsShowingOverflowDot; private StatusBarIconView mIsolatedIcon; private Rect mIsolatedIconLocation; private int[] mAbsolutePosition = new int[2]; @@ -387,8 +385,8 @@ public class NotificationIconContainer extends ViewGroup { } } - public boolean hasMaxNumDot() { - return mNumDots >= MAX_DOTS; + public boolean areIconsOverflowing() { + return mIsShowingOverflowDot; } private boolean areAnimationsEnabled(StatusBarIconView icon) { @@ -494,7 +492,7 @@ public class NotificationIconContainer extends ViewGroup { : 1f; translationX += iconState.iconAppearAmount * view.getWidth() * drawingScale; } - mNumDots = 0; + mIsShowingOverflowDot = false; if (firstOverflowIndex != -1) { translationX = mVisualOverflowStart; for (int i = firstOverflowIndex; i < childCount; i++) { @@ -502,15 +500,14 @@ public class NotificationIconContainer extends ViewGroup { IconState iconState = mIconStates.get(view); int dotWidth = mStaticDotDiameter + mDotPadding; iconState.setXTranslation(translationX); - if (mNumDots < MAX_DOTS) { - if (mNumDots == 0 && iconState.iconAppearAmount < 0.8f) { + if (!mIsShowingOverflowDot) { + if (iconState.iconAppearAmount < 0.8f) { iconState.visibleState = StatusBarIconView.STATE_ICON; } else { iconState.visibleState = StatusBarIconView.STATE_DOT; - mNumDots++; + mIsShowingOverflowDot = true; } - translationX += (mNumDots == MAX_DOTS ? MAX_DOTS * dotWidth : dotWidth) - * iconState.iconAppearAmount; + translationX += dotWidth * iconState.iconAppearAmount; mLastVisibleIconState = iconState; } else { iconState.visibleState = StatusBarIconView.STATE_HIDDEN; @@ -618,10 +615,6 @@ public class NotificationIconContainer extends ViewGroup { return Math.min(getWidth(), translation); } - private float getMaxOverflowStart() { - return getLayoutEnd() - mIconSize; - } - public void setChangingViewPositions(boolean changingViewPositions) { mChangingViewPositions = changingViewPositions; } @@ -645,25 +638,6 @@ public class NotificationIconContainer extends ViewGroup { mSpeedBumpIndex = speedBumpIndex; } - public boolean hasOverflow() { - return mNumDots > 0; - } - - // Give some extra room for btw notifications if we can - public int getNoOverflowExtraPadding() { - if (mNumDots != 0) { - return 0; - } - - int collapsedPadding = mIconSize; - - if (collapsedPadding + getFinalTranslationX() > getWidth()) { - collapsedPadding = getWidth() - getFinalTranslationX(); - } - - return collapsedPadding; - } - public int getIconSize() { return mIconSize; } 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 cf3a48cf5000..86e27aba65f0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -820,15 +820,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump mNotificationsAlpha = KEYGUARD_SCRIM_ALPHA; } } else if (mState == ScrimState.AUTH_SCRIMMED_SHADE) { - float behindFraction = getInterpolatedFraction(); - behindFraction = (float) Math.pow(behindFraction, 0.8f); - - mBehindAlpha = behindFraction * mDefaultScrimAlpha; - mNotificationsAlpha = mBehindAlpha; - if (mClipsQsScrim) { - mBehindAlpha = 1; - mBehindTint = Color.BLACK; - } + mNotificationsAlpha = (float) Math.pow(getInterpolatedFraction(), 0.8f); } else if (mState == ScrimState.KEYGUARD || mState == ScrimState.SHADE_LOCKED || mState == ScrimState.PULSING) { Pair<Integer, Float> result = calculateBackStateForState(mState); @@ -921,7 +913,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump if (mQsExpansion > 0) { behindAlpha = MathUtils.lerp(behindAlpha, mDefaultScrimAlpha, mQsExpansion); float tintProgress = mQsExpansion; - if (mStatusBarKeyguardViewManager.isBouncerInTransit()) { + if (mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit()) { // this is case of - on lockscreen - going from expanded QS to bouncer. // Because mQsExpansion is already interpolated and transition between tints // is too slow, we want to speed it up and make it more aligned to bouncer @@ -1104,7 +1096,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump } private float getInterpolatedFraction() { - if (mStatusBarKeyguardViewManager.isBouncerInTransit()) { + if (mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit()) { return BouncerPanelExpansionCalculator .aboutToShowBouncerProgress(mPanelExpansionFraction); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java index b447f0d36c10..52430d33cbf0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java @@ -90,11 +90,14 @@ public enum ScrimState { AUTH_SCRIMMED_SHADE { @Override public void prepare(ScrimState previousState) { - // notif & behind scrim alpha values are determined by ScrimController#applyState + // notif scrim alpha values are determined by ScrimController#applyState // based on the shade expansion mFrontTint = Color.BLACK; mFrontAlpha = .66f; + + mBehindTint = Color.BLACK; + mBehindAlpha = 1f; } }, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHideIconsForBouncerManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHideIconsForBouncerManager.kt index 51131914363d..4d9de09fded4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHideIconsForBouncerManager.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHideIconsForBouncerManager.kt @@ -5,6 +5,7 @@ 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.shade.ShadeExpansionStateManager import com.android.systemui.statusbar.CommandQueue import com.android.systemui.statusbar.window.StatusBarWindowStateController import com.android.systemui.util.concurrency.DelayableExecutor @@ -24,10 +25,11 @@ import javax.inject.Inject */ @SysUISingleton class StatusBarHideIconsForBouncerManager @Inject constructor( - private val commandQueue: CommandQueue, - @Main private val mainExecutor: DelayableExecutor, - statusBarWindowStateController: StatusBarWindowStateController, - dumpManager: DumpManager + private val commandQueue: CommandQueue, + @Main private val mainExecutor: DelayableExecutor, + statusBarWindowStateController: StatusBarWindowStateController, + shadeExpansionStateManager: ShadeExpansionStateManager, + dumpManager: DumpManager ) : Dumpable { // State variables set by external classes. private var panelExpanded: Boolean = false @@ -47,6 +49,12 @@ class StatusBarHideIconsForBouncerManager @Inject constructor( statusBarWindowStateController.addListener { state -> setStatusBarStateAndTriggerUpdate(state) } + shadeExpansionStateManager.addFullExpansionListener { isExpanded -> + if (panelExpanded != isExpanded) { + panelExpanded = isExpanded + updateHideIconsForBouncer(animate = false) + } + } } /** Returns true if the status bar icons should be hidden in the bouncer. */ @@ -63,11 +71,6 @@ class StatusBarHideIconsForBouncerManager @Inject constructor( this.displayId = displayId } - fun setPanelExpandedAndTriggerUpdate(panelExpanded: Boolean) { - this.panelExpanded = panelExpanded - updateHideIconsForBouncer(animate = false) - } - fun setIsOccludedAndTriggerUpdate(isOccluded: Boolean) { this.isOccluded = isOccluded updateHideIconsForBouncer(animate = false) 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 86f6ff850409..0a0ded24ef30 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java @@ -18,6 +18,7 @@ import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_ICON import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_MOBILE; import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_MOBILE_NEW; import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_WIFI; +import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_WIFI_NEW; import android.annotation.Nullable; import android.content.Context; @@ -53,8 +54,9 @@ import com.android.systemui.statusbar.pipeline.mobile.ui.MobileUiAdapter; import com.android.systemui.statusbar.pipeline.mobile.ui.binder.MobileIconsBinder; 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.WifiUiAdapter; import com.android.systemui.statusbar.pipeline.wifi.ui.view.ModernStatusBarWifiView; -import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.WifiViewModel; +import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.LocationBasedWifiViewModel; import com.android.systemui.util.Assert; import java.util.ArrayList; @@ -84,7 +86,18 @@ public interface StatusBarIconController { /** */ void setIcon(String slot, StatusBarIcon icon); /** */ - void setSignalIcon(String slot, WifiIconState state); + void setWifiIcon(String slot, WifiIconState state); + + /** + * Sets up a wifi icon using the new data pipeline. No effect if the wifi icon has already been + * set up (inflated and added to the view hierarchy). + * + * This method completely replaces {@link #setWifiIcon} with the information from the new wifi + * data pipeline. Icons will automatically keep their state up to date, so we don't have to + * worry about funneling state objects through anymore. + */ + void setNewWifiIcon(); + /** */ void setMobileIcons(String slot, List<MobileIconState> states); @@ -151,14 +164,14 @@ public interface StatusBarIconController { LinearLayout linearLayout, StatusBarLocation location, StatusBarPipelineFlags statusBarPipelineFlags, - WifiViewModel wifiViewModel, + WifiUiAdapter wifiUiAdapter, MobileUiAdapter mobileUiAdapter, MobileContextProvider mobileContextProvider, DarkIconDispatcher darkIconDispatcher) { super(linearLayout, location, statusBarPipelineFlags, - wifiViewModel, + wifiUiAdapter, mobileUiAdapter, mobileContextProvider); mIconHPadding = mContext.getResources().getDimensionPixelSize( @@ -218,7 +231,7 @@ public interface StatusBarIconController { @SysUISingleton public static class Factory { private final StatusBarPipelineFlags mStatusBarPipelineFlags; - private final WifiViewModel mWifiViewModel; + private final WifiUiAdapter mWifiUiAdapter; private final MobileContextProvider mMobileContextProvider; private final MobileUiAdapter mMobileUiAdapter; private final DarkIconDispatcher mDarkIconDispatcher; @@ -226,12 +239,12 @@ public interface StatusBarIconController { @Inject public Factory( StatusBarPipelineFlags statusBarPipelineFlags, - WifiViewModel wifiViewModel, + WifiUiAdapter wifiUiAdapter, MobileContextProvider mobileContextProvider, MobileUiAdapter mobileUiAdapter, DarkIconDispatcher darkIconDispatcher) { mStatusBarPipelineFlags = statusBarPipelineFlags; - mWifiViewModel = wifiViewModel; + mWifiUiAdapter = wifiUiAdapter; mMobileContextProvider = mobileContextProvider; mMobileUiAdapter = mobileUiAdapter; mDarkIconDispatcher = darkIconDispatcher; @@ -242,7 +255,7 @@ public interface StatusBarIconController { group, location, mStatusBarPipelineFlags, - mWifiViewModel, + mWifiUiAdapter, mMobileUiAdapter, mMobileContextProvider, mDarkIconDispatcher); @@ -260,14 +273,14 @@ public interface StatusBarIconController { ViewGroup group, StatusBarLocation location, StatusBarPipelineFlags statusBarPipelineFlags, - WifiViewModel wifiViewModel, + WifiUiAdapter wifiUiAdapter, MobileUiAdapter mobileUiAdapter, MobileContextProvider mobileContextProvider ) { super(group, location, statusBarPipelineFlags, - wifiViewModel, + wifiUiAdapter, mobileUiAdapter, mobileContextProvider); } @@ -302,19 +315,19 @@ public interface StatusBarIconController { @SysUISingleton public static class Factory { private final StatusBarPipelineFlags mStatusBarPipelineFlags; - private final WifiViewModel mWifiViewModel; + private final WifiUiAdapter mWifiUiAdapter; private final MobileContextProvider mMobileContextProvider; private final MobileUiAdapter mMobileUiAdapter; @Inject public Factory( StatusBarPipelineFlags statusBarPipelineFlags, - WifiViewModel wifiViewModel, + WifiUiAdapter wifiUiAdapter, MobileUiAdapter mobileUiAdapter, MobileContextProvider mobileContextProvider ) { mStatusBarPipelineFlags = statusBarPipelineFlags; - mWifiViewModel = wifiViewModel; + mWifiUiAdapter = wifiUiAdapter; mMobileUiAdapter = mobileUiAdapter; mMobileContextProvider = mobileContextProvider; } @@ -324,7 +337,7 @@ public interface StatusBarIconController { group, location, mStatusBarPipelineFlags, - mWifiViewModel, + mWifiUiAdapter, mMobileUiAdapter, mMobileContextProvider); } @@ -336,10 +349,9 @@ public interface StatusBarIconController { */ class IconManager implements DemoModeCommandReceiver { protected final ViewGroup mGroup; - private final StatusBarLocation mLocation; private final StatusBarPipelineFlags mStatusBarPipelineFlags; - private final WifiViewModel mWifiViewModel; private final MobileContextProvider mMobileContextProvider; + private final LocationBasedWifiViewModel mWifiViewModel; private final MobileIconsViewModel mMobileIconsViewModel; protected final Context mContext; @@ -359,26 +371,33 @@ public interface StatusBarIconController { ViewGroup group, StatusBarLocation location, StatusBarPipelineFlags statusBarPipelineFlags, - WifiViewModel wifiViewModel, + WifiUiAdapter wifiUiAdapter, MobileUiAdapter mobileUiAdapter, MobileContextProvider mobileContextProvider ) { mGroup = group; - mLocation = location; mStatusBarPipelineFlags = statusBarPipelineFlags; - mWifiViewModel = wifiViewModel; mMobileContextProvider = mobileContextProvider; mContext = group.getContext(); mIconSize = mContext.getResources().getDimensionPixelSize( com.android.internal.R.dimen.status_bar_icon_size); - if (statusBarPipelineFlags.useNewMobileIcons()) { - // This starts the flow for the new pipeline, and will notify us of changes + if (statusBarPipelineFlags.runNewMobileIconsBackend()) { + // This starts the flow for the new pipeline, and will notify us of changes if + // {@link StatusBarPipelineFlags#useNewMobileIcons} is also true. mMobileIconsViewModel = mobileUiAdapter.createMobileIconsViewModel(); MobileIconsBinder.bind(mGroup, mMobileIconsViewModel); } else { mMobileIconsViewModel = null; } + + if (statusBarPipelineFlags.runNewWifiIconBackend()) { + // This starts the flow for the new pipeline, and will notify us of changes if + // {@link StatusBarPipelineFlags#useNewWifiIcon} is also true. + mWifiViewModel = wifiUiAdapter.bindGroup(mGroup, location); + } else { + mWifiViewModel = null; + } } public boolean isDemoable() { @@ -429,6 +448,9 @@ public interface StatusBarIconController { case TYPE_WIFI: return addWifiIcon(index, slot, holder.getWifiState()); + case TYPE_WIFI_NEW: + return addNewWifiIcon(index, slot); + case TYPE_MOBILE: return addMobileIcon(index, slot, holder.getMobileState()); @@ -450,16 +472,13 @@ public interface StatusBarIconController { @VisibleForTesting protected StatusIconDisplayable addWifiIcon(int index, String slot, WifiIconState state) { - final BaseStatusBarFrameLayout view; if (mStatusBarPipelineFlags.useNewWifiIcon()) { - view = onCreateModernStatusBarWifiView(slot); - // When [ModernStatusBarWifiView] is created, it will automatically apply the - // correct view state so we don't need to call applyWifiState. - } else { - StatusBarWifiView wifiView = onCreateStatusBarWifiView(slot); - wifiView.applyWifiState(state); - view = wifiView; + throw new IllegalStateException("Attempting to add a mobile icon while the new " + + "icons are enabled is not supported"); } + + final StatusBarWifiView view = onCreateStatusBarWifiView(slot); + view.applyWifiState(state); mGroup.addView(view, index, onCreateLayoutParams()); if (mIsInDemoMode) { @@ -468,6 +487,17 @@ public interface StatusBarIconController { return view; } + protected StatusIconDisplayable addNewWifiIcon(int index, String slot) { + if (!mStatusBarPipelineFlags.useNewWifiIcon()) { + throw new IllegalStateException("Attempting to add a wifi icon using the new" + + "pipeline, but the enabled flag is false."); + } + + ModernStatusBarWifiView view = onCreateModernStatusBarWifiView(slot); + mGroup.addView(view, index, onCreateLayoutParams()); + return view; + } + @VisibleForTesting protected StatusIconDisplayable addMobileIcon( int index, @@ -523,8 +553,7 @@ public interface StatusBarIconController { } private ModernStatusBarWifiView onCreateModernStatusBarWifiView(String slot) { - return ModernStatusBarWifiView.constructAndBind( - mContext, slot, mWifiViewModel, mLocation); + return ModernStatusBarWifiView.constructAndBind(mContext, slot, mWifiViewModel); } private StatusBarMobileView onCreateStatusBarMobileView(int subId, String slot) { @@ -600,7 +629,8 @@ public interface StatusBarIconController { onSetMobileIcon(viewIndex, holder.getMobileState()); return; case TYPE_MOBILE_NEW: - // Nothing, the icon updates itself now + case TYPE_WIFI_NEW: + // Nothing, the new icons update themselves return; default: break; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java index 31e960ad7d69..674e5747e331 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java @@ -195,12 +195,13 @@ public class StatusBarIconControllerImpl implements Tunable, } } - /** - * Signal icons need to be handled differently, because they can be - * composite views - */ @Override - public void setSignalIcon(String slot, WifiIconState state) { + public void setWifiIcon(String slot, WifiIconState state) { + if (mStatusBarPipelineFlags.useNewWifiIcon()) { + Log.d(TAG, "ignoring old pipeline callback because the new wifi icon is enabled"); + return; + } + if (state == null) { removeIcon(slot, 0); return; @@ -216,6 +217,24 @@ public class StatusBarIconControllerImpl implements Tunable, } } + + @Override + public void setNewWifiIcon() { + if (!mStatusBarPipelineFlags.useNewWifiIcon()) { + Log.d(TAG, "ignoring new pipeline callback because the new wifi icon is disabled"); + return; + } + + String slot = mContext.getString(com.android.internal.R.string.status_bar_wifi); + StatusBarIconHolder holder = mStatusBarIconList.getIconHolder(slot, /* tag= */ 0); + if (holder == null) { + holder = StatusBarIconHolder.forNewWifiIcon(); + setIcon(slot, holder); + } else { + // Don't have to do anything in the new world + } + } + /** * Accept a list of MobileIconStates, which all live in the same slot(?!), and then are sorted * by subId. Don't worry this definitely makes sense and works. @@ -225,7 +244,7 @@ public class StatusBarIconControllerImpl implements Tunable, @Override public void setMobileIcons(String slot, List<MobileIconState> iconStates) { if (mStatusBarPipelineFlags.useNewMobileIcons()) { - Log.d(TAG, "ignoring old pipeline callbacks, because the new " + Log.d(TAG, "ignoring old pipeline callbacks, because the new mobile " + "icons are enabled"); return; } @@ -251,10 +270,11 @@ public class StatusBarIconControllerImpl implements Tunable, public void setNewMobileIconSubIds(List<Integer> subIds) { if (!mStatusBarPipelineFlags.useNewMobileIcons()) { Log.d(TAG, "ignoring new pipeline callback, " - + "since the new icons are disabled"); + + "since the new mobile icons are disabled"); return; } - Slot mobileSlot = mStatusBarIconList.getSlot("mobile"); + String slotName = mContext.getString(com.android.internal.R.string.status_bar_mobile); + Slot mobileSlot = mStatusBarIconList.getSlot(slotName); Collections.reverse(subIds); @@ -262,7 +282,7 @@ public class StatusBarIconControllerImpl implements Tunable, StatusBarIconHolder holder = mobileSlot.getHolderForTag(subId); if (holder == null) { holder = StatusBarIconHolder.fromSubIdForModernMobileIcon(subId); - setIcon("mobile", holder); + setIcon(slotName, holder); } else { // Don't have to do anything in the new world } 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 68a203e30f98..f6c0da8da8c0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconHolder.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconHolder.java @@ -51,11 +51,24 @@ public class StatusBarIconHolder { @Deprecated public static final int TYPE_MOBILE_NEW = 3; + /** + * TODO (b/238425913): address this once the new pipeline is in place + * This type exists so that the new wifi pipeline can be used to inform the old view system + * about the existence of the wifi icon. The design of the new pipeline should allow for removal + * of this icon holder type, and obsolete the need for this entire class. + * + * @deprecated This field only exists so the new status bar pipeline can interface with the + * view holder system. + */ + @Deprecated + public static final int TYPE_WIFI_NEW = 4; + @IntDef({ TYPE_ICON, TYPE_WIFI, TYPE_MOBILE, - TYPE_MOBILE_NEW + TYPE_MOBILE_NEW, + TYPE_WIFI_NEW }) @Retention(RetentionPolicy.SOURCE) @interface IconType {} @@ -95,6 +108,13 @@ public class StatusBarIconHolder { return holder; } + /** Creates a new holder with for the new wifi icon. */ + public static StatusBarIconHolder forNewWifiIcon() { + StatusBarIconHolder holder = new StatusBarIconHolder(); + holder.mType = TYPE_WIFI_NEW; + return holder; + } + /** */ public static StatusBarIconHolder fromMobileIconState(MobileIconState state) { StatusBarIconHolder holder = new StatusBarIconHolder(); @@ -172,9 +192,10 @@ public class StatusBarIconHolder { case TYPE_MOBILE: return mMobileState.visible; case TYPE_MOBILE_NEW: - //TODO (b/249790733), the new pipeline can control visibility via the ViewModel + case TYPE_WIFI_NEW: + // The new pipeline controls visibilities via the view model and view binder, so + // this is effectively an unused return value. return true; - default: return true; } @@ -199,7 +220,9 @@ public class StatusBarIconHolder { break; case TYPE_MOBILE_NEW: - //TODO (b/249790733), the new pipeline can control visibility via the ViewModel + case TYPE_WIFI_NEW: + // The new pipeline controls visibilities via the view model and view binder, so + // ignore setVisible. break; } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index a00e75642f55..56fb337e5b4f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -60,8 +60,8 @@ import com.android.systemui.dreams.DreamOverlayStateController; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; import com.android.systemui.keyguard.data.BouncerView; -import com.android.systemui.keyguard.domain.interactor.BouncerCallbackInteractor; -import com.android.systemui.keyguard.domain.interactor.BouncerInteractor; +import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor; +import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor; import com.android.systemui.navigationbar.NavigationBarView; import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.plugins.statusbar.StatusBarStateController; @@ -78,7 +78,7 @@ import com.android.systemui.statusbar.RemoteInputController; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.ViewGroupFadeHelper; -import com.android.systemui.statusbar.phone.KeyguardBouncer.BouncerExpansionCallback; +import com.android.systemui.statusbar.phone.KeyguardBouncer.PrimaryBouncerExpansionCallback; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.unfold.FoldAodAnimationController; @@ -135,62 +135,63 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb @Nullable private final FoldAodAnimationController mFoldAodAnimationController; private KeyguardMessageAreaController<AuthKeyguardMessageArea> mKeyguardMessageAreaController; - private final BouncerCallbackInteractor mBouncerCallbackInteractor; - private final BouncerInteractor mBouncerInteractor; - private final BouncerView mBouncerView; + private final PrimaryBouncerCallbackInteractor mPrimaryBouncerCallbackInteractor; + private final PrimaryBouncerInteractor mPrimaryBouncerInteractor; + private final BouncerView mPrimaryBouncerView; private final Lazy<com.android.systemui.shade.ShadeController> mShadeController; - private final BouncerExpansionCallback mExpansionCallback = new BouncerExpansionCallback() { - private boolean mBouncerAnimating; + private final PrimaryBouncerExpansionCallback mExpansionCallback = + new PrimaryBouncerExpansionCallback() { + private boolean mPrimaryBouncerAnimating; - @Override - public void onFullyShown() { - mBouncerAnimating = false; - updateStates(); - } + @Override + public void onFullyShown() { + mPrimaryBouncerAnimating = false; + updateStates(); + } - @Override - public void onStartingToHide() { - mBouncerAnimating = true; - updateStates(); - } + @Override + public void onStartingToHide() { + mPrimaryBouncerAnimating = true; + updateStates(); + } - @Override - public void onStartingToShow() { - mBouncerAnimating = true; - updateStates(); - } + @Override + public void onStartingToShow() { + mPrimaryBouncerAnimating = true; + updateStates(); + } - @Override - public void onFullyHidden() { - mBouncerAnimating = false; - } + @Override + public void onFullyHidden() { + mPrimaryBouncerAnimating = false; + } - @Override - public void onExpansionChanged(float expansion) { - if (mBouncerAnimating) { - mCentralSurfaces.setBouncerHiddenFraction(expansion); + @Override + public void onExpansionChanged(float expansion) { + if (mPrimaryBouncerAnimating) { + mCentralSurfaces.setPrimaryBouncerHiddenFraction(expansion); + } } - } - @Override - public void onVisibilityChanged(boolean isVisible) { - mCentralSurfaces - .setBouncerShowingOverDream( - isVisible && mDreamOverlayStateController.isOverlayActive()); + @Override + public void onVisibilityChanged(boolean isVisible) { + mCentralSurfaces.setBouncerShowingOverDream( + isVisible && mDreamOverlayStateController.isOverlayActive()); - if (!isVisible) { - mCentralSurfaces.setBouncerHiddenFraction(KeyguardBouncer.EXPANSION_HIDDEN); - } + if (!isVisible) { + mCentralSurfaces.setPrimaryBouncerHiddenFraction( + KeyguardBouncer.EXPANSION_HIDDEN); + } - /* Register predictive back callback when keyguard becomes visible, and unregister - when it's hidden. */ - if (isVisible) { - registerBackCallback(); - } else { - unregisterBackCallback(); + /* Register predictive back callback when keyguard becomes visible, and unregister + when it's hidden. */ + if (isVisible) { + registerBackCallback(); + } else { + unregisterBackCallback(); + } } - } }; private final OnBackInvokedCallback mOnBackInvokedCallback = () -> { @@ -223,7 +224,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb private View mNotificationContainer; - @Nullable protected KeyguardBouncer mBouncer; + @Nullable protected KeyguardBouncer mPrimaryBouncer; protected boolean mRemoteInputActive; private boolean mGlobalActionsVisible = false; private boolean mLastGlobalActionsVisible = false; @@ -236,8 +237,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb protected boolean mFirstUpdate = true; protected boolean mLastShowing; protected boolean mLastOccluded; - private boolean mLastBouncerShowing; - private boolean mLastBouncerIsOrWillBeShowing; + private boolean mLastPrimaryBouncerShowing; + private boolean mLastPrimaryBouncerIsOrWillBeShowing; private boolean mLastBouncerDismissible; protected boolean mLastRemoteInputActive; private boolean mLastDozing; @@ -265,7 +266,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb private final LatencyTracker mLatencyTracker; private final KeyguardSecurityModel mKeyguardSecurityModel; private KeyguardBypassController mBypassController; - @Nullable private AlternateAuthInterceptor mAlternateAuthInterceptor; + @Nullable private AlternateBouncer mAlternateBouncer; private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback = new KeyguardUpdateMonitorCallback() { @@ -300,9 +301,9 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb LatencyTracker latencyTracker, KeyguardSecurityModel keyguardSecurityModel, FeatureFlags featureFlags, - BouncerCallbackInteractor bouncerCallbackInteractor, - BouncerInteractor bouncerInteractor, - BouncerView bouncerView) { + PrimaryBouncerCallbackInteractor primaryBouncerCallbackInteractor, + PrimaryBouncerInteractor primaryBouncerInteractor, + BouncerView primaryBouncerView) { mContext = context; mViewMediatorCallback = callback; mLockPatternUtils = lockPatternUtils; @@ -320,9 +321,9 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mShadeController = shadeController; mLatencyTracker = latencyTracker; mKeyguardSecurityModel = keyguardSecurityModel; - mBouncerCallbackInteractor = bouncerCallbackInteractor; - mBouncerInteractor = bouncerInteractor; - mBouncerView = bouncerView; + mPrimaryBouncerCallbackInteractor = primaryBouncerCallbackInteractor; + mPrimaryBouncerInteractor = primaryBouncerInteractor; + mPrimaryBouncerView = primaryBouncerView; mFoldAodAnimationController = sysUIUnfoldComponent .map(SysUIUnfoldComponent::getFoldAodAnimationController).orElse(null); mIsModernBouncerEnabled = featureFlags.isEnabled(Flags.MODERN_BOUNCER); @@ -340,9 +341,9 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb ViewGroup container = mCentralSurfaces.getBouncerContainer(); if (mIsModernBouncerEnabled) { - mBouncerCallbackInteractor.addBouncerExpansionCallback(mExpansionCallback); + mPrimaryBouncerCallbackInteractor.addBouncerExpansionCallback(mExpansionCallback); } else { - mBouncer = mKeyguardBouncerFactory.create(container, mExpansionCallback); + mPrimaryBouncer = mKeyguardBouncerFactory.create(container, mExpansionCallback); } mNotificationPanelViewController = notificationPanelViewController; if (shadeExpansionStateManager != null) { @@ -361,20 +362,20 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb * Sets the given alt auth interceptor to null if it's the current auth interceptor. Else, * does nothing. */ - public void removeAlternateAuthInterceptor(@NonNull AlternateAuthInterceptor authInterceptor) { - if (Objects.equals(mAlternateAuthInterceptor, authInterceptor)) { - mAlternateAuthInterceptor = null; - resetAlternateAuth(true); + public void removeAlternateAuthInterceptor(@NonNull AlternateBouncer authInterceptor) { + if (Objects.equals(mAlternateBouncer, authInterceptor)) { + mAlternateBouncer = null; + hideAlternateBouncer(true); } } /** * Sets a new alt auth interceptor. */ - public void setAlternateAuthInterceptor(@NonNull AlternateAuthInterceptor authInterceptor) { - if (!Objects.equals(mAlternateAuthInterceptor, authInterceptor)) { - mAlternateAuthInterceptor = authInterceptor; - resetAlternateAuth(false); + public void setAlternateBouncer(@NonNull AlternateBouncer authInterceptor) { + if (!Objects.equals(mAlternateBouncer, authInterceptor)) { + mAlternateBouncer = authInterceptor; + hideAlternateBouncer(false); } } @@ -458,49 +459,48 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb if (mDozing && !mPulsing) { return; } else if (mNotificationPanelViewController.isUnlockHintRunning()) { - if (mBouncer != null) { - mBouncer.setExpansion(KeyguardBouncer.EXPANSION_HIDDEN); + if (mPrimaryBouncer != null) { + mPrimaryBouncer.setExpansion(KeyguardBouncer.EXPANSION_HIDDEN); } else { - mBouncerInteractor.setPanelExpansion(KeyguardBouncer.EXPANSION_HIDDEN); + mPrimaryBouncerInteractor.setPanelExpansion(KeyguardBouncer.EXPANSION_HIDDEN); } } else if (mStatusBarStateController.getState() == StatusBarState.SHADE_LOCKED) { // Don't expand to the bouncer. Instead transition back to the lock screen (see // CentralSurfaces#showBouncerOrLockScreenIfKeyguard) return; - } else if (bouncerNeedsScrimming()) { - if (mBouncer != null) { - mBouncer.setExpansion(KeyguardBouncer.EXPANSION_VISIBLE); + } else if (primaryBouncerNeedsScrimming()) { + if (mPrimaryBouncer != null) { + mPrimaryBouncer.setExpansion(KeyguardBouncer.EXPANSION_VISIBLE); } else { - mBouncerInteractor.setPanelExpansion(KeyguardBouncer.EXPANSION_VISIBLE); + mPrimaryBouncerInteractor.setPanelExpansion(KeyguardBouncer.EXPANSION_VISIBLE); } } else if (mKeyguardStateController.isShowing() && !hideBouncerOverDream) { if (!isWakeAndUnlocking() && !(mBiometricUnlockController.getMode() == MODE_DISMISS_BOUNCER) - && !mNotificationPanelViewController.isLaunchTransitionFinished() && !isUnlockCollapsing()) { - if (mBouncer != null) { - mBouncer.setExpansion(fraction); + if (mPrimaryBouncer != null) { + mPrimaryBouncer.setExpansion(fraction); } else { - mBouncerInteractor.setPanelExpansion(fraction); + mPrimaryBouncerInteractor.setPanelExpansion(fraction); } } if (fraction != KeyguardBouncer.EXPANSION_HIDDEN && tracking && !mKeyguardStateController.canDismissLockScreen() - && !bouncerIsShowing() + && !primaryBouncerIsShowing() && !bouncerIsAnimatingAway()) { - if (mBouncer != null) { - mBouncer.show(false /* resetSecuritySelection */, false /* scrimmed */); + if (mPrimaryBouncer != null) { + mPrimaryBouncer.show(false /* resetSecuritySelection */, false /* scrimmed */); } else { - mBouncerInteractor.show(/* isScrimmed= */false); + mPrimaryBouncerInteractor.show(/* isScrimmed= */false); } } - } else if (!mKeyguardStateController.isShowing() && isBouncerInTransit()) { + } else if (!mKeyguardStateController.isShowing() && isPrimaryBouncerInTransit()) { // Keyguard is not visible anymore, but expansion animation was still running. // We need to hide the bouncer, otherwise it will be stuck in transit. - if (mBouncer != null) { - mBouncer.setExpansion(KeyguardBouncer.EXPANSION_HIDDEN); + if (mPrimaryBouncer != null) { + mPrimaryBouncer.setExpansion(KeyguardBouncer.EXPANSION_HIDDEN); } else { - mBouncerInteractor.setPanelExpansion(KeyguardBouncer.EXPANSION_HIDDEN); + mPrimaryBouncerInteractor.setPanelExpansion(KeyguardBouncer.EXPANSION_HIDDEN); } } else if (mPulsing && fraction == KeyguardBouncer.EXPANSION_VISIBLE) { // Panel expanded while pulsing but didn't translate the bouncer (because we are @@ -544,17 +544,17 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb if (needsFullscreenBouncer() && !mDozing) { // The keyguard might be showing (already). So we need to hide it. mCentralSurfaces.hideKeyguard(); - if (mBouncer != null) { - mBouncer.show(true /* resetSecuritySelection */); + if (mPrimaryBouncer != null) { + mPrimaryBouncer.show(true /* resetSecuritySelection */); } else { - mBouncerInteractor.show(true); + mPrimaryBouncerInteractor.show(true); } } else { mCentralSurfaces.showKeyguard(); if (hideBouncerWhenShowing) { hideBouncer(false /* destroyView */); - if (mBouncer != null) { - mBouncer.prepare(); + if (mPrimaryBouncer != null) { + mPrimaryBouncer.prepare(); } } } @@ -562,23 +562,25 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb } /** - * If applicable, shows the alternate authentication bouncer. Else, shows the input - * (pin/password/pattern) bouncer. - * @param scrimmed true when the input bouncer should show scrimmed, false when the user will be - * dragging it and translation should be deferred {@see KeyguardBouncer#show(boolean, boolean)} + * + * If possible, shows the alternate bouncer. Else, shows the primary (pin/pattern/password) + * bouncer. + * @param scrimmed true when the primary bouncer should show scrimmed, + * false when the user will be dragging it and translation should be deferred + * {@see KeyguardBouncer#show(boolean, boolean)} */ - public void showGenericBouncer(boolean scrimmed) { - if (shouldShowAltAuth()) { - updateAlternateAuthShowing(mAlternateAuthInterceptor.showAlternateAuthBouncer()); + public void showBouncer(boolean scrimmed) { + if (canShowAlternateBouncer()) { + updateAlternateBouncerShowing(mAlternateBouncer.showAlternateBouncer()); return; } - showBouncer(scrimmed); + showPrimaryBouncer(scrimmed); } - /** Whether we should show the alternate authentication instead of the traditional bouncer. */ - public boolean shouldShowAltAuth() { - return mAlternateAuthInterceptor != null + /** Whether we can show the alternate bouncer instead of the primary bouncer. */ + public boolean canShowAlternateBouncer() { + return mAlternateBouncer != null && mKeyguardUpdateManager.isUnlockingWithBiometricAllowed(true); } @@ -587,10 +589,10 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb */ @VisibleForTesting void hideBouncer(boolean destroyView) { - if (mBouncer != null) { - mBouncer.hide(destroyView); + if (mPrimaryBouncer != null) { + mPrimaryBouncer.hide(destroyView); } else { - mBouncerInteractor.hide(); + mPrimaryBouncerInteractor.hide(); } if (mKeyguardStateController.isShowing()) { // If we were showing the bouncer and then aborting, we need to also clear out any @@ -601,19 +603,19 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb } /** - * Shows the keyguard input bouncer - the password challenge on the lock screen + * Shows the primary bouncer - the pin/pattern/password challenge on the lock screen. * * @param scrimmed true when the bouncer should show scrimmed, false when the user will be * dragging it and translation should be deferred {@see KeyguardBouncer#show(boolean, boolean)} */ - public void showBouncer(boolean scrimmed) { - resetAlternateAuth(false); + public void showPrimaryBouncer(boolean scrimmed) { + hideAlternateBouncer(false); if (mKeyguardStateController.isShowing() && !isBouncerShowing()) { - if (mBouncer != null) { - mBouncer.show(false /* resetSecuritySelection */, scrimmed); + if (mPrimaryBouncer != null) { + mPrimaryBouncer.show(false /* resetSecuritySelection */, scrimmed); } else { - mBouncerInteractor.show(scrimmed); + mPrimaryBouncerInteractor.show(scrimmed); } } updateStates(); @@ -645,42 +647,41 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb // If there is an an alternate auth interceptor (like the UDFPS), show that one // instead of the bouncer. - if (shouldShowAltAuth()) { + if (canShowAlternateBouncer()) { if (!afterKeyguardGone) { - if (mBouncer != null) { - mBouncer.setDismissAction(mAfterKeyguardGoneAction, + if (mPrimaryBouncer != null) { + mPrimaryBouncer.setDismissAction(mAfterKeyguardGoneAction, mKeyguardGoneCancelAction); } else { - mBouncerInteractor.setDismissAction(mAfterKeyguardGoneAction, + mPrimaryBouncerInteractor.setDismissAction(mAfterKeyguardGoneAction, mKeyguardGoneCancelAction); } mAfterKeyguardGoneAction = null; mKeyguardGoneCancelAction = null; } - updateAlternateAuthShowing( - mAlternateAuthInterceptor.showAlternateAuthBouncer()); + updateAlternateBouncerShowing(mAlternateBouncer.showAlternateBouncer()); return; } if (afterKeyguardGone) { // we'll handle the dismiss action after keyguard is gone, so just show the // bouncer - if (mBouncer != null) { - mBouncer.show(false /* resetSecuritySelection */); + if (mPrimaryBouncer != null) { + mPrimaryBouncer.show(false /* resetSecuritySelection */); } else { - mBouncerInteractor.show(/* isScrimmed= */true); + mPrimaryBouncerInteractor.show(/* isScrimmed= */true); } } else { // after authentication success, run dismiss action with the option to defer // hiding the keyguard based on the return value of the OnDismissAction - if (mBouncer != null) { - mBouncer.showWithDismissAction(mAfterKeyguardGoneAction, + if (mPrimaryBouncer != null) { + mPrimaryBouncer.showWithDismissAction(mAfterKeyguardGoneAction, mKeyguardGoneCancelAction); } else { - mBouncerInteractor.setDismissAction( + mPrimaryBouncerInteractor.setDismissAction( mAfterKeyguardGoneAction, mKeyguardGoneCancelAction); - mBouncerInteractor.show(/* isScrimmed= */true); + mPrimaryBouncerInteractor.show(/* isScrimmed= */true); } // bouncer will handle the dismiss action, so we no longer need to track it here mAfterKeyguardGoneAction = null; @@ -725,28 +726,28 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb } else { showBouncerOrKeyguard(hideBouncerWhenShowing); } - resetAlternateAuth(false); + hideAlternateBouncer(false); mKeyguardUpdateManager.sendKeyguardReset(); updateStates(); } } @Override - public void resetAlternateAuth(boolean forceUpdateScrim) { - final boolean updateScrim = (mAlternateAuthInterceptor != null - && mAlternateAuthInterceptor.hideAlternateAuthBouncer()) + public void hideAlternateBouncer(boolean forceUpdateScrim) { + final boolean updateScrim = (mAlternateBouncer != null + && mAlternateBouncer.hideAlternateBouncer()) || forceUpdateScrim; - updateAlternateAuthShowing(updateScrim); + updateAlternateBouncerShowing(updateScrim); } - private void updateAlternateAuthShowing(boolean updateScrim) { - final boolean isShowingAltAuth = isShowingAlternateAuth(); + private void updateAlternateBouncerShowing(boolean updateScrim) { + final boolean isShowingAlternateBouncer = isShowingAlternateBouncer(); if (mKeyguardMessageAreaController != null) { - mKeyguardMessageAreaController.setIsVisible(isShowingAltAuth); + mKeyguardMessageAreaController.setIsVisible(isShowingAlternateBouncer); mKeyguardMessageAreaController.setMessage(""); } - mBypassController.setAltBouncerShowing(isShowingAltAuth); - mKeyguardUpdateManager.setUdfpsBouncerShowing(isShowingAltAuth); + mBypassController.setAltBouncerShowing(isShowingAlternateBouncer); + mKeyguardUpdateManager.setUdfpsBouncerShowing(isShowingAlternateBouncer); if (updateScrim) { mCentralSurfaces.updateScrimController(); @@ -783,10 +784,10 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb @Override public void onFinishedGoingToSleep() { - if (mBouncer != null) { - mBouncer.onScreenTurnedOff(); + if (mPrimaryBouncer != null) { + mPrimaryBouncer.onScreenTurnedOff(); } else { - mBouncerInteractor.onScreenTurnedOff(); + mPrimaryBouncerInteractor.onScreenTurnedOff(); } } @@ -845,21 +846,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb if (isShowing && isOccluding) { SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_STATE_CHANGED, SysUiStatsLog.KEYGUARD_STATE_CHANGED__STATE__OCCLUDED); - if (mNotificationPanelViewController.isLaunchTransitionFinished()) { - final Runnable endRunnable = new Runnable() { - @Override - public void run() { - mNotificationShadeWindowController.setKeyguardOccluded(isOccluded); - reset(true /* hideBouncerWhenShowing */); - } - }; - mCentralSurfaces.fadeKeyguardAfterLaunchTransition( - null /* beforeFading */, - endRunnable, - endRunnable); - return; - } - if (mCentralSurfaces.isLaunchingActivityOverLockscreen()) { // When isLaunchingActivityOverLockscreen() is true, we know for sure that the post // collapse runnables will be run. @@ -886,18 +872,18 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb // by a FLAG_DISMISS_KEYGUARD_ACTIVITY. reset(isOccluding /* hideBouncerWhenShowing*/); } - if (animate && !isOccluded && isShowing && !bouncerIsShowing()) { + if (animate && !isOccluded && isShowing && !primaryBouncerIsShowing()) { mCentralSurfaces.animateKeyguardUnoccluding(); } } @Override public void startPreHideAnimation(Runnable finishRunnable) { - if (bouncerIsShowing()) { - if (mBouncer != null) { - mBouncer.startPreHideAnimation(finishRunnable); + if (primaryBouncerIsShowing()) { + if (mPrimaryBouncer != null) { + mPrimaryBouncer.startPreHideAnimation(finishRunnable); } else { - mBouncerInteractor.startDisappearAnimation(finishRunnable); + mPrimaryBouncerInteractor.startDisappearAnimation(finishRunnable); } mNotificationPanelViewController.startBouncerPreHideAnimation(); @@ -931,8 +917,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb long uptimeMillis = SystemClock.uptimeMillis(); long delay = Math.max(0, startTime + HIDE_TIMING_CORRECTION_MS - uptimeMillis); - if (mNotificationPanelViewController.isLaunchTransitionFinished() - || mKeyguardStateController.isFlingingToDismissKeyguard()) { + if (mKeyguardStateController.isFlingingToDismissKeyguard()) { final boolean wasFlingingToDismissKeyguard = mKeyguardStateController.isFlingingToDismissKeyguard(); mCentralSurfaces.fadeKeyguardAfterLaunchTransition(new Runnable() { @@ -1011,13 +996,13 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb updateResources(); return; } - boolean wasShowing = bouncerIsShowing(); - boolean wasScrimmed = bouncerIsScrimmed(); + boolean wasShowing = primaryBouncerIsShowing(); + boolean wasScrimmed = primaryBouncerIsScrimmed(); hideBouncer(true /* destroyView */); - mBouncer.prepare(); + mPrimaryBouncer.prepare(); - if (wasShowing) showBouncer(wasScrimmed); + if (wasShowing) showPrimaryBouncer(wasScrimmed); } public void onKeyguardFadedAway() { @@ -1062,8 +1047,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb * WARNING: This method might cause Binder calls. */ public boolean isSecure() { - if (mBouncer != null) { - return mBouncer.isSecure(); + if (mPrimaryBouncer != null) { + return mPrimaryBouncer.isSecure(); } return mKeyguardSecurityModel.getSecurityMode( @@ -1077,7 +1062,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb * @return whether a back press can be handled right now. */ public boolean canHandleBackPressed() { - return bouncerIsShowing(); + return primaryBouncerIsShowing(); } /** @@ -1090,7 +1075,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mCentralSurfaces.endAffordanceLaunch(); // The second condition is for SIM card locked bouncer - if (bouncerIsScrimmed() && !needsFullscreenBouncer()) { + if (primaryBouncerIsScrimmed() && !needsFullscreenBouncer()) { hideBouncer(false); updateStates(); } else { @@ -1111,27 +1096,27 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb @Override public boolean isBouncerShowing() { - return bouncerIsShowing() || isShowingAlternateAuth(); + return primaryBouncerIsShowing() || isShowingAlternateBouncer(); } @Override - public boolean bouncerIsOrWillBeShowing() { - return isBouncerShowing() || isBouncerInTransit(); + public boolean primaryBouncerIsOrWillBeShowing() { + return isBouncerShowing() || isPrimaryBouncerInTransit(); } public boolean isFullscreenBouncer() { - if (mBouncerView.getDelegate() != null) { - return mBouncerView.getDelegate().isFullScreenBouncer(); + if (mPrimaryBouncerView.getDelegate() != null) { + return mPrimaryBouncerView.getDelegate().isFullScreenBouncer(); } - return mBouncer != null && mBouncer.isFullscreenBouncer(); + return mPrimaryBouncer != null && mPrimaryBouncer.isFullscreenBouncer(); } /** * Clear out any potential actions that were saved to run when the device is unlocked */ public void cancelPostAuthActions() { - if (bouncerIsOrWillBeShowing()) { - return; // allow bouncer to trigger saved actions + if (primaryBouncerIsOrWillBeShowing()) { + return; // allow the primary bouncer to trigger saved actions } mAfterKeyguardGoneAction = null; mDismissActionWillAnimateOnKeyguard = false; @@ -1170,25 +1155,25 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb } boolean showing = mKeyguardStateController.isShowing(); boolean occluded = mKeyguardStateController.isOccluded(); - boolean bouncerShowing = bouncerIsShowing(); - boolean bouncerIsOrWillBeShowing = bouncerIsOrWillBeShowing(); - boolean bouncerDismissible = !isFullscreenBouncer(); + boolean primaryBouncerShowing = primaryBouncerIsShowing(); + boolean primaryBouncerIsOrWillBeShowing = primaryBouncerIsOrWillBeShowing(); + boolean primaryBouncerDismissible = !isFullscreenBouncer(); boolean remoteInputActive = mRemoteInputActive; - if ((bouncerDismissible || !showing || remoteInputActive) != - (mLastBouncerDismissible || !mLastShowing || mLastRemoteInputActive) + if ((primaryBouncerDismissible || !showing || remoteInputActive) + != (mLastBouncerDismissible || !mLastShowing || mLastRemoteInputActive) || mFirstUpdate) { - if (bouncerDismissible || !showing || remoteInputActive) { - if (mBouncer != null) { - mBouncer.setBackButtonEnabled(true); + if (primaryBouncerDismissible || !showing || remoteInputActive) { + if (mPrimaryBouncer != null) { + mPrimaryBouncer.setBackButtonEnabled(true); } else { - mBouncerInteractor.setBackButtonEnabled(true); + mPrimaryBouncerInteractor.setBackButtonEnabled(true); } } else { - if (mBouncer != null) { - mBouncer.setBackButtonEnabled(false); + if (mPrimaryBouncer != null) { + mPrimaryBouncer.setBackButtonEnabled(false); } else { - mBouncerInteractor.setBackButtonEnabled(false); + mPrimaryBouncerInteractor.setBackButtonEnabled(false); } } } @@ -1199,23 +1184,23 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb updateNavigationBarVisibility(navBarVisible); } - if (bouncerShowing != mLastBouncerShowing || mFirstUpdate) { - mNotificationShadeWindowController.setBouncerShowing(bouncerShowing); - mCentralSurfaces.setBouncerShowing(bouncerShowing); + if (primaryBouncerShowing != mLastPrimaryBouncerShowing || mFirstUpdate) { + mNotificationShadeWindowController.setBouncerShowing(primaryBouncerShowing); + mCentralSurfaces.setBouncerShowing(primaryBouncerShowing); } - if (bouncerIsOrWillBeShowing != mLastBouncerIsOrWillBeShowing || mFirstUpdate - || bouncerShowing != mLastBouncerShowing) { - mKeyguardUpdateManager.sendKeyguardBouncerChanged(bouncerIsOrWillBeShowing, - bouncerShowing); + if (primaryBouncerIsOrWillBeShowing != mLastPrimaryBouncerIsOrWillBeShowing || mFirstUpdate + || primaryBouncerShowing != mLastPrimaryBouncerShowing) { + mKeyguardUpdateManager.sendPrimaryBouncerChanged(primaryBouncerIsOrWillBeShowing, + primaryBouncerShowing); } mFirstUpdate = false; mLastShowing = showing; mLastGlobalActionsVisible = mGlobalActionsVisible; mLastOccluded = occluded; - mLastBouncerShowing = bouncerShowing; - mLastBouncerIsOrWillBeShowing = bouncerIsOrWillBeShowing; - mLastBouncerDismissible = bouncerDismissible; + mLastPrimaryBouncerShowing = primaryBouncerShowing; + mLastPrimaryBouncerIsOrWillBeShowing = primaryBouncerIsOrWillBeShowing; + mLastBouncerDismissible = primaryBouncerDismissible; mLastRemoteInputActive = remoteInputActive; mLastDozing = mDozing; mLastPulsing = mPulsing; @@ -1259,7 +1244,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb || mPulsing && !mIsDocked) && mGesturalNav; return (!keyguardVisible && !hideWhileDozing && !mScreenOffAnimationPlaying - || bouncerIsShowing() + || primaryBouncerIsShowing() || mRemoteInputActive || keyguardWithGestureNav || mGlobalActionsVisible); @@ -1275,32 +1260,32 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb && !mLastScreenOffAnimationPlaying || mLastPulsing && !mLastIsDocked) && mLastGesturalNav; return (!keyguardShowing && !hideWhileDozing && !mLastScreenOffAnimationPlaying - || mLastBouncerShowing || mLastRemoteInputActive || keyguardWithGestureNav + || mLastPrimaryBouncerShowing || mLastRemoteInputActive || keyguardWithGestureNav || mLastGlobalActionsVisible); } public boolean shouldDismissOnMenuPressed() { - if (mBouncerView.getDelegate() != null) { - return mBouncerView.getDelegate().shouldDismissOnMenuPressed(); + if (mPrimaryBouncerView.getDelegate() != null) { + return mPrimaryBouncerView.getDelegate().shouldDismissOnMenuPressed(); } - return mBouncer != null && mBouncer.shouldDismissOnMenuPressed(); + return mPrimaryBouncer != null && mPrimaryBouncer.shouldDismissOnMenuPressed(); } public boolean interceptMediaKey(KeyEvent event) { - if (mBouncerView.getDelegate() != null) { - return mBouncerView.getDelegate().interceptMediaKey(event); + if (mPrimaryBouncerView.getDelegate() != null) { + return mPrimaryBouncerView.getDelegate().interceptMediaKey(event); } - return mBouncer != null && mBouncer.interceptMediaKey(event); + return mPrimaryBouncer != null && mPrimaryBouncer.interceptMediaKey(event); } /** * @return true if the pre IME back event should be handled */ public boolean dispatchBackKeyEventPreIme() { - if (mBouncerView.getDelegate() != null) { - return mBouncerView.getDelegate().dispatchBackKeyEventPreIme(); + if (mPrimaryBouncerView.getDelegate() != null) { + return mPrimaryBouncerView.getDelegate().dispatchBackKeyEventPreIme(); } - return mBouncer != null && mBouncer.dispatchBackKeyEventPreIme(); + return mPrimaryBouncer != null && mPrimaryBouncer.dispatchBackKeyEventPreIme(); } public void readyForKeyguardDone() { @@ -1309,7 +1294,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb @Override public boolean shouldDisableWindowAnimationsForUnlock() { - return mNotificationPanelViewController.isLaunchTransitionFinished(); + return false; } @Override @@ -1346,29 +1331,29 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb * fingerprint. */ public void notifyKeyguardAuthenticated(boolean strongAuth) { - if (mBouncer != null) { - mBouncer.notifyKeyguardAuthenticated(strongAuth); + if (mPrimaryBouncer != null) { + mPrimaryBouncer.notifyKeyguardAuthenticated(strongAuth); } else { - mBouncerInteractor.notifyKeyguardAuthenticated(strongAuth); + mPrimaryBouncerInteractor.notifyKeyguardAuthenticated(strongAuth); } - if (mAlternateAuthInterceptor != null && isShowingAlternateAuth()) { - resetAlternateAuth(false); + if (mAlternateBouncer != null && isShowingAlternateBouncer()) { + hideAlternateBouncer(false); executeAfterKeyguardGoneAction(); } } /** Display security message to relevant KeyguardMessageArea. */ public void setKeyguardMessage(String message, ColorStateList colorState) { - if (isShowingAlternateAuth()) { + if (isShowingAlternateBouncer()) { if (mKeyguardMessageAreaController != null) { mKeyguardMessageAreaController.setMessage(message); } } else { - if (mBouncer != null) { - mBouncer.showMessage(message, colorState); + if (mPrimaryBouncer != null) { + mPrimaryBouncer.showMessage(message, colorState); } else { - mBouncerInteractor.showMessage(message, colorState); + mPrimaryBouncerInteractor.showMessage(message, colorState); } } } @@ -1407,12 +1392,15 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb } } - public boolean bouncerNeedsScrimming() { + /** + * Whether the primary bouncer requires scrimming. + */ + public boolean primaryBouncerNeedsScrimming() { // When a dream overlay is active, scrimming will cause any expansion to immediately expand. return (mKeyguardStateController.isOccluded() && !mDreamOverlayStateController.isOverlayActive()) - || bouncerWillDismissWithAction() - || (bouncerIsShowing() && bouncerIsScrimmed()) + || primaryBouncerWillDismissWithAction() + || (primaryBouncerIsShowing() && primaryBouncerIsScrimmed()) || isFullscreenBouncer(); } @@ -1422,10 +1410,10 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb * configuration. */ public void updateResources() { - if (mBouncer != null) { - mBouncer.updateResources(); + if (mPrimaryBouncer != null) { + mPrimaryBouncer.updateResources(); } else { - mBouncerInteractor.updateResources(); + mPrimaryBouncerInteractor.updateResources(); } } @@ -1437,19 +1425,20 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb pw.println(" mAfterKeyguardGoneRunnables: " + mAfterKeyguardGoneRunnables); pw.println(" mPendingWakeupAction: " + mPendingWakeupAction); pw.println(" isBouncerShowing(): " + isBouncerShowing()); - pw.println(" bouncerIsOrWillBeShowing(): " + bouncerIsOrWillBeShowing()); + pw.println(" bouncerIsOrWillBeShowing(): " + primaryBouncerIsOrWillBeShowing()); pw.println(" Registered KeyguardViewManagerCallbacks:"); for (KeyguardViewManagerCallback callback : mCallbacks) { pw.println(" " + callback); } - if (mBouncer != null) { - mBouncer.dump(pw); + if (mPrimaryBouncer != null) { + pw.println("PrimaryBouncer:"); + mPrimaryBouncer.dump(pw); } - if (mAlternateAuthInterceptor != null) { - pw.println("AltAuthInterceptor: "); - mAlternateAuthInterceptor.dump(pw); + if (mAlternateBouncer != null) { + pw.println("AlternateBouncer:"); + mAlternateBouncer.dump(pw); } } @@ -1497,13 +1486,12 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb } @Nullable - public KeyguardBouncer getBouncer() { - return mBouncer; + public KeyguardBouncer getPrimaryBouncer() { + return mPrimaryBouncer; } - public boolean isShowingAlternateAuth() { - return mAlternateAuthInterceptor != null - && mAlternateAuthInterceptor.isShowingAlternateAuthBouncer(); + public boolean isShowingAlternateBouncer() { + return mAlternateBouncer != null && mAlternateBouncer.isShowingAlternateBouncer(); } /** @@ -1517,10 +1505,10 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb /** Update keyguard position based on a tapped X coordinate. */ public void updateKeyguardPosition(float x) { - if (mBouncer != null) { - mBouncer.updateKeyguardPosition(x); + if (mPrimaryBouncer != null) { + mPrimaryBouncer.updateKeyguardPosition(x); } else { - mBouncerInteractor.setKeyguardPosition(x); + mPrimaryBouncerInteractor.setKeyguardPosition(x); } } @@ -1552,41 +1540,41 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb */ public void requestFp(boolean request, int udfpsColor) { mKeyguardUpdateManager.requestFingerprintAuthOnOccludingApp(request); - if (mAlternateAuthInterceptor != null) { - mAlternateAuthInterceptor.requestUdfps(request, udfpsColor); + if (mAlternateBouncer != null) { + mAlternateBouncer.requestUdfps(request, udfpsColor); } } /** * Returns if bouncer expansion is between 0 and 1 non-inclusive. */ - public boolean isBouncerInTransit() { - if (mBouncer != null) { - return mBouncer.inTransit(); + public boolean isPrimaryBouncerInTransit() { + if (mPrimaryBouncer != null) { + return mPrimaryBouncer.inTransit(); } else { - return mBouncerInteractor.isInTransit(); + return mPrimaryBouncerInteractor.isInTransit(); } } /** * Returns if bouncer is showing */ - public boolean bouncerIsShowing() { - if (mBouncer != null) { - return mBouncer.isShowing(); + public boolean primaryBouncerIsShowing() { + if (mPrimaryBouncer != null) { + return mPrimaryBouncer.isShowing(); } else { - return mBouncerInteractor.isFullyShowing(); + return mPrimaryBouncerInteractor.isFullyShowing(); } } /** * Returns if bouncer is scrimmed */ - public boolean bouncerIsScrimmed() { - if (mBouncer != null) { - return mBouncer.isScrimmed(); + public boolean primaryBouncerIsScrimmed() { + if (mPrimaryBouncer != null) { + return mPrimaryBouncer.isScrimmed(); } else { - return mBouncerInteractor.isScrimmed(); + return mPrimaryBouncerInteractor.isScrimmed(); } } @@ -1594,10 +1582,10 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb * Returns if bouncer is animating away */ public boolean bouncerIsAnimatingAway() { - if (mBouncer != null) { - return mBouncer.isAnimatingAway(); + if (mPrimaryBouncer != null) { + return mPrimaryBouncer.isAnimatingAway(); } else { - return mBouncerInteractor.isAnimatingAway(); + return mPrimaryBouncerInteractor.isAnimatingAway(); } } @@ -1605,11 +1593,11 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb /** * Returns if bouncer will dismiss with action */ - public boolean bouncerWillDismissWithAction() { - if (mBouncer != null) { - return mBouncer.willDismissWithAction(); + public boolean primaryBouncerWillDismissWithAction() { + if (mPrimaryBouncer != null) { + return mPrimaryBouncer.willDismissWithAction(); } else { - return mBouncerInteractor.willDismissWithAction(); + return mPrimaryBouncerInteractor.willDismissWithAction(); } } @@ -1624,26 +1612,26 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb } /** - * Delegate used to send show/reset events to an alternate authentication method instead of the - * regular pin/pattern/password bouncer. + * Delegate used to send show and hide events to an alternate authentication method instead of + * the regular pin/pattern/password bouncer. */ - public interface AlternateAuthInterceptor { + public interface AlternateBouncer { /** * Show alternate authentication bouncer. * @return whether alternate auth method was newly shown */ - boolean showAlternateAuthBouncer(); + boolean showAlternateBouncer(); /** * Hide alternate authentication bouncer * @return whether the alternate auth method was newly hidden */ - boolean hideAlternateAuthBouncer(); + boolean hideAlternateBouncer(); /** * @return true if the alternate auth bouncer is showing */ - boolean isShowingAlternateAuthBouncer(); + boolean isShowingAlternateBouncer(); /** * Use when an app occluding the keyguard would like to give the user ability to @@ -1655,7 +1643,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb void requestUdfps(boolean requestUdfps, int color); /** - * print information for the alternate auth interceptor registered + * print information for the alternate bouncer registered */ void dump(PrintWriter pw); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java index 5cd2ba1b1cf3..b6ae4a088880 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java @@ -23,7 +23,6 @@ import static com.android.systemui.statusbar.phone.CentralSurfaces.getActivityOp import android.app.ActivityManager; import android.app.KeyguardManager; import android.app.Notification; -import android.app.NotificationManager; import android.app.PendingIntent; import android.app.TaskStackBuilder; import android.content.Context; @@ -60,9 +59,8 @@ import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.notification.NotificationActivityStarter; import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorControllerProvider; -import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; -import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener; +import com.android.systemui.statusbar.notification.collection.provider.LaunchFullScreenIntentProvider; import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; @@ -126,7 +124,6 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte Context context, Handler mainThreadHandler, Executor uiBgExecutor, - NotifPipeline notifPipeline, NotificationVisibilityProvider visibilityProvider, HeadsUpManagerPhone headsUpManager, ActivityStarter activityStarter, @@ -151,7 +148,8 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte NotificationPresenter presenter, NotificationPanelViewController panel, ActivityLaunchAnimator activityLaunchAnimator, - NotificationLaunchAnimatorControllerProvider notificationAnimationProvider) { + NotificationLaunchAnimatorControllerProvider notificationAnimationProvider, + LaunchFullScreenIntentProvider launchFullScreenIntentProvider) { mContext = context; mMainThreadHandler = mainThreadHandler; mUiBgExecutor = uiBgExecutor; @@ -182,12 +180,7 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte mActivityLaunchAnimator = activityLaunchAnimator; mNotificationAnimationProvider = notificationAnimationProvider; - notifPipeline.addCollectionListener(new NotifCollectionListener() { - @Override - public void onEntryAdded(NotificationEntry entry) { - handleFullScreenIntent(entry); - } - }); + launchFullScreenIntentProvider.registerListener(entry -> launchFullScreenIntent(entry)); } /** @@ -549,38 +542,36 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte } @VisibleForTesting - void handleFullScreenIntent(NotificationEntry entry) { - if (mNotificationInterruptStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry)) { - if (shouldSuppressFullScreenIntent(entry)) { - mLogger.logFullScreenIntentSuppressedByDnD(entry); - } else if (entry.getImportance() < NotificationManager.IMPORTANCE_HIGH) { - mLogger.logFullScreenIntentNotImportantEnough(entry); - } else { - // Stop screensaver if the notification has a fullscreen intent. - // (like an incoming phone call) - mUiBgExecutor.execute(() -> { - try { - mDreamManager.awaken(); - } catch (RemoteException e) { - e.printStackTrace(); - } - }); + void launchFullScreenIntent(NotificationEntry entry) { + // Skip if device is in VR mode. + if (mPresenter.isDeviceInVrMode()) { + mLogger.logFullScreenIntentSuppressedByVR(entry); + return; + } - // not immersive & a fullscreen alert should be shown - final PendingIntent fullscreenIntent = - entry.getSbn().getNotification().fullScreenIntent; - mLogger.logSendingFullScreenIntent(entry, fullscreenIntent); - try { - EventLog.writeEvent(EventLogTags.SYSUI_FULLSCREEN_NOTIFICATION, - entry.getKey()); - mCentralSurfaces.wakeUpForFullScreenIntent(); - fullscreenIntent.send(); - entry.notifyFullScreenIntentLaunched(); - mMetricsLogger.count("note_fullscreen", 1); - } catch (PendingIntent.CanceledException e) { - // ignore - } + // Stop screensaver if the notification has a fullscreen intent. + // (like an incoming phone call) + mUiBgExecutor.execute(() -> { + try { + mDreamManager.awaken(); + } catch (RemoteException e) { + e.printStackTrace(); } + }); + + // not immersive & a fullscreen alert should be shown + final PendingIntent fullscreenIntent = + entry.getSbn().getNotification().fullScreenIntent; + mLogger.logSendingFullScreenIntent(entry, fullscreenIntent); + try { + EventLog.writeEvent(EventLogTags.SYSUI_FULLSCREEN_NOTIFICATION, + entry.getKey()); + mCentralSurfaces.wakeUpForFullScreenIntent(); + fullscreenIntent.send(); + entry.notifyFullScreenIntentLaunched(); + mMetricsLogger.count("note_fullscreen", 1); + } catch (PendingIntent.CanceledException e) { + // ignore } } @@ -607,12 +598,4 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte mMainThreadHandler.post(mShadeController::collapsePanel); } } - - private boolean shouldSuppressFullScreenIntent(NotificationEntry entry) { - if (mPresenter.isDeviceInVrMode()) { - return true; - } - - return entry.shouldSuppressFullScreenIntent(); - } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterLogger.kt index 81edff45c505..1f0b96a58da6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterLogger.kt @@ -96,19 +96,11 @@ class StatusBarNotificationActivityStarterLogger @Inject constructor( }) } - fun logFullScreenIntentSuppressedByDnD(entry: NotificationEntry) { + fun logFullScreenIntentSuppressedByVR(entry: NotificationEntry) { buffer.log(TAG, DEBUG, { str1 = entry.logKey }, { - "No Fullscreen intent: suppressed by DND: $str1" - }) - } - - fun logFullScreenIntentNotImportantEnough(entry: NotificationEntry) { - buffer.log(TAG, DEBUG, { - str1 = entry.logKey - }, { - "No Fullscreen intent: not important enough: $str1" + "No Fullscreen intent: suppressed by VR mode: $str1" }) } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java index 70af77e1eb36..8a49850b1822 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java @@ -133,7 +133,7 @@ public class StatusBarRemoteInputCallback implements Callback, Callbacks, if (!row.isPinned()) { mStatusBarStateController.setLeaveOpenOnKeyguardHide(true); } - mStatusBarKeyguardViewManager.showGenericBouncer(true /* scrimmed */); + mStatusBarKeyguardViewManager.showBouncer(true /* scrimmed */); mPendingRemoteInputView = clicked; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java index 492734e93dca..de7bf3c021dd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java @@ -212,7 +212,7 @@ public class StatusBarSignalPolicy implements SignalCallback, private void updateWifiIconWithState(WifiIconState state) { if (DEBUG) Log.d(TAG, "WifiIconState: " + state == null ? "" : state.toString()); if (state.visible && state.resId > 0) { - mIconController.setSignalIcon(mSlotWifi, state); + mIconController.setWifiIcon(mSlotWifi, state); mIconController.setIconVisibility(mSlotWifi, true); } else { mIconController.setIconVisibility(mSlotWifi, false); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java index d9c0293fe13d..2a039dade059 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java @@ -34,6 +34,7 @@ import com.android.systemui.Dumpable; import com.android.systemui.R; import com.android.systemui.ScreenDecorations; import com.android.systemui.dagger.SysUISingleton; +import com.android.systemui.shade.ShadeExpansionStateManager; import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener; @@ -68,12 +69,15 @@ public final class StatusBarTouchableRegionManager implements Dumpable { private int mDisplayCutoutTouchableRegionSize; private int mStatusBarHeight; + private final OnComputeInternalInsetsListener mOnComputeInternalInsetsListener; + @Inject public StatusBarTouchableRegionManager( Context context, NotificationShadeWindowController notificationShadeWindowController, ConfigurationController configurationController, HeadsUpManagerPhone headsUpManager, + ShadeExpansionStateManager shadeExpansionStateManager, UnlockedScreenOffAnimationController unlockedScreenOffAnimationController ) { mContext = context; @@ -101,17 +105,7 @@ public final class StatusBarTouchableRegionManager implements Dumpable { updateTouchableRegion(); } }); - mHeadsUpManager.addHeadsUpPhoneListener( - new HeadsUpManagerPhone.OnHeadsUpPhoneListenerChange() { - @Override - public void onHeadsUpGoingAwayStateChanged(boolean headsUpGoingAway) { - if (!headsUpGoingAway) { - updateTouchableRegionAfterLayout(); - } else { - updateTouchableRegion(); - } - } - }); + mHeadsUpManager.addHeadsUpPhoneListener(this::onHeadsUpGoingAwayStateChanged); mNotificationShadeWindowController = notificationShadeWindowController; mNotificationShadeWindowController.setForcePluginOpenListener((forceOpen) -> { @@ -119,6 +113,9 @@ public final class StatusBarTouchableRegionManager implements Dumpable { }); mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController; + shadeExpansionStateManager.addFullExpansionListener(this::onShadeExpansionFullyChanged); + + mOnComputeInternalInsetsListener = this::onComputeInternalInsets; } protected void setup( @@ -136,17 +133,11 @@ public final class StatusBarTouchableRegionManager implements Dumpable { pw.println(mTouchableRegion); } - /** - * Notify that the status bar panel gets expanded or collapsed. - * - * @param isExpanded True to notify expanded, false to notify collapsed. - * TODO(b/237811427) replace with a listener - */ - public void setPanelExpanded(boolean isExpanded) { + private void onShadeExpansionFullyChanged(Boolean isExpanded) { if (isExpanded != mIsStatusBarExpanded) { mIsStatusBarExpanded = isExpanded; if (isExpanded) { - // make sure our state is sane + // make sure our state is sensible mForceCollapsedUntilLayout = false; } updateTouchableRegion(); @@ -260,18 +251,22 @@ public final class StatusBarTouchableRegionManager implements Dumpable { || mUnlockedScreenOffAnimationController.isAnimationPlaying(); } - private final OnComputeInternalInsetsListener mOnComputeInternalInsetsListener = - new OnComputeInternalInsetsListener() { - @Override - public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo info) { - if (shouldMakeEntireScreenTouchable()) { - return; - } + private void onHeadsUpGoingAwayStateChanged(boolean headsUpGoingAway) { + if (!headsUpGoingAway) { + updateTouchableRegionAfterLayout(); + } else { + updateTouchableRegion(); + } + } - // Update touch insets to include any area needed for touching features that live in - // the status bar (ie: heads up notifications) - info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION); - info.touchableRegion.set(calculateTouchableRegion()); + private void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo info) { + if (shouldMakeEntireScreenTouchable()) { + return; } - }; + + // Update touch insets to include any area needed for touching features that live in + // the status bar (ie: heads up notifications) + info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION); + info.touchableRegion.set(calculateTouchableRegion()); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialogManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialogManager.java index e7d9221ac861..678c2d972e2d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialogManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialogManager.java @@ -87,7 +87,7 @@ public class SystemUIDialogManager implements Dumpable { private void updateDialogListeners() { if (shouldHideAffordance()) { - mKeyguardViewController.resetAlternateAuth(true); + mKeyguardViewController.hideAlternateBouncer(true); } for (Listener listener : mListeners) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/StatusBarPipelineFlags.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/StatusBarPipelineFlags.kt index 06cd12dd1a0d..946d7e4a3e75 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/StatusBarPipelineFlags.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/StatusBarPipelineFlags.kt @@ -27,11 +27,26 @@ class StatusBarPipelineFlags @Inject constructor(private val featureFlags: Featu /** True if we should display the mobile icons using the new status bar data pipeline. */ fun useNewMobileIcons(): Boolean = featureFlags.isEnabled(Flags.NEW_STATUS_BAR_MOBILE_ICONS) + /** + * True if we should run the new mobile icons backend to get the logging. + * + * Does *not* affect whether we render the mobile icons using the new backend data. See + * [useNewMobileIcons] for that. + */ + fun runNewMobileIconsBackend(): Boolean = + featureFlags.isEnabled(Flags.NEW_STATUS_BAR_MOBILE_ICONS_BACKEND) || useNewMobileIcons() + /** True if we should display the wifi icon using the new status bar data pipeline. */ fun useNewWifiIcon(): Boolean = featureFlags.isEnabled(Flags.NEW_STATUS_BAR_WIFI_ICON) - // TODO(b/238425913): Add flags to only run the mobile backend or wifi backend so we get the - // logging without getting the UI effects. + /** + * True if we should run the new wifi icon backend to get the logging. + * + * Does *not* affect whether we render the wifi icon using the new backend data. See + * [useNewWifiIcon] for that. + */ + fun runNewWifiIconBackend(): Boolean = + featureFlags.isEnabled(Flags.NEW_STATUS_BAR_WIFI_ICON_BACKEND) || useNewWifiIcon() /** * Returns true if we should apply some coloring to the wifi icon that was rendered with the new 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 380017cd3418..c7e0ce173ece 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 @@ -20,6 +20,7 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.statusbar.phone.StatusBarIconController import com.android.systemui.statusbar.phone.StatusBarIconController.IconManager +import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel import javax.inject.Inject @@ -50,6 +51,7 @@ constructor( private val iconController: StatusBarIconController, private val iconsViewModelFactory: MobileIconsViewModel.Factory, @Application scope: CoroutineScope, + private val statusBarPipelineFlags: StatusBarPipelineFlags, ) { private val mobileSubIds: Flow<List<Int>> = interactor.filteredSubscriptions.mapLatest { infos -> @@ -66,8 +68,14 @@ constructor( private val mobileSubIdsState: StateFlow<List<Int>> = mobileSubIds .onEach { - // Notify the icon controller here so that it knows to add icons - iconController.setNewMobileIconSubIds(it) + // Only notify the icon controller if we want to *render* the new icons. + // Note that this flow may still run if + // [statusBarPipelineFlags.runNewMobileIconsBackend] is true because we may want to + // get the logging data without rendering. + if (statusBarPipelineFlags.useNewMobileIcons()) { + // Notify the icon controller here so that it knows to add icons + iconController.setNewMobileIconSubIds(it) + } } .stateIn(scope, SharingStarted.WhileSubscribed(), listOf()) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/WifiUiAdapter.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/WifiUiAdapter.kt new file mode 100644 index 000000000000..b816364ed4cf --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/WifiUiAdapter.kt @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.pipeline.wifi.ui + +import android.view.ViewGroup +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.repeatOnLifecycle +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.lifecycle.repeatWhenAttached +import com.android.systemui.statusbar.phone.StatusBarIconController +import com.android.systemui.statusbar.phone.StatusBarLocation +import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags +import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.LocationBasedWifiViewModel +import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.WifiViewModel +import javax.inject.Inject +import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.launch + +/** + * This class serves as a bridge between the old UI classes and the new data pipeline. + * + * Once the new pipeline notifies [wifiViewModel] that the wifi icon should be visible, this class + * notifies [iconController] to inflate the wifi icon (if needed). After that, the [wifiViewModel] + * has sole responsibility for updating the wifi icon drawable, visibility, etc. and the + * [iconController] will not do any updates to the icon. + */ +@SysUISingleton +class WifiUiAdapter +@Inject +constructor( + private val iconController: StatusBarIconController, + private val wifiViewModel: WifiViewModel, + private val statusBarPipelineFlags: StatusBarPipelineFlags, +) { + /** + * Binds the container for all the status bar icons to a view model, so that we inflate the wifi + * view once we receive a valid icon from the data pipeline. + * + * NOTE: This should go away as we better integrate the data pipeline with the UI. + * + * @return the view model used for this particular group in the given [location]. + */ + fun bindGroup( + statusBarIconGroup: ViewGroup, + location: StatusBarLocation, + ): LocationBasedWifiViewModel { + val locationViewModel = + when (location) { + StatusBarLocation.HOME -> wifiViewModel.home + StatusBarLocation.KEYGUARD -> wifiViewModel.keyguard + StatusBarLocation.QS -> wifiViewModel.qs + } + + statusBarIconGroup.repeatWhenAttached { + repeatOnLifecycle(Lifecycle.State.STARTED) { + launch { + locationViewModel.wifiIcon.collect { wifiIcon -> + // Only notify the icon controller if we want to *render* the new icon. + // Note that this flow may still run if + // [statusBarPipelineFlags.runNewWifiIconBackend] is true because we may + // want to get the logging data without rendering. + if (wifiIcon != null && statusBarPipelineFlags.useNewWifiIcon()) { + iconController.setNewWifiIcon() + } + } + } + } + } + + return locationViewModel + } +} 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 25537b948517..345f8cb75660 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 @@ -30,9 +30,7 @@ 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.phone.StatusBarLocation import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.LocationBasedWifiViewModel -import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.WifiViewModel import kotlinx.coroutines.InternalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.collect @@ -62,26 +60,9 @@ object WifiViewBinder { fun onVisibilityStateChanged(@StatusBarIconView.VisibleState state: Int) } - /** - * Binds the view to the appropriate view-model based on the given location. The view will - * continue to be updated following updates from the view-model. - */ - @JvmStatic - fun bind( - view: ViewGroup, - wifiViewModel: WifiViewModel, - location: StatusBarLocation, - ): Binding { - return when (location) { - StatusBarLocation.HOME -> bind(view, wifiViewModel.home) - StatusBarLocation.KEYGUARD -> bind(view, wifiViewModel.keyguard) - StatusBarLocation.QS -> bind(view, wifiViewModel.qs) - } - } - /** Binds the view to the view-model, continuing to update the former based on the latter. */ @JvmStatic - private fun bind( + fun bind( view: ViewGroup, viewModel: LocationBasedWifiViewModel, ): Binding { 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 0cd9bd7d97b0..a45076b53356 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 @@ -26,9 +26,8 @@ import com.android.systemui.statusbar.BaseStatusBarFrameLayout 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.phone.StatusBarLocation import com.android.systemui.statusbar.pipeline.wifi.ui.binder.WifiViewBinder -import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.WifiViewModel +import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.LocationBasedWifiViewModel /** * A new and more modern implementation of [com.android.systemui.statusbar.StatusBarWifiView] that @@ -81,12 +80,11 @@ class ModernStatusBarWifiView( private fun initView( slotName: String, - wifiViewModel: WifiViewModel, - location: StatusBarLocation, + wifiViewModel: LocationBasedWifiViewModel, ) { slot = slotName initDotView() - binding = WifiViewBinder.bind(this, wifiViewModel, location) + binding = WifiViewBinder.bind(this, wifiViewModel) } // Mostly duplicated from [com.android.systemui.statusbar.StatusBarWifiView]. @@ -116,14 +114,13 @@ class ModernStatusBarWifiView( fun constructAndBind( context: Context, slot: String, - wifiViewModel: WifiViewModel, - location: StatusBarLocation, + wifiViewModel: LocationBasedWifiViewModel, ): ModernStatusBarWifiView { return ( LayoutInflater.from(context).inflate(R.layout.new_status_bar_wifi_group, null) as ModernStatusBarWifiView ).also { - it.initView(slot, wifiViewModel, location) + it.initView(slot, wifiViewModel) } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt index 89b96b7bc75d..0782bbb774eb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt @@ -145,7 +145,8 @@ constructor( else -> null } } - .stateIn(scope, started = SharingStarted.WhileSubscribed(), initialValue = null) + .logOutputChange(logger, "icon") { icon -> icon?.contentDescription.toString() } + .stateIn(scope, started = SharingStarted.WhileSubscribed(), initialValue = null) /** The wifi activity status. Null if we shouldn't display the activity status. */ private val activity: Flow<WifiActivityModel?> = 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 1d414745e6ed..7acdaffb48c4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java @@ -118,7 +118,10 @@ public final class DeviceStateRotationLockSettingController private void updateDeviceState(int state) { Log.v(TAG, "updateDeviceState [state=" + state + "]"); - Trace.beginSection("updateDeviceState [state=" + state + "]"); + if (Trace.isEnabled()) { + Trace.traceBegin( + Trace.TRACE_TAG_APP, "updateDeviceState [state=" + state + "]"); + } try { if (mDeviceState == state) { return; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java index bd2123a251c3..69b55c81f48b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java @@ -33,6 +33,7 @@ import android.util.Log; import androidx.annotation.NonNull; import com.android.internal.util.ConcurrentUtils; +import com.android.systemui.R; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; @@ -63,6 +64,7 @@ public class HotspotControllerImpl implements HotspotController, WifiManager.Sof private volatile int mNumConnectedDevices; // Assume tethering is available until told otherwise private volatile boolean mIsTetheringSupported = true; + private final boolean mIsTetheringSupportedConfig; private volatile boolean mHasTetherableWifiRegexs = true; private boolean mWaitingForTerminalState; @@ -100,23 +102,29 @@ public class HotspotControllerImpl implements HotspotController, WifiManager.Sof mTetheringManager = context.getSystemService(TetheringManager.class); mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); mMainHandler = mainHandler; - mTetheringManager.registerTetheringEventCallback( - new HandlerExecutor(backgroundHandler), mTetheringCallback); + mIsTetheringSupportedConfig = context.getResources() + .getBoolean(R.bool.config_show_wifi_tethering); + if (mIsTetheringSupportedConfig) { + mTetheringManager.registerTetheringEventCallback( + new HandlerExecutor(backgroundHandler), mTetheringCallback); + } dumpManager.registerDumpable(getClass().getSimpleName(), this); } /** * Whether hotspot is currently supported. * - * This will return {@code true} immediately on creation of the controller, but may be updated - * later. Callbacks from this controllers will notify if the state changes. + * This may return {@code true} immediately on creation of the controller, but may be updated + * later as capabilities are collected from System Server. + * + * Callbacks from this controllers will notify if the state changes. * * @return {@code true} if hotspot is supported (or we haven't been told it's not) * @see #addCallback */ @Override public boolean isHotspotSupported() { - return mIsTetheringSupported && mHasTetherableWifiRegexs + return mIsTetheringSupportedConfig && mIsTetheringSupported && mHasTetherableWifiRegexs && UserManager.get(mContext).isUserAdmin(ActivityManager.getCurrentUser()); } diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt index 637fac05f0b6..4cb41f3a977e 100644 --- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt +++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt @@ -22,7 +22,6 @@ import android.graphics.PixelFormat import android.graphics.Rect import android.graphics.drawable.Drawable import android.os.PowerManager -import android.os.SystemClock import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -35,6 +34,7 @@ import com.android.systemui.CoreStartable import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.util.concurrency.DelayableExecutor +import com.android.systemui.util.wakelock.WakeLock /** * A generic controller that can temporarily display a new view in a new window. @@ -54,6 +54,7 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora private val configurationController: ConfigurationController, private val powerManager: PowerManager, @LayoutRes private val viewLayoutRes: Int, + private val wakeLockBuilder: WakeLock.Builder, ) : CoreStartable { /** * Window layout params that will be used as a starting point for the [windowLayoutParams] of @@ -64,7 +65,8 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora height = WindowManager.LayoutParams.WRAP_CONTENT type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or - WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL + WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or + WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON format = PixelFormat.TRANSLUCENT setTrustedOverlay() } @@ -84,6 +86,15 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora private var cancelViewTimeout: Runnable? = null /** + * A wakelock that is acquired when view is displayed and screen off, + * then released when view is removed. + */ + private var wakeLock: WakeLock? = null + + /** A string that keeps track of wakelock reason once it is acquired till it gets released */ + private var wakeReasonAcquired: String? = null + + /** * Displays the view with the provided [newInfo]. * * This method handles inflating and attaching the view, then delegates to [updateView] to @@ -113,11 +124,15 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora // the view to show over the dream state, so we should only wake up if the screen is // completely off.) if (!powerManager.isScreenOn) { - powerManager.wakeUp( - SystemClock.uptimeMillis(), - PowerManager.WAKE_REASON_APPLICATION, - "com.android.systemui:${newInfo.wakeReason}", - ) + wakeLock = wakeLockBuilder + .setTag(newInfo.windowTitle) + .setLevelsAndFlags( + PowerManager.FULL_WAKE_LOCK or + PowerManager.ACQUIRE_CAUSES_WAKEUP + ) + .build() + wakeLock?.acquire(newInfo.wakeReason) + wakeReasonAcquired = newInfo.wakeReason } logger.logViewAddition(newInfo.windowTitle) inflateAndUpdateView(newInfo) @@ -155,6 +170,7 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora it.copyFrom(windowLayoutParams) it.title = newInfo.windowTitle } + newView.keepScreenOn = true windowManager.addView(newView, paramsWithTitle) animateViewIn(newView) } @@ -183,7 +199,10 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora val currentDisplayInfo = displayInfo ?: return val currentView = currentDisplayInfo.view - animateViewOut(currentView) { windowManager.removeView(currentView) } + animateViewOut(currentView) { + windowManager.removeView(currentView) + wakeLock?.release(wakeReasonAcquired) + } logger.logViewRemoval(removalReason) configurationController.removeCallback(displayScaleListener) diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt index 87b6e8d3af34..44e5ce865241 100644 --- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt @@ -44,6 +44,7 @@ import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.temporarydisplay.TemporaryViewDisplayController import com.android.systemui.util.concurrency.DelayableExecutor import com.android.systemui.util.view.ViewUtil +import com.android.systemui.util.wakelock.WakeLock import javax.inject.Inject /** @@ -75,6 +76,7 @@ open class ChipbarCoordinator @Inject constructor( private val falsingCollector: FalsingCollector, private val viewUtil: ViewUtil, private val vibratorHelper: VibratorHelper, + wakeLockBuilder: WakeLock.Builder, ) : TemporaryViewDisplayController<ChipbarInfo, ChipbarLogger>( context, logger, @@ -84,6 +86,7 @@ open class ChipbarCoordinator @Inject constructor( configurationController, powerManager, R.layout.chipbar, + wakeLockBuilder, ) { private lateinit var parent: ChipbarRootView @@ -92,8 +95,6 @@ open class ChipbarCoordinator @Inject constructor( gravity = Gravity.TOP.or(Gravity.CENTER_HORIZONTAL) } - override fun start() {} - override fun updateView( newInfo: ChipbarInfo, currentView: ViewGroup @@ -192,6 +193,8 @@ open class ChipbarCoordinator @Inject constructor( ) } + override fun start() {} + override fun getTouchableRegion(view: View, outRect: Rect) { viewUtil.setRectToViewWindowLocation(view, outRect) } diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java index 10a09dd169e8..82200c61eeb5 100644 --- a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java @@ -47,6 +47,7 @@ import com.android.systemui.screenshot.ReferenceScreenshotModule; import com.android.systemui.shade.NotificationShadeWindowControllerImpl; import com.android.systemui.shade.ShadeController; import com.android.systemui.shade.ShadeControllerImpl; +import com.android.systemui.shade.ShadeExpansionStateManager; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.NotificationListener; import com.android.systemui.statusbar.NotificationLockscreenUserManager; @@ -157,7 +158,8 @@ public abstract class TvSystemUIModule { ConfigurationController configurationController, @Main Handler handler, AccessibilityManagerWrapper accessibilityManagerWrapper, - UiEventLogger uiEventLogger) { + UiEventLogger uiEventLogger, + ShadeExpansionStateManager shadeExpansionStateManager) { return new HeadsUpManagerPhone( context, headsUpManagerLogger, @@ -168,7 +170,8 @@ public abstract class TvSystemUIModule { configurationController, handler, accessibilityManagerWrapper, - uiEventLogger + uiEventLogger, + shadeExpansionStateManager ); } diff --git a/packages/SystemUI/src/com/android/systemui/user/CreateUserActivity.java b/packages/SystemUI/src/com/android/systemui/user/CreateUserActivity.java index f01712653e1b..b56c4034936f 100644 --- a/packages/SystemUI/src/com/android/systemui/user/CreateUserActivity.java +++ b/packages/SystemUI/src/com/android/systemui/user/CreateUserActivity.java @@ -25,6 +25,8 @@ import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.RemoteException; import android.util.Log; +import android.window.OnBackInvokedCallback; +import android.window.OnBackInvokedDispatcher; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -59,6 +61,7 @@ public class CreateUserActivity extends Activity { private final ActivityStarter mActivityStarter; private Dialog mSetupUserDialog; + private final OnBackInvokedCallback mBackCallback = this::onBackInvoked; @Inject public CreateUserActivity(UserCreator userCreator, @@ -82,6 +85,10 @@ public class CreateUserActivity extends Activity { mSetupUserDialog = createDialog(); mSetupUserDialog.show(); + + getOnBackInvokedDispatcher().registerOnBackInvokedCallback( + OnBackInvokedDispatcher.PRIORITY_DEFAULT, + mBackCallback); } @Override @@ -125,10 +132,20 @@ public class CreateUserActivity extends Activity { @Override public void onBackPressed() { - super.onBackPressed(); + onBackInvoked(); + } + + private void onBackInvoked() { if (mSetupUserDialog != null) { mSetupUserDialog.dismiss(); } + finish(); + } + + @Override + protected void onDestroy() { + getOnBackInvokedDispatcher().unregisterOnBackInvokedCallback(mBackCallback); + super.onDestroy(); } private void addUserNow(String userName, Drawable userIcon) { diff --git a/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt b/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt index 6a2326036ec0..ffaf524bb0d1 100644 --- a/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt @@ -250,6 +250,10 @@ constructor( override fun onUserChanged(newUser: Int, userContext: Context) { send() } + + override fun onProfilesChanged(profiles: List<UserInfo>) { + send() + } } tracker.addCallback(callback, mainDispatcher.asExecutor()) diff --git a/packages/SystemUI/src/com/android/systemui/util/BrightnessProgressDrawable.kt b/packages/SystemUI/src/com/android/systemui/util/BrightnessProgressDrawable.kt new file mode 100644 index 000000000000..12a0c03a2ad7 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/util/BrightnessProgressDrawable.kt @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.util + +import android.content.pm.ActivityInfo +import android.content.res.Resources +import android.graphics.Rect +import android.graphics.drawable.Drawable +import android.graphics.drawable.DrawableWrapper +import android.graphics.drawable.InsetDrawable + +/** + * [DrawableWrapper] to use in the progress of brightness slider. + * + * This drawable is used to change the bounds of the enclosed drawable depending on the level to + * simulate a sliding progress, instead of using clipping or scaling. That way, the shape of the + * edges is maintained. + * + * Meant to be used with a rounded ends background, it will also prevent deformation when the slider + * is meant to be smaller than the rounded corner. The background should have rounded corners that + * are half of the height. + * + * This class also assumes that a "thumb" icon exists within the end's edge of the progress + * drawable, and the slider's width, when interacted on, if offset by half the size of the thumb + * icon which puts the icon directly underneath the user's finger. + */ +class BrightnessProgressDrawable @JvmOverloads constructor(drawable: Drawable? = null) : + InsetDrawable(drawable, 0) { + + companion object { + private const val MAX_LEVEL = 10000 // Taken from Drawable + } + + override fun onLayoutDirectionChanged(layoutDirection: Int): Boolean { + onLevelChange(level) + return super.onLayoutDirectionChanged(layoutDirection) + } + + override fun onBoundsChange(bounds: Rect) { + super.onBoundsChange(bounds) + onLevelChange(level) + } + + override fun onLevelChange(level: Int): Boolean { + val db = drawable?.bounds!! + + // The thumb offset shifts the sun icon directly under the user's thumb + val thumbOffset = bounds.height() / 2 + val width = bounds.width() * level / MAX_LEVEL + thumbOffset + + // On 0, the width is bounds.height (a circle), and on MAX_LEVEL, the width is bounds.width + drawable?.setBounds( + bounds.left, + db.top, + width.coerceAtMost(bounds.width()).coerceAtLeast(bounds.height()), + db.bottom + ) + return super.onLevelChange(level) + } + + override fun getConstantState(): ConstantState { + // This should not be null as it was created with a state in the constructor. + return RoundedCornerState(super.getConstantState()!!) + } + + override fun getChangingConfigurations(): Int { + return super.getChangingConfigurations() or ActivityInfo.CONFIG_DENSITY + } + + override fun canApplyTheme(): Boolean { + return (drawable?.canApplyTheme() ?: false) || super.canApplyTheme() + } + + private class RoundedCornerState(private val wrappedState: ConstantState) : ConstantState() { + override fun newDrawable(): Drawable { + return newDrawable(null, null) + } + + override fun newDrawable(res: Resources?, theme: Resources.Theme?): Drawable { + val wrapper = wrappedState.newDrawable(res, theme) as DrawableWrapper + return BrightnessProgressDrawable(wrapper.drawable) + } + + override fun getChangingConfigurations(): Int { + return wrappedState.changingConfigurations + } + + override fun canApplyTheme(): Boolean { + return true + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/util/RoundedCornerProgressDrawable.kt b/packages/SystemUI/src/com/android/systemui/util/RoundedCornerProgressDrawable.kt index 99eb03b44276..1059d6c61287 100644 --- a/packages/SystemUI/src/com/android/systemui/util/RoundedCornerProgressDrawable.kt +++ b/packages/SystemUI/src/com/android/systemui/util/RoundedCornerProgressDrawable.kt @@ -33,11 +33,6 @@ import android.graphics.drawable.InsetDrawable * Meant to be used with a rounded ends background, it will also prevent deformation when the slider * is meant to be smaller than the rounded corner. The background should have rounded corners that * are half of the height. - * - * This class also assumes that a "thumb" icon exists within the end's edge of the progress - * drawable, and the slider's width, when interacted on, if offset by half the size of the thumb - * icon which puts the icon directly underneath the user's finger. - * */ class RoundedCornerProgressDrawable @JvmOverloads constructor( drawable: Drawable? = null @@ -59,16 +54,9 @@ class RoundedCornerProgressDrawable @JvmOverloads constructor( override fun onLevelChange(level: Int): Boolean { val db = drawable?.bounds!! - - // The thumb offset shifts the sun icon directly under the user's thumb - val thumbOffset = bounds.height() / 2 - val width = bounds.width() * level / MAX_LEVEL + thumbOffset - // On 0, the width is bounds.height (a circle), and on MAX_LEVEL, the width is bounds.width - drawable?.setBounds( - bounds.left, db.top, - width.coerceAtMost(bounds.width()).coerceAtLeast(bounds.height()), db.bottom - ) + val width = bounds.height() + (bounds.width() - bounds.height()) * level / MAX_LEVEL + drawable?.setBounds(bounds.left, db.top, bounds.left + width, db.bottom) return super.onLevelChange(level) } @@ -103,4 +91,4 @@ class RoundedCornerProgressDrawable @JvmOverloads constructor( return true } } -} +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLock.java b/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLock.java index 8d77c4a194a9..f320d071b54f 100644 --- a/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLock.java +++ b/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLock.java @@ -38,6 +38,11 @@ public interface WakeLock { long DEFAULT_MAX_TIMEOUT = 20000; /** + * Default wake-lock levels and flags. + */ + int DEFAULT_LEVELS_AND_FLAGS = PowerManager.PARTIAL_WAKE_LOCK; + + /** * @param why A tag that will be saved for sysui dumps. * @see android.os.PowerManager.WakeLock#acquire() **/ @@ -60,13 +65,21 @@ public interface WakeLock { * Creates a {@link WakeLock} that has a default release timeout. * @see android.os.PowerManager.WakeLock#acquire(long) */ static WakeLock createPartial(Context context, String tag, long maxTimeout) { - return wrap(createPartialInner(context, tag), maxTimeout); + return wrap(createWakeLockInner(context, tag, DEFAULT_LEVELS_AND_FLAGS), maxTimeout); + } + + /** + * Creates a {@link WakeLock} that has a default release timeout and flags. + */ + static WakeLock createWakeLock(Context context, String tag, int flags, long maxTimeout) { + return wrap(createWakeLockInner(context, tag, flags), maxTimeout); } @VisibleForTesting - static PowerManager.WakeLock createPartialInner(Context context, String tag) { + static PowerManager.WakeLock createWakeLockInner( + Context context, String tag, int levelsAndFlags) { return context.getSystemService(PowerManager.class) - .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, tag); + .newWakeLock(levelsAndFlags, tag); } static Runnable wrapImpl(WakeLock w, Runnable r) { @@ -131,6 +144,7 @@ public interface WakeLock { class Builder { private final Context mContext; private String mTag; + private int mLevelsAndFlags = DEFAULT_LEVELS_AND_FLAGS; private long mMaxTimeout = DEFAULT_MAX_TIMEOUT; @Inject @@ -143,13 +157,18 @@ public interface WakeLock { return this; } + public Builder setLevelsAndFlags(int levelsAndFlags) { + this.mLevelsAndFlags = levelsAndFlags; + return this; + } + public Builder setMaxTimeout(long maxTimeout) { this.mMaxTimeout = maxTimeout; return this; } public WakeLock build() { - return WakeLock.createPartial(mContext, mTag, mMaxTimeout); + return WakeLock.createWakeLock(mContext, mTag, mLevelsAndFlags, mMaxTimeout); } } } diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java index 4e7751464564..a4384d5810ce 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java @@ -25,6 +25,7 @@ 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; @@ -51,6 +52,7 @@ import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.statusbar.IStatusBarService; import com.android.systemui.dagger.SysUISingleton; +import com.android.systemui.flags.FeatureFlags; import com.android.systemui.model.SysUiState; import com.android.systemui.shade.ShadeController; import com.android.systemui.shared.system.QuickStepContract; @@ -129,6 +131,7 @@ public class BubblesManager { CommonNotifCollection notifCollection, NotifPipeline notifPipeline, SysUiState sysUiState, + FeatureFlags featureFlags, Executor sysuiMainExecutor) { if (bubblesOptional.isPresent()) { return new BubblesManager(context, @@ -146,6 +149,7 @@ public class BubblesManager { notifCollection, notifPipeline, sysUiState, + featureFlags, sysuiMainExecutor); } else { return null; @@ -168,6 +172,7 @@ public class BubblesManager { CommonNotifCollection notifCollection, NotifPipeline notifPipeline, SysUiState sysUiState, + FeatureFlags featureFlags, Executor sysuiMainExecutor) { mContext = context; mBubbles = bubbles; @@ -352,6 +357,7 @@ public class BubblesManager { }); } }; + mBubbles.setBubbleBarEnabled(featureFlags.isEnabled(WM_BUBBLE_BAR)); mBubbles.setSysuiProxy(mSysuiProxy); } diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml index 1b404a82145b..ea0b03d1ebfd 100644 --- a/packages/SystemUI/tests/AndroidManifest.xml +++ b/packages/SystemUI/tests/AndroidManifest.xml @@ -93,6 +93,21 @@ android:excludeFromRecents="true" /> + <activity android:name="com.android.systemui.controls.management.ControlsEditingActivityTest$TestableControlsEditingActivity" + android:exported="false" + android:excludeFromRecents="true" + /> + + <activity android:name="com.android.systemui.controls.management.ControlsFavoritingActivityTest$TestableControlsFavoritingActivity" + android:exported="false" + android:excludeFromRecents="true" + /> + + <activity android:name="com.android.systemui.controls.management.ControlsProviderSelectorActivityTest$TestableControlsProviderSelectorActivity" + android:exported="false" + android:excludeFromRecents="true" + /> + <activity android:name="com.android.systemui.screenshot.ScrollViewActivity" android:exported="false" /> @@ -106,6 +121,12 @@ android:finishOnCloseSystemDialogs="true" android:excludeFromRecents="true" /> + <activity android:name=".user.CreateUserActivityTest$CreateUserActivityTestable" + android:exported="false" + android:theme="@style/Theme.SystemUI.Dialog.Alert" + android:finishOnCloseSystemDialogs="true" + android:excludeFromRecents="true" /> + <provider android:name="androidx.startup.InitializationProvider" tools:replace="android:authorities" diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java index 0a2b3d8498c4..aa4469f12161 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java @@ -54,7 +54,8 @@ import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; -import com.android.systemui.biometrics.SidefpsController; +import com.android.systemui.biometrics.SideFpsController; +import com.android.systemui.biometrics.SideFpsUiRequestSource; import com.android.systemui.classifier.FalsingA11yDelegate; import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.flags.FeatureFlags; @@ -141,7 +142,7 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { @Mock private KeyguardViewController mKeyguardViewController; @Mock - private SidefpsController mSidefpsController; + private SideFpsController mSideFpsController; @Mock private KeyguardPasswordViewController mKeyguardPasswordViewControllerMock; @Mock @@ -189,7 +190,7 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { mKeyguardStateController, mKeyguardSecurityViewFlipperController, mConfigurationController, mFalsingCollector, mFalsingManager, mUserSwitcherController, mFeatureFlags, mGlobalSettings, - mSessionTracker, Optional.of(mSidefpsController), mFalsingA11yDelegate).create( + mSessionTracker, Optional.of(mSideFpsController), mFalsingA11yDelegate).create( mSecurityCallback); } @@ -345,48 +346,48 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { @Test public void onBouncerVisibilityChanged_allConditionsGood_sideFpsHintShown() { setupConditionsToEnableSideFpsHint(); - reset(mSidefpsController); + reset(mSideFpsController); mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); - verify(mSidefpsController).show(); - verify(mSidefpsController, never()).hide(); + verify(mSideFpsController).show(SideFpsUiRequestSource.PRIMARY_BOUNCER); + verify(mSideFpsController, never()).hide(any()); } @Test public void onBouncerVisibilityChanged_fpsSensorNotRunning_sideFpsHintHidden() { setupConditionsToEnableSideFpsHint(); setFingerprintDetectionRunning(false); - reset(mSidefpsController); + reset(mSideFpsController); mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); - verify(mSidefpsController).hide(); - verify(mSidefpsController, never()).show(); + verify(mSideFpsController).hide(SideFpsUiRequestSource.PRIMARY_BOUNCER); + verify(mSideFpsController, never()).show(any()); } @Test public void onBouncerVisibilityChanged_withoutSidedSecurity_sideFpsHintHidden() { setupConditionsToEnableSideFpsHint(); setSideFpsHintEnabledFromResources(false); - reset(mSidefpsController); + reset(mSideFpsController); mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); - verify(mSidefpsController).hide(); - verify(mSidefpsController, never()).show(); + verify(mSideFpsController).hide(SideFpsUiRequestSource.PRIMARY_BOUNCER); + verify(mSideFpsController, never()).show(any()); } @Test public void onBouncerVisibilityChanged_needsStrongAuth_sideFpsHintHidden() { setupConditionsToEnableSideFpsHint(); setNeedsStrongAuth(true); - reset(mSidefpsController); + reset(mSideFpsController); mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); - verify(mSidefpsController).hide(); - verify(mSidefpsController, never()).show(); + verify(mSideFpsController).hide(SideFpsUiRequestSource.PRIMARY_BOUNCER); + verify(mSideFpsController, never()).show(any()); } @Test @@ -394,13 +395,13 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { setupGetSecurityView(); setupConditionsToEnableSideFpsHint(); mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); - verify(mSidefpsController, atLeastOnce()).show(); - reset(mSidefpsController); + verify(mSideFpsController, atLeastOnce()).show(SideFpsUiRequestSource.PRIMARY_BOUNCER); + reset(mSideFpsController); mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.INVISIBLE); - verify(mSidefpsController).hide(); - verify(mSidefpsController, never()).show(); + verify(mSideFpsController).hide(SideFpsUiRequestSource.PRIMARY_BOUNCER); + verify(mSideFpsController, never()).show(any()); } @Test @@ -408,13 +409,13 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { setupGetSecurityView(); setupConditionsToEnableSideFpsHint(); mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); - verify(mSidefpsController, atLeastOnce()).show(); - reset(mSidefpsController); + verify(mSideFpsController, atLeastOnce()).show(SideFpsUiRequestSource.PRIMARY_BOUNCER); + reset(mSideFpsController); mKeyguardSecurityContainerController.onStartingToHide(); - verify(mSidefpsController).hide(); - verify(mSidefpsController, never()).show(); + verify(mSideFpsController).hide(SideFpsUiRequestSource.PRIMARY_BOUNCER); + verify(mSideFpsController, never()).show(any()); } @Test @@ -422,13 +423,13 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { setupGetSecurityView(); setupConditionsToEnableSideFpsHint(); mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); - verify(mSidefpsController, atLeastOnce()).show(); - reset(mSidefpsController); + verify(mSideFpsController, atLeastOnce()).show(SideFpsUiRequestSource.PRIMARY_BOUNCER); + reset(mSideFpsController); mKeyguardSecurityContainerController.onPause(); - verify(mSidefpsController).hide(); - verify(mSidefpsController, never()).show(); + verify(mSideFpsController).hide(SideFpsUiRequestSource.PRIMARY_BOUNCER); + verify(mSideFpsController, never()).show(any()); } @Test @@ -436,12 +437,12 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { setupGetSecurityView(); setupConditionsToEnableSideFpsHint(); mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); - reset(mSidefpsController); + reset(mSideFpsController); mKeyguardSecurityContainerController.onResume(0); - verify(mSidefpsController).show(); - verify(mSidefpsController, never()).hide(); + verify(mSideFpsController).show(SideFpsUiRequestSource.PRIMARY_BOUNCER); + verify(mSideFpsController, never()).hide(any()); } @Test @@ -450,12 +451,12 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { setupConditionsToEnableSideFpsHint(); setSideFpsHintEnabledFromResources(false); mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); - reset(mSidefpsController); + reset(mSideFpsController); mKeyguardSecurityContainerController.onResume(0); - verify(mSidefpsController).hide(); - verify(mSidefpsController, never()).show(); + verify(mSideFpsController).hide(SideFpsUiRequestSource.PRIMARY_BOUNCER); + verify(mSideFpsController, never()).show(any()); } @Test diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java index a8284d29197d..c6200daca6f6 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java @@ -629,7 +629,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { @Test public void testNoStartAuthenticate_whenAboutToShowBouncer() { - mKeyguardUpdateMonitor.sendKeyguardBouncerChanged( + mKeyguardUpdateMonitor.sendPrimaryBouncerChanged( /* bouncerIsOrWillBeShowing */ true, /* bouncerFullyShown */ false); verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(), @@ -1621,7 +1621,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } @Test - public void testShouldListenForFace_whenFaceIsLockedOut_returnsFalse() + public void testShouldListenForFace_whenFaceIsLockedOut_returnsTrue() throws RemoteException { // Preconditions for face auth to run keyguardNotGoingAway(); @@ -1638,7 +1638,9 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { faceAuthLockedOut(); mTestableLooper.processAllMessages(); - assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isFalse(); + // This is needed beccause we want to show face locked out error message whenever face auth + // is supposed to run. + assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isTrue(); } @Test @@ -1850,7 +1852,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } private void setKeyguardBouncerVisibility(boolean isVisible) { - mKeyguardUpdateMonitor.sendKeyguardBouncerChanged(isVisible, isVisible); + mKeyguardUpdateMonitor.sendPrimaryBouncerChanged(isVisible, isVisible); mTestableLooper.processAllMessages(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/ChooserSelectorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/ChooserSelectorTest.kt index 6b1ef389a98e..81d0034128b1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/ChooserSelectorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/ChooserSelectorTest.kt @@ -3,6 +3,7 @@ package com.android.systemui import android.content.ComponentName import android.content.Context import android.content.pm.PackageManager +import android.content.pm.UserInfo import android.content.res.Resources import android.testing.AndroidTestingRunner import androidx.test.filters.SmallTest @@ -11,9 +12,11 @@ import com.android.systemui.flags.Flag import com.android.systemui.flags.FlagListenable import com.android.systemui.flags.Flags import com.android.systemui.flags.UnreleasedFlag +import com.android.systemui.settings.UserTracker import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.eq import com.android.systemui.util.mockito.kotlinArgumentCaptor +import com.android.systemui.util.mockito.whenever import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.cancel @@ -26,9 +29,9 @@ import org.mockito.Mock import org.mockito.Mockito.anyInt import org.mockito.Mockito.clearInvocations import org.mockito.Mockito.never +import org.mockito.Mockito.times import org.mockito.Mockito.verify import org.mockito.Mockito.verifyZeroInteractions -import org.mockito.Mockito.`when` import org.mockito.MockitoAnnotations @OptIn(ExperimentalCoroutinesApi::class) @@ -44,6 +47,8 @@ class ChooserSelectorTest : SysuiTestCase() { private lateinit var chooserSelector: ChooserSelector @Mock private lateinit var mockContext: Context + @Mock private lateinit var mockProfileContext: Context + @Mock private lateinit var mockUserTracker: UserTracker @Mock private lateinit var mockPackageManager: PackageManager @Mock private lateinit var mockResources: Resources @Mock private lateinit var mockFeatureFlags: FeatureFlags @@ -52,12 +57,20 @@ class ChooserSelectorTest : SysuiTestCase() { fun setup() { MockitoAnnotations.initMocks(this) - `when`(mockContext.packageManager).thenReturn(mockPackageManager) - `when`(mockContext.resources).thenReturn(mockResources) - `when`(mockResources.getString(anyInt())).thenReturn( + whenever(mockContext.createContextAsUser(any(), anyInt())).thenReturn(mockProfileContext) + whenever(mockContext.resources).thenReturn(mockResources) + whenever(mockProfileContext.packageManager).thenReturn(mockPackageManager) + whenever(mockResources.getString(anyInt())).thenReturn( ComponentName("TestPackage", "TestClass").flattenToString()) - - chooserSelector = ChooserSelector(mockContext, mockFeatureFlags, testScope, testDispatcher) + whenever(mockUserTracker.userProfiles).thenReturn(listOf(UserInfo(), UserInfo())) + + chooserSelector = ChooserSelector( + mockContext, + mockUserTracker, + mockFeatureFlags, + testScope, + testDispatcher, + ) } @After @@ -74,7 +87,9 @@ class ChooserSelectorTest : SysuiTestCase() { // Assert verify(mockFeatureFlags).addListener( - eq<Flag<*>>(Flags.CHOOSER_UNBUNDLED), flagListener.capture()) + eq<Flag<*>>(Flags.CHOOSER_UNBUNDLED), + flagListener.capture(), + ) verify(mockFeatureFlags, never()).removeListener(any()) // Act @@ -87,86 +102,102 @@ class ChooserSelectorTest : SysuiTestCase() { @Test fun initialize_enablesUnbundledChooser_whenFlagEnabled() { // Arrange - `when`(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(true) + whenever(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(true) // Act chooserSelector.start() // Assert - verify(mockPackageManager).setComponentEnabledSetting( + verify(mockPackageManager, times(2)).setComponentEnabledSetting( eq(ComponentName("TestPackage", "TestClass")), eq(PackageManager.COMPONENT_ENABLED_STATE_ENABLED), - anyInt()) + anyInt(), + ) } @Test fun initialize_disablesUnbundledChooser_whenFlagDisabled() { // Arrange - `when`(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(false) + whenever(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(false) // Act chooserSelector.start() // Assert - verify(mockPackageManager).setComponentEnabledSetting( + verify(mockPackageManager, times(2)).setComponentEnabledSetting( eq(ComponentName("TestPackage", "TestClass")), eq(PackageManager.COMPONENT_ENABLED_STATE_DISABLED), - anyInt()) + anyInt(), + ) } @Test fun enablesUnbundledChooser_whenFlagBecomesEnabled() { // Arrange - `when`(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(false) + whenever(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(false) chooserSelector.start() verify(mockFeatureFlags).addListener( - eq<Flag<*>>(Flags.CHOOSER_UNBUNDLED), flagListener.capture()) + eq<Flag<*>>(Flags.CHOOSER_UNBUNDLED), + flagListener.capture(), + ) verify(mockPackageManager, never()).setComponentEnabledSetting( - any(), eq(PackageManager.COMPONENT_ENABLED_STATE_ENABLED), anyInt()) + any(), + eq(PackageManager.COMPONENT_ENABLED_STATE_ENABLED), + anyInt(), + ) // Act - `when`(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(true) + whenever(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(true) flagListener.value.onFlagChanged(TestFlagEvent(Flags.CHOOSER_UNBUNDLED.id)) // Assert - verify(mockPackageManager).setComponentEnabledSetting( + verify(mockPackageManager, times(2)).setComponentEnabledSetting( eq(ComponentName("TestPackage", "TestClass")), eq(PackageManager.COMPONENT_ENABLED_STATE_ENABLED), - anyInt()) + anyInt(), + ) } @Test fun disablesUnbundledChooser_whenFlagBecomesDisabled() { // Arrange - `when`(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(true) + whenever(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(true) chooserSelector.start() verify(mockFeatureFlags).addListener( - eq<Flag<*>>(Flags.CHOOSER_UNBUNDLED), flagListener.capture()) + eq<Flag<*>>(Flags.CHOOSER_UNBUNDLED), + flagListener.capture(), + ) verify(mockPackageManager, never()).setComponentEnabledSetting( - any(), eq(PackageManager.COMPONENT_ENABLED_STATE_DISABLED), anyInt()) + any(), + eq(PackageManager.COMPONENT_ENABLED_STATE_DISABLED), + anyInt(), + ) // Act - `when`(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(false) + whenever(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(false) flagListener.value.onFlagChanged(TestFlagEvent(Flags.CHOOSER_UNBUNDLED.id)) // Assert - verify(mockPackageManager).setComponentEnabledSetting( + verify(mockPackageManager, times(2)).setComponentEnabledSetting( eq(ComponentName("TestPackage", "TestClass")), eq(PackageManager.COMPONENT_ENABLED_STATE_DISABLED), - anyInt()) + anyInt(), + ) } @Test fun doesNothing_whenAnotherFlagChanges() { // Arrange - `when`(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(false) + whenever(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(false) chooserSelector.start() verify(mockFeatureFlags).addListener( - eq<Flag<*>>(Flags.CHOOSER_UNBUNDLED), flagListener.capture()) + eq<Flag<*>>(Flags.CHOOSER_UNBUNDLED), + flagListener.capture(), + ) clearInvocations(mockPackageManager) // Act - `when`(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(false) + whenever(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(false) flagListener.value.onFlagChanged(TestFlagEvent(Flags.CHOOSER_UNBUNDLED.id + 1)) // Assert diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt index d1107c612977..eaef159e9020 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt @@ -161,6 +161,25 @@ class AuthContainerViewTest : SysuiTestCase() { } @Test + fun testFocusLossAfterRotating() { + val container = initializeFingerprintContainer() + waitForIdleSync() + + val requestID = authContainer?.requestId ?: 0L + + verify(callback).onDialogAnimatedIn(requestID) + container.onOrientationChanged() + container.onWindowFocusChanged(false) + waitForIdleSync() + + verify(callback, never()).onDismissed( + eq(AuthDialogCallback.DISMISSED_USER_CANCELED), + eq<ByteArray?>(null), /* credentialAttestation */ + eq(requestID) + ) + } + + @Test fun testDismissesOnFocusLoss_hidesKeyboardWhenVisible() { val container = initializeFingerprintContainer( authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java index a275c8d33751..83bf1834989b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java @@ -145,7 +145,7 @@ public class AuthControllerTest extends SysuiTestCase { @Mock private UdfpsController mUdfpsController; @Mock - private SidefpsController mSidefpsController; + private SideFpsController mSideFpsController; @Mock private DisplayManager mDisplayManager; @Mock @@ -225,7 +225,7 @@ public class AuthControllerTest extends SysuiTestCase { mAuthController = new TestableAuthController(mContextSpy, mExecution, mCommandQueue, mActivityTaskManager, mWindowManager, mFingerprintManager, mFaceManager, - () -> mUdfpsController, () -> mSidefpsController, mStatusBarStateController, + () -> mUdfpsController, () -> mSideFpsController, mStatusBarStateController, mVibratorHelper); mAuthController.start(); @@ -256,7 +256,7 @@ public class AuthControllerTest extends SysuiTestCase { // This test requires an uninitialized AuthController. AuthController authController = new TestableAuthController(mContextSpy, mExecution, mCommandQueue, mActivityTaskManager, mWindowManager, mFingerprintManager, - mFaceManager, () -> mUdfpsController, () -> mSidefpsController, + mFaceManager, () -> mUdfpsController, () -> mSideFpsController, mStatusBarStateController, mVibratorHelper); authController.start(); @@ -282,7 +282,7 @@ public class AuthControllerTest extends SysuiTestCase { // This test requires an uninitialized AuthController. AuthController authController = new TestableAuthController(mContextSpy, mExecution, mCommandQueue, mActivityTaskManager, mWindowManager, mFingerprintManager, - mFaceManager, () -> mUdfpsController, () -> mSidefpsController, + mFaceManager, () -> mUdfpsController, () -> mSideFpsController, mStatusBarStateController, mVibratorHelper); authController.start(); @@ -936,7 +936,7 @@ public class AuthControllerTest extends SysuiTestCase { FingerprintManager fingerprintManager, FaceManager faceManager, Provider<UdfpsController> udfpsControllerFactory, - Provider<SidefpsController> sidefpsControllerFactory, + Provider<SideFpsController> sidefpsControllerFactory, StatusBarStateController statusBarStateController, VibratorHelper vibratorHelper) { super(context, execution, commandQueue, activityTaskManager, windowManager, 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 8d969d0f1045..e7d5632c7087 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SidefpsControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt @@ -52,6 +52,7 @@ import androidx.test.filters.SmallTest import com.airbnb.lottie.LottieAnimationView import com.android.systemui.R import com.android.systemui.SysuiTestCase +import com.android.systemui.dump.DumpManager import com.android.systemui.recents.OverviewProxyService import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.time.FakeSystemClock @@ -82,37 +83,31 @@ private const val SENSOR_ID = 1 @SmallTest @RunWith(AndroidTestingRunner::class) @TestableLooper.RunWithLooper -class SidefpsControllerTest : SysuiTestCase() { - - @JvmField @Rule - var rule = MockitoJUnit.rule() - - @Mock - lateinit var layoutInflater: LayoutInflater - @Mock - lateinit var fingerprintManager: FingerprintManager - @Mock - lateinit var windowManager: WindowManager - @Mock - lateinit var activityTaskManager: ActivityTaskManager - @Mock - lateinit var sidefpsView: View - @Mock - lateinit var displayManager: DisplayManager - @Mock - lateinit var overviewProxyService: OverviewProxyService - @Mock - lateinit var handler: Handler - @Captor - lateinit var overlayCaptor: ArgumentCaptor<View> - @Captor - lateinit var overlayViewParamsCaptor: ArgumentCaptor<WindowManager.LayoutParams> +class SideFpsControllerTest : SysuiTestCase() { + + @JvmField @Rule var rule = MockitoJUnit.rule() + + @Mock lateinit var layoutInflater: LayoutInflater + @Mock lateinit var fingerprintManager: FingerprintManager + @Mock lateinit var windowManager: WindowManager + @Mock lateinit var activityTaskManager: ActivityTaskManager + @Mock lateinit var sideFpsView: View + @Mock lateinit var displayManager: DisplayManager + @Mock lateinit var overviewProxyService: OverviewProxyService + @Mock lateinit var handler: Handler + @Mock lateinit var dumpManager: DumpManager + @Captor lateinit var overlayCaptor: ArgumentCaptor<View> + @Captor lateinit var overlayViewParamsCaptor: ArgumentCaptor<WindowManager.LayoutParams> private val executor = FakeExecutor(FakeSystemClock()) private lateinit var overlayController: ISidefpsController - private lateinit var sideFpsController: SidefpsController + private lateinit var sideFpsController: SideFpsController - enum class DeviceConfig { X_ALIGNED, Y_ALIGNED_UNFOLDED, Y_ALIGNED_FOLDED } + enum class DeviceConfig { + X_ALIGNED, + Y_ALIGNED_UNFOLDED, + Y_ALIGNED_FOLDED + } private lateinit var deviceConfig: DeviceConfig private lateinit var indicatorBounds: Rect @@ -128,17 +123,18 @@ class SidefpsControllerTest : SysuiTestCase() { context.addMockSystemService(DisplayManager::class.java, displayManager) context.addMockSystemService(WindowManager::class.java, windowManager) - whenEver(layoutInflater.inflate(R.layout.sidefps_view, null, false)).thenReturn(sidefpsView) - whenEver(sidefpsView.findViewById<LottieAnimationView>(eq(R.id.sidefps_animation))) + whenEver(layoutInflater.inflate(R.layout.sidefps_view, null, false)).thenReturn(sideFpsView) + whenEver(sideFpsView.findViewById<LottieAnimationView>(eq(R.id.sidefps_animation))) .thenReturn(mock(LottieAnimationView::class.java)) with(mock(ViewPropertyAnimator::class.java)) { - whenEver(sidefpsView.animate()).thenReturn(this) + whenEver(sideFpsView.animate()).thenReturn(this) whenEver(alpha(anyFloat())).thenReturn(this) whenEver(setStartDelay(anyLong())).thenReturn(this) whenEver(setDuration(anyLong())).thenReturn(this) whenEver(setListener(any())).thenAnswer { - (it.arguments[0] as Animator.AnimatorListener) - .onAnimationEnd(mock(Animator::class.java)) + (it.arguments[0] as Animator.AnimatorListener).onAnimationEnd( + mock(Animator::class.java) + ) this } } @@ -179,20 +175,21 @@ class SidefpsControllerTest : SysuiTestCase() { displayBounds = Rect(0, 0, displayWidth, displayHeight) var locations = listOf(sensorLocation) - whenEver(fingerprintManager.sensorPropertiesInternal).thenReturn( - listOf( - FingerprintSensorPropertiesInternal( - SENSOR_ID, - SensorProperties.STRENGTH_STRONG, - 5 /* maxEnrollmentsPerUser */, - listOf() /* componentInfo */, - FingerprintSensorProperties.TYPE_POWER_BUTTON, - true /* halControlsIllumination */, - true /* resetLockoutRequiresHardwareAuthToken */, - locations + whenEver(fingerprintManager.sensorPropertiesInternal) + .thenReturn( + listOf( + FingerprintSensorPropertiesInternal( + SENSOR_ID, + SensorProperties.STRENGTH_STRONG, + 5 /* maxEnrollmentsPerUser */, + listOf() /* componentInfo */, + FingerprintSensorProperties.TYPE_POWER_BUTTON, + true /* halControlsIllumination */, + true /* resetLockoutRequiresHardwareAuthToken */, + locations + ) ) ) - ) val displayInfo = DisplayInfo() displayInfo.initInfo() @@ -200,22 +197,29 @@ class SidefpsControllerTest : SysuiTestCase() { val display = Display(dmGlobal, DISPLAY_ID, displayInfo, DEFAULT_DISPLAY_ADJUSTMENTS) whenEver(dmGlobal.getDisplayInfo(eq(DISPLAY_ID))).thenReturn(displayInfo) whenEver(windowManager.defaultDisplay).thenReturn(display) - whenEver(windowManager.maximumWindowMetrics).thenReturn( - WindowMetrics(displayBounds, WindowInsets.CONSUMED) - ) - whenEver(windowManager.currentWindowMetrics).thenReturn( - WindowMetrics(displayBounds, windowInsets) - ) - - sideFpsController = SidefpsController( - context.createDisplayContext(display), layoutInflater, fingerprintManager, - windowManager, activityTaskManager, overviewProxyService, displayManager, executor, - handler - ) - - overlayController = ArgumentCaptor.forClass(ISidefpsController::class.java).apply { - verify(fingerprintManager).setSidefpsController(capture()) - }.value + whenEver(windowManager.maximumWindowMetrics) + .thenReturn(WindowMetrics(displayBounds, WindowInsets.CONSUMED)) + whenEver(windowManager.currentWindowMetrics) + .thenReturn(WindowMetrics(displayBounds, windowInsets)) + + sideFpsController = + SideFpsController( + context.createDisplayContext(display), + layoutInflater, + fingerprintManager, + windowManager, + activityTaskManager, + overviewProxyService, + displayManager, + executor, + handler, + dumpManager + ) + + overlayController = + ArgumentCaptor.forClass(ISidefpsController::class.java) + .apply { verify(fingerprintManager).setSidefpsController(capture()) } + .value block() } @@ -272,10 +276,7 @@ class SidefpsControllerTest : SysuiTestCase() { verify(windowManager).removeView(any()) } - @Test - fun testIgnoredForKeyguard() = testWithDisplay { - testIgnoredFor(REASON_AUTH_KEYGUARD) - } + @Test fun testIgnoredForKeyguard() = testWithDisplay { testIgnoredFor(REASON_AUTH_KEYGUARD) } @Test fun testShowsForMostSettings() = testWithDisplay { @@ -297,88 +298,76 @@ class SidefpsControllerTest : SysuiTestCase() { } @Test - fun showsWithTaskbar() = testWithDisplay( - deviceConfig = DeviceConfig.X_ALIGNED, - { rotation = Surface.ROTATION_0 } - ) { - hidesWithTaskbar(visible = true) - } + fun showsWithTaskbar() = + testWithDisplay(deviceConfig = DeviceConfig.X_ALIGNED, { rotation = Surface.ROTATION_0 }) { + hidesWithTaskbar(visible = true) + } @Test - fun showsWithTaskbarOnY() = testWithDisplay( - deviceConfig = DeviceConfig.Y_ALIGNED_UNFOLDED, - { rotation = Surface.ROTATION_0 } - ) { - hidesWithTaskbar(visible = true) - } + fun showsWithTaskbarOnY() = + testWithDisplay( + deviceConfig = DeviceConfig.Y_ALIGNED_UNFOLDED, + { rotation = Surface.ROTATION_0 } + ) { hidesWithTaskbar(visible = true) } @Test - fun showsWithTaskbar90() = testWithDisplay( - deviceConfig = DeviceConfig.X_ALIGNED, - { rotation = Surface.ROTATION_90 } - ) { - hidesWithTaskbar(visible = true) - } + fun showsWithTaskbar90() = + testWithDisplay(deviceConfig = DeviceConfig.X_ALIGNED, { rotation = Surface.ROTATION_90 }) { + hidesWithTaskbar(visible = true) + } @Test - fun showsWithTaskbar90OnY() = testWithDisplay( - deviceConfig = DeviceConfig.Y_ALIGNED_UNFOLDED, - { rotation = Surface.ROTATION_90 } - ) { - hidesWithTaskbar(visible = true) - } + fun showsWithTaskbar90OnY() = + testWithDisplay( + deviceConfig = DeviceConfig.Y_ALIGNED_UNFOLDED, + { rotation = Surface.ROTATION_90 } + ) { hidesWithTaskbar(visible = true) } @Test - fun showsWithTaskbar180() = testWithDisplay( - deviceConfig = DeviceConfig.X_ALIGNED, - { rotation = Surface.ROTATION_180 } - ) { - hidesWithTaskbar(visible = true) - } + fun showsWithTaskbar180() = + testWithDisplay( + deviceConfig = DeviceConfig.X_ALIGNED, + { rotation = Surface.ROTATION_180 } + ) { hidesWithTaskbar(visible = true) } @Test - fun showsWithTaskbar270OnY() = testWithDisplay( - deviceConfig = DeviceConfig.Y_ALIGNED_UNFOLDED, - { rotation = Surface.ROTATION_270 } - ) { - hidesWithTaskbar(visible = true) - } + fun showsWithTaskbar270OnY() = + testWithDisplay( + deviceConfig = DeviceConfig.Y_ALIGNED_UNFOLDED, + { rotation = Surface.ROTATION_270 } + ) { hidesWithTaskbar(visible = true) } @Test - fun showsWithTaskbarCollapsedDown() = testWithDisplay( - deviceConfig = DeviceConfig.X_ALIGNED, - { rotation = Surface.ROTATION_270 }, - windowInsets = insetsForSmallNavbar() - ) { - hidesWithTaskbar(visible = true) - } + fun showsWithTaskbarCollapsedDown() = + testWithDisplay( + deviceConfig = DeviceConfig.X_ALIGNED, + { rotation = Surface.ROTATION_270 }, + windowInsets = insetsForSmallNavbar() + ) { hidesWithTaskbar(visible = true) } @Test - fun showsWithTaskbarCollapsedDownOnY() = testWithDisplay( - deviceConfig = DeviceConfig.Y_ALIGNED_UNFOLDED, - { rotation = Surface.ROTATION_180 }, - windowInsets = insetsForSmallNavbar() - ) { - hidesWithTaskbar(visible = true) - } + fun showsWithTaskbarCollapsedDownOnY() = + testWithDisplay( + deviceConfig = DeviceConfig.Y_ALIGNED_UNFOLDED, + { rotation = Surface.ROTATION_180 }, + windowInsets = insetsForSmallNavbar() + ) { hidesWithTaskbar(visible = true) } @Test - fun hidesWithTaskbarDown() = testWithDisplay( - deviceConfig = DeviceConfig.X_ALIGNED, - { rotation = Surface.ROTATION_180 }, - windowInsets = insetsForLargeNavbar() - ) { - hidesWithTaskbar(visible = false) - } + fun hidesWithTaskbarDown() = + testWithDisplay( + deviceConfig = DeviceConfig.X_ALIGNED, + { rotation = Surface.ROTATION_180 }, + windowInsets = insetsForLargeNavbar() + ) { hidesWithTaskbar(visible = false) } @Test - fun hidesWithTaskbarDownOnY() = testWithDisplay( - deviceConfig = DeviceConfig.Y_ALIGNED_UNFOLDED, - { rotation = Surface.ROTATION_270 }, - windowInsets = insetsForLargeNavbar() - ) { - hidesWithTaskbar(visible = true) - } + fun hidesWithTaskbarDownOnY() = + testWithDisplay( + deviceConfig = DeviceConfig.Y_ALIGNED_UNFOLDED, + { rotation = Surface.ROTATION_270 }, + windowInsets = insetsForLargeNavbar() + ) { hidesWithTaskbar(visible = true) } private fun hidesWithTaskbar(visible: Boolean) { overlayController.show(SENSOR_ID, REASON_UNKNOWN) @@ -389,43 +378,35 @@ class SidefpsControllerTest : SysuiTestCase() { verify(windowManager).addView(any(), any()) verify(windowManager, never()).removeView(any()) - verify(sidefpsView).visibility = if (visible) View.VISIBLE else View.GONE + verify(sideFpsView).visibility = if (visible) View.VISIBLE else View.GONE } @Test - fun testIndicatorPlacementForXAlignedSensor() = testWithDisplay( - deviceConfig = DeviceConfig.X_ALIGNED - ) { - overlayController.show(SENSOR_ID, REASON_UNKNOWN) - sideFpsController.overlayOffsets = sensorLocation - sideFpsController.updateOverlayParams( - windowManager.defaultDisplay, - indicatorBounds - ) - executor.runAllReady() + fun testIndicatorPlacementForXAlignedSensor() = + testWithDisplay(deviceConfig = DeviceConfig.X_ALIGNED) { + overlayController.show(SENSOR_ID, REASON_UNKNOWN) + sideFpsController.overlayOffsets = sensorLocation + sideFpsController.updateOverlayParams(windowManager.defaultDisplay, indicatorBounds) + executor.runAllReady() - verify(windowManager).updateViewLayout(any(), overlayViewParamsCaptor.capture()) + verify(windowManager).updateViewLayout(any(), overlayViewParamsCaptor.capture()) - assertThat(overlayViewParamsCaptor.value.x).isEqualTo(sensorLocation.sensorLocationX) - assertThat(overlayViewParamsCaptor.value.y).isEqualTo(0) - } + assertThat(overlayViewParamsCaptor.value.x).isEqualTo(sensorLocation.sensorLocationX) + assertThat(overlayViewParamsCaptor.value.y).isEqualTo(0) + } @Test - fun testIndicatorPlacementForYAlignedSensor() = testWithDisplay( - deviceConfig = DeviceConfig.Y_ALIGNED_UNFOLDED - ) { - sideFpsController.overlayOffsets = sensorLocation - sideFpsController.updateOverlayParams( - windowManager.defaultDisplay, - indicatorBounds - ) - overlayController.show(SENSOR_ID, REASON_UNKNOWN) - executor.runAllReady() + fun testIndicatorPlacementForYAlignedSensor() = + testWithDisplay(deviceConfig = DeviceConfig.Y_ALIGNED_UNFOLDED) { + sideFpsController.overlayOffsets = sensorLocation + sideFpsController.updateOverlayParams(windowManager.defaultDisplay, indicatorBounds) + overlayController.show(SENSOR_ID, REASON_UNKNOWN) + executor.runAllReady() - verify(windowManager).updateViewLayout(any(), overlayViewParamsCaptor.capture()) - assertThat(overlayViewParamsCaptor.value.x).isEqualTo(displayWidth - boundsWidth) - assertThat(overlayViewParamsCaptor.value.y).isEqualTo(sensorLocation.sensorLocationY) - } + verify(windowManager).updateViewLayout(any(), overlayViewParamsCaptor.capture()) + assertThat(overlayViewParamsCaptor.value.x).isEqualTo(displayWidth - boundsWidth) + assertThat(overlayViewParamsCaptor.value.y).isEqualTo(sensorLocation.sensorLocationY) + } @Test fun hasSideFpsSensor_withSensorProps_returnsTrue() = testWithDisplay { @@ -442,52 +423,50 @@ class SidefpsControllerTest : SysuiTestCase() { } @Test - fun testLayoutParams_hasNoMoveAnimationWindowFlag() = testWithDisplay( - deviceConfig = DeviceConfig.Y_ALIGNED_UNFOLDED - ) { - sideFpsController.overlayOffsets = sensorLocation - sideFpsController.updateOverlayParams( - windowManager.defaultDisplay, - indicatorBounds - ) - overlayController.show(SENSOR_ID, REASON_UNKNOWN) - executor.runAllReady() + fun testLayoutParams_hasNoMoveAnimationWindowFlag() = + testWithDisplay(deviceConfig = DeviceConfig.Y_ALIGNED_UNFOLDED) { + sideFpsController.overlayOffsets = sensorLocation + sideFpsController.updateOverlayParams(windowManager.defaultDisplay, indicatorBounds) + overlayController.show(SENSOR_ID, REASON_UNKNOWN) + executor.runAllReady() - verify(windowManager).updateViewLayout(any(), overlayViewParamsCaptor.capture()) + verify(windowManager).updateViewLayout(any(), overlayViewParamsCaptor.capture()) - val lpFlags = overlayViewParamsCaptor.value.privateFlags + val lpFlags = overlayViewParamsCaptor.value.privateFlags - assertThat((lpFlags and PRIVATE_FLAG_NO_MOVE_ANIMATION) != 0).isTrue() - } + assertThat((lpFlags and PRIVATE_FLAG_NO_MOVE_ANIMATION) != 0).isTrue() + } @Test - fun testLayoutParams_hasTrustedOverlayWindowFlag() = testWithDisplay( - deviceConfig = DeviceConfig.Y_ALIGNED_UNFOLDED - ) { - sideFpsController.overlayOffsets = sensorLocation - sideFpsController.updateOverlayParams( - windowManager.defaultDisplay, - indicatorBounds - ) - overlayController.show(SENSOR_ID, REASON_UNKNOWN) - executor.runAllReady() + fun testLayoutParams_hasTrustedOverlayWindowFlag() = + testWithDisplay(deviceConfig = DeviceConfig.Y_ALIGNED_UNFOLDED) { + sideFpsController.overlayOffsets = sensorLocation + sideFpsController.updateOverlayParams(windowManager.defaultDisplay, indicatorBounds) + overlayController.show(SENSOR_ID, REASON_UNKNOWN) + executor.runAllReady() - verify(windowManager).updateViewLayout(any(), overlayViewParamsCaptor.capture()) + verify(windowManager).updateViewLayout(any(), overlayViewParamsCaptor.capture()) - val lpFlags = overlayViewParamsCaptor.value.privateFlags + val lpFlags = overlayViewParamsCaptor.value.privateFlags - assertThat((lpFlags and PRIVATE_FLAG_TRUSTED_OVERLAY) != 0).isTrue() - } + assertThat((lpFlags and PRIVATE_FLAG_TRUSTED_OVERLAY) != 0).isTrue() + } } private fun insetsForSmallNavbar() = insetsWithBottom(60) + private fun insetsForLargeNavbar() = insetsWithBottom(100) -private fun insetsWithBottom(bottom: Int) = WindowInsets.Builder() - .setInsets(WindowInsets.Type.navigationBars(), Insets.of(0, 0, 0, bottom)) - .build() + +private fun insetsWithBottom(bottom: Int) = + WindowInsets.Builder() + .setInsets(WindowInsets.Type.navigationBars(), Insets.of(0, 0, 0, bottom)) + .build() private fun fpEnrollTask() = settingsTask(".biometrics.fingerprint.FingerprintEnrollEnrolling") + private fun fpSettingsTask() = settingsTask(".biometrics.fingerprint.FingerprintSettings") -private fun settingsTask(cls: String) = ActivityManager.RunningTaskInfo().apply { - topActivity = ComponentName.createRelative("com.android.settings", cls) -} + +private fun settingsTask(cls: String) = + ActivityManager.RunningTaskInfo().apply { + topActivity = ComponentName.createRelative("com.android.settings", cls) + } diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt index 90948ff3b769..53bc2c231d0c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt @@ -43,7 +43,7 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.animation.ActivityLaunchAnimator import com.android.systemui.dump.DumpManager import com.android.systemui.flags.FeatureFlags -import com.android.systemui.keyguard.domain.interactor.BouncerInteractor +import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.shade.ShadeExpansionStateManager import com.android.systemui.statusbar.LockscreenShadeTransitionController @@ -106,7 +106,7 @@ class UdfpsControllerOverlayTest : SysuiTestCase() { @Mock private lateinit var udfpsEnrollView: UdfpsEnrollView @Mock private lateinit var activityLaunchAnimator: ActivityLaunchAnimator @Mock private lateinit var featureFlags: FeatureFlags - @Mock private lateinit var bouncerInteractor: BouncerInteractor + @Mock private lateinit var mPrimaryBouncerInteractor: PrimaryBouncerInteractor @Captor private lateinit var layoutParamsCaptor: ArgumentCaptor<WindowManager.LayoutParams> private val onTouch = { _: View, _: MotionEvent, _: Boolean -> true } @@ -141,7 +141,7 @@ class UdfpsControllerOverlayTest : SysuiTestCase() { configurationController, systemClock, keyguardStateController, unlockedScreenOffAnimationController, udfpsDisplayMode, REQUEST_ID, reason, controllerCallback, onTouch, activityLaunchAnimator, featureFlags, - bouncerInteractor, isDebuggable + mPrimaryBouncerInteractor, isDebuggable ) block() } @@ -191,10 +191,11 @@ class UdfpsControllerOverlayTest : SysuiTestCase() { val sensorBounds = Rect(0, 0, SENSOR_WIDTH, SENSOR_HEIGHT) overlayParams = UdfpsOverlayParams( sensorBounds, + sensorBounds, DISPLAY_WIDTH, DISPLAY_HEIGHT, scaleFactor = 1f, - rotation + rotation = rotation ) block() } diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java index be39c0de22a1..1b5f9b6d45cd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java @@ -20,6 +20,8 @@ import static android.view.MotionEvent.ACTION_DOWN; import static android.view.MotionEvent.ACTION_MOVE; import static android.view.MotionEvent.ACTION_UP; +import static com.android.internal.util.FunctionalUtils.ThrowingConsumer; + import static junit.framework.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; @@ -71,7 +73,7 @@ import com.android.systemui.animation.ActivityLaunchAnimator; import com.android.systemui.dump.DumpManager; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.keyguard.ScreenLifecycle; -import com.android.systemui.keyguard.domain.interactor.BouncerInteractor; +import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.shade.ShadeExpansionStateManager; @@ -108,9 +110,6 @@ import java.util.Optional; @RunWithLooper(setAsMainLooper = true) public class UdfpsControllerTest extends SysuiTestCase { - // Use this for inputs going into SystemUI. Use UdfpsController.mUdfpsSensorId for things - // leaving SystemUI. - private static final int TEST_UDFPS_SENSOR_ID = 1; private static final long TEST_REQUEST_ID = 70; @Rule @@ -121,7 +120,6 @@ public class UdfpsControllerTest extends SysuiTestCase { // Dependencies private FakeExecutor mBiometricsExecutor; - private Execution mExecution; @Mock private LayoutInflater mLayoutInflater; @Mock @@ -129,8 +127,6 @@ public class UdfpsControllerTest extends SysuiTestCase { @Mock private WindowManager mWindowManager; @Mock - private UdfpsDisplayModeProvider mDisplayModeProvider; - @Mock private StatusBarStateController mStatusBarStateController; @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; @@ -196,20 +192,27 @@ public class UdfpsControllerTest extends SysuiTestCase { @Mock private AlternateUdfpsTouchProvider mAlternateTouchProvider; @Mock - private BouncerInteractor mBouncerInteractor; + private PrimaryBouncerInteractor mPrimaryBouncerInteractor; // Capture listeners so that they can be used to send events - @Captor private ArgumentCaptor<IUdfpsOverlayController> mOverlayCaptor; + @Captor + private ArgumentCaptor<IUdfpsOverlayController> mOverlayCaptor; private IUdfpsOverlayController mOverlayController; - @Captor private ArgumentCaptor<UdfpsView.OnTouchListener> mTouchListenerCaptor; - @Captor private ArgumentCaptor<View.OnHoverListener> mHoverListenerCaptor; - @Captor private ArgumentCaptor<Runnable> mOnDisplayConfiguredCaptor; - @Captor private ArgumentCaptor<ScreenLifecycle.Observer> mScreenObserverCaptor; + @Captor + private ArgumentCaptor<UdfpsView.OnTouchListener> mTouchListenerCaptor; + @Captor + private ArgumentCaptor<View.OnHoverListener> mHoverListenerCaptor; + @Captor + private ArgumentCaptor<Runnable> mOnDisplayConfiguredCaptor; + @Captor + private ArgumentCaptor<ScreenLifecycle.Observer> mScreenObserverCaptor; private ScreenLifecycle.Observer mScreenObserver; + private FingerprintSensorPropertiesInternal mOpticalProps; + private FingerprintSensorPropertiesInternal mUltrasonicProps; @Before public void setUp() { - mExecution = new FakeExecution(); + Execution execution = new FakeExecution(); when(mLayoutInflater.inflate(R.layout.udfps_view, null, false)) .thenReturn(mUdfpsView); @@ -222,9 +225,7 @@ public class UdfpsControllerTest extends SysuiTestCase { when(mLayoutInflater.inflate(R.layout.udfps_fpm_other_view, null)) .thenReturn(mFpmOtherView); when(mEnrollView.getContext()).thenReturn(mContext); - when(mKeyguardStateController.isOccluded()).thenReturn(false); when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(true); - final List<FingerprintSensorPropertiesInternal> props = new ArrayList<>(); final List<ComponentInfoInternal> componentInfo = new ArrayList<>(); componentInfo.add(new ComponentInfoInternal("faceSensor" /* componentId */, @@ -234,13 +235,25 @@ public class UdfpsControllerTest extends SysuiTestCase { "" /* hardwareVersion */, "" /* firmwareVersion */, "" /* serialNumber */, "vendor/version/revision" /* softwareVersion */)); - props.add(new FingerprintSensorPropertiesInternal(TEST_UDFPS_SENSOR_ID, + mOpticalProps = new FingerprintSensorPropertiesInternal(1 /* sensorId */, SensorProperties.STRENGTH_STRONG, 5 /* maxEnrollmentsPerUser */, componentInfo, FingerprintSensorProperties.TYPE_UDFPS_OPTICAL, - true /* resetLockoutRequiresHardwareAuthToken */)); + true /* resetLockoutRequiresHardwareAuthToken */); + + mUltrasonicProps = new FingerprintSensorPropertiesInternal(2 /* sensorId */, + SensorProperties.STRENGTH_STRONG, + 5 /* maxEnrollmentsPerUser */, + componentInfo, + FingerprintSensorProperties.TYPE_UDFPS_ULTRASONIC, + true /* resetLockoutRequiresHardwareAuthToken */); + + List<FingerprintSensorPropertiesInternal> props = new ArrayList<>(); + props.add(mOpticalProps); + props.add(mUltrasonicProps); when(mFingerprintManager.getSensorPropertiesInternal()).thenReturn(props); + mFgExecutor = new FakeExecutor(new FakeSystemClock()); // Create a fake background executor. @@ -248,7 +261,7 @@ public class UdfpsControllerTest extends SysuiTestCase { mUdfpsController = new UdfpsController( mContext, - mExecution, + execution, mLayoutInflater, mFingerprintManager, mWindowManager, @@ -278,18 +291,18 @@ public class UdfpsControllerTest extends SysuiTestCase { mActivityLaunchAnimator, Optional.of(mAlternateTouchProvider), mBiometricsExecutor, - mBouncerInteractor); + mPrimaryBouncerInteractor); verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture()); mOverlayController = mOverlayCaptor.getValue(); verify(mScreenLifecycle).addObserver(mScreenObserverCaptor.capture()); mScreenObserver = mScreenObserverCaptor.getValue(); - mUdfpsController.updateOverlayParams(TEST_UDFPS_SENSOR_ID, new UdfpsOverlayParams()); + mUdfpsController.updateOverlayParams(mOpticalProps, new UdfpsOverlayParams()); mUdfpsController.setUdfpsDisplayMode(mUdfpsDisplayMode); } @Test public void dozeTimeTick() throws RemoteException { - mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID, + mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId, BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback); mFgExecutor.runAllReady(); mUdfpsController.dozeTimeTick(); @@ -304,7 +317,7 @@ public class UdfpsControllerTest extends SysuiTestCase { when(mUdfpsView.getAnimationViewController()).thenReturn(mUdfpsKeyguardViewController); // GIVEN that the overlay is showing - mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID, + mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId, BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback); mFgExecutor.runAllReady(); @@ -339,7 +352,7 @@ public class UdfpsControllerTest extends SysuiTestCase { when(mUdfpsView.getAnimationViewController()).thenReturn(mUdfpsKeyguardViewController); // GIVEN that the overlay is showing - mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID, + mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId, BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback); mFgExecutor.runAllReady(); @@ -347,7 +360,7 @@ public class UdfpsControllerTest extends SysuiTestCase { verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture()); MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0); if (stale) { - mOverlayController.hideUdfpsOverlay(TEST_UDFPS_SENSOR_ID); + mOverlayController.hideUdfpsOverlay(mOpticalProps.sensorId); mFgExecutor.runAllReady(); } mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent); @@ -367,7 +380,7 @@ public class UdfpsControllerTest extends SysuiTestCase { when(mUdfpsView.getAnimationViewController()).thenReturn(mUdfpsKeyguardViewController); // GIVEN that the overlay is showing - mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID, + mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId, BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback); mFgExecutor.runAllReady(); @@ -390,27 +403,27 @@ public class UdfpsControllerTest extends SysuiTestCase { @Test public void hideUdfpsOverlay_resetsAltAuthBouncerWhenShowing() throws RemoteException { // GIVEN overlay was showing and the udfps bouncer is showing - mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID, + mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId, BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback); - when(mStatusBarKeyguardViewManager.isShowingAlternateAuth()).thenReturn(true); + when(mStatusBarKeyguardViewManager.isShowingAlternateBouncer()).thenReturn(true); // WHEN the overlay is hidden - mOverlayController.hideUdfpsOverlay(TEST_UDFPS_SENSOR_ID); + mOverlayController.hideUdfpsOverlay(mOpticalProps.sensorId); mFgExecutor.runAllReady(); // THEN the udfps bouncer is reset - verify(mStatusBarKeyguardViewManager).resetAlternateAuth(eq(true)); + verify(mStatusBarKeyguardViewManager).hideAlternateBouncer(eq(true)); } @Test public void testSubscribesToOrientationChangesWhenShowingOverlay() throws Exception { - mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID, + mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId, BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback); mFgExecutor.runAllReady(); verify(mDisplayManager).registerDisplayListener(any(), eq(mHandler), anyLong()); - mOverlayController.hideUdfpsOverlay(TEST_UDFPS_SENSOR_ID); + mOverlayController.hideUdfpsOverlay(mOpticalProps.sensorId); mFgExecutor.runAllReady(); verify(mDisplayManager).unregisterDisplayListener(any()); @@ -424,39 +437,45 @@ public class UdfpsControllerTest extends SysuiTestCase { final float[] scaleFactor = new float[]{1f, displayHeight[1] / (float) displayHeight[0]}; final int[] rotation = new int[]{Surface.ROTATION_0, Surface.ROTATION_90}; final UdfpsOverlayParams oldParams = new UdfpsOverlayParams(sensorBounds[0], - displayWidth[0], displayHeight[0], scaleFactor[0], rotation[0]); - - for (int i1 = 0; i1 <= 1; ++i1) - for (int i2 = 0; i2 <= 1; ++i2) - for (int i3 = 0; i3 <= 1; ++i3) - for (int i4 = 0; i4 <= 1; ++i4) - for (int i5 = 0; i5 <= 1; ++i5) { - final UdfpsOverlayParams newParams = new UdfpsOverlayParams(sensorBounds[i1], - displayWidth[i2], displayHeight[i3], scaleFactor[i4], rotation[i5]); - - if (newParams.equals(oldParams)) { - continue; + sensorBounds[0], displayWidth[0], displayHeight[0], scaleFactor[0], rotation[0]); + + for (int i1 = 0; i1 <= 1; ++i1) { + for (int i2 = 0; i2 <= 1; ++i2) { + for (int i3 = 0; i3 <= 1; ++i3) { + for (int i4 = 0; i4 <= 1; ++i4) { + for (int i5 = 0; i5 <= 1; ++i5) { + final UdfpsOverlayParams newParams = new UdfpsOverlayParams( + sensorBounds[i1], sensorBounds[i1], displayWidth[i2], + displayHeight[i3], scaleFactor[i4], rotation[i5]); + + if (newParams.equals(oldParams)) { + continue; + } + + // Initialize the overlay with old parameters. + mUdfpsController.updateOverlayParams(mOpticalProps, oldParams); + + // Show the overlay. + reset(mWindowManager); + mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, + mOpticalProps.sensorId, + BiometricOverlayConstants.REASON_ENROLL_ENROLLING, + mUdfpsOverlayControllerCallback); + mFgExecutor.runAllReady(); + verify(mWindowManager).addView(any(), any()); + + // Update overlay parameters. + reset(mWindowManager); + mUdfpsController.updateOverlayParams(mOpticalProps, newParams); + mFgExecutor.runAllReady(); + + // Ensure the overlay was recreated. + verify(mWindowManager).removeView(any()); + verify(mWindowManager).addView(any(), any()); + } + } + } } - - // Initialize the overlay with old parameters. - mUdfpsController.updateOverlayParams(TEST_UDFPS_SENSOR_ID, oldParams); - - // Show the overlay. - reset(mWindowManager); - mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID, - BiometricOverlayConstants.REASON_ENROLL_ENROLLING, - mUdfpsOverlayControllerCallback); - mFgExecutor.runAllReady(); - verify(mWindowManager).addView(any(), any()); - - // Update overlay parameters. - reset(mWindowManager); - mUdfpsController.updateOverlayParams(TEST_UDFPS_SENSOR_ID, newParams); - mFgExecutor.runAllReady(); - - // Ensure the overlay was recreated. - verify(mWindowManager).removeView(any()); - verify(mWindowManager).addView(any(), any()); } } @@ -469,20 +488,20 @@ public class UdfpsControllerTest extends SysuiTestCase { final int rotation = Surface.ROTATION_0; // Initialize the overlay. - mUdfpsController.updateOverlayParams(TEST_UDFPS_SENSOR_ID, - new UdfpsOverlayParams(sensorBounds, displayWidth, displayHeight, scaleFactor, - rotation)); + mUdfpsController.updateOverlayParams(mOpticalProps, + new UdfpsOverlayParams(sensorBounds, sensorBounds, displayWidth, displayHeight, + scaleFactor, rotation)); // Show the overlay. - mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID, + mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId, BiometricOverlayConstants.REASON_ENROLL_ENROLLING, mUdfpsOverlayControllerCallback); mFgExecutor.runAllReady(); verify(mWindowManager).addView(any(), any()); // Update overlay with the same parameters. - mUdfpsController.updateOverlayParams(TEST_UDFPS_SENSOR_ID, - new UdfpsOverlayParams(sensorBounds, displayWidth, displayHeight, scaleFactor, - rotation)); + mUdfpsController.updateOverlayParams(mOpticalProps, + new UdfpsOverlayParams(sensorBounds, sensorBounds, displayWidth, displayHeight, + scaleFactor, rotation)); mFgExecutor.runAllReady(); // Ensure the overlay was not recreated. @@ -522,15 +541,15 @@ public class UdfpsControllerTest extends SysuiTestCase { when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true); // Show the overlay. - mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID, + mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId, BiometricOverlayConstants.REASON_ENROLL_ENROLLING, mUdfpsOverlayControllerCallback); mFgExecutor.runAllReady(); verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture()); // Test ROTATION_0 - mUdfpsController.updateOverlayParams(TEST_UDFPS_SENSOR_ID, - new UdfpsOverlayParams(sensorBounds, displayWidth, displayHeight, scaleFactor, - Surface.ROTATION_0)); + mUdfpsController.updateOverlayParams(mOpticalProps, + new UdfpsOverlayParams(sensorBounds, sensorBounds, displayWidth, displayHeight, + scaleFactor, Surface.ROTATION_0)); MotionEvent event = obtainMotionEvent(ACTION_DOWN, displayWidth, displayHeight, touchMinor, touchMajor); mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event); @@ -545,9 +564,9 @@ public class UdfpsControllerTest extends SysuiTestCase { // Test ROTATION_90 reset(mAlternateTouchProvider); - mUdfpsController.updateOverlayParams(TEST_UDFPS_SENSOR_ID, - new UdfpsOverlayParams(sensorBounds, displayWidth, displayHeight, scaleFactor, - Surface.ROTATION_90)); + mUdfpsController.updateOverlayParams(mOpticalProps, + new UdfpsOverlayParams(sensorBounds, sensorBounds, displayWidth, displayHeight, + scaleFactor, Surface.ROTATION_90)); event = obtainMotionEvent(ACTION_DOWN, displayHeight, 0, touchMinor, touchMajor); mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event); mBiometricsExecutor.runAllReady(); @@ -561,9 +580,9 @@ public class UdfpsControllerTest extends SysuiTestCase { // Test ROTATION_270 reset(mAlternateTouchProvider); - mUdfpsController.updateOverlayParams(TEST_UDFPS_SENSOR_ID, - new UdfpsOverlayParams(sensorBounds, displayWidth, displayHeight, scaleFactor, - Surface.ROTATION_270)); + mUdfpsController.updateOverlayParams(mOpticalProps, + new UdfpsOverlayParams(sensorBounds, sensorBounds, displayWidth, displayHeight, + scaleFactor, Surface.ROTATION_270)); event = obtainMotionEvent(ACTION_DOWN, 0, displayWidth, touchMinor, touchMajor); mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event); mBiometricsExecutor.runAllReady(); @@ -577,9 +596,9 @@ public class UdfpsControllerTest extends SysuiTestCase { // Test ROTATION_180 reset(mAlternateTouchProvider); - mUdfpsController.updateOverlayParams(TEST_UDFPS_SENSOR_ID, - new UdfpsOverlayParams(sensorBounds, displayWidth, displayHeight, scaleFactor, - Surface.ROTATION_180)); + mUdfpsController.updateOverlayParams(mOpticalProps, + new UdfpsOverlayParams(sensorBounds, sensorBounds, displayWidth, displayHeight, + scaleFactor, Surface.ROTATION_180)); // ROTATION_180 is not supported. It should be treated like ROTATION_0. event = obtainMotionEvent(ACTION_DOWN, displayWidth, displayHeight, touchMinor, touchMajor); mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event); @@ -593,63 +612,108 @@ public class UdfpsControllerTest extends SysuiTestCase { eq(expectedY), eq(expectedMinor), eq(expectedMajor)); } + private void runForAllUdfpsTypes( + ThrowingConsumer<FingerprintSensorPropertiesInternal> sensorPropsConsumer) { + for (FingerprintSensorPropertiesInternal sensorProps : List.of(mOpticalProps, + mUltrasonicProps)) { + mUdfpsController.updateOverlayParams(sensorProps, new UdfpsOverlayParams()); + sensorPropsConsumer.accept(sensorProps); + } + } + @Test - public void fingerDown() throws RemoteException { + public void fingerDown() { + runForAllUdfpsTypes(this::fingerDownForSensor); + } + + private void fingerDownForSensor(FingerprintSensorPropertiesInternal sensorProps) + throws RemoteException { + reset(mUdfpsView, mAlternateTouchProvider, mFingerprintManager, mLatencyTracker, + mKeyguardUpdateMonitor); + // Configure UdfpsView to accept the ACTION_DOWN event when(mUdfpsView.isDisplayConfigured()).thenReturn(false); when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true); when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(true); // GIVEN that the overlay is showing - mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID, + mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, sensorProps.sensorId, BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback); mFgExecutor.runAllReady(); - // WHEN ACTION_DOWN is received verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture()); + + // WHEN ACTION_DOWN is received MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0); mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent); mBiometricsExecutor.runAllReady(); downEvent.recycle(); - MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0); - // FIX THIS TEST + MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0); mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent); mBiometricsExecutor.runAllReady(); moveEvent.recycle(); + mFgExecutor.runAllReady(); + // THEN FingerprintManager is notified about onPointerDown verify(mAlternateTouchProvider).onPointerDown(eq(TEST_REQUEST_ID), eq(0), eq(0), eq(0f), eq(0f)); verify(mFingerprintManager, never()).onPointerDown(anyLong(), anyInt(), anyInt(), anyInt(), anyFloat(), anyFloat()); - verify(mLatencyTracker).onActionStart(eq(LatencyTracker.ACTION_UDFPS_ILLUMINATE)); + // AND display configuration begins - verify(mUdfpsView).configureDisplay(mOnDisplayConfiguredCaptor.capture()); + if (sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) { + verify(mLatencyTracker).onActionStart(eq(LatencyTracker.ACTION_UDFPS_ILLUMINATE)); + verify(mUdfpsView).configureDisplay(mOnDisplayConfiguredCaptor.capture()); + } else { + verify(mLatencyTracker, never()).onActionStart( + eq(LatencyTracker.ACTION_UDFPS_ILLUMINATE)); + verify(mUdfpsView, never()).configureDisplay(any()); + } verify(mLatencyTracker, never()).onActionEnd(eq(LatencyTracker.ACTION_UDFPS_ILLUMINATE)); verify(mKeyguardUpdateMonitor).onUdfpsPointerDown(eq((int) TEST_REQUEST_ID)); - // AND onDisplayConfigured notifies FingerprintManager about onUiReady - mOnDisplayConfiguredCaptor.getValue().run(); - mBiometricsExecutor.runAllReady(); - InOrder inOrder = inOrder(mAlternateTouchProvider, mLatencyTracker); - inOrder.verify(mAlternateTouchProvider).onUiReady(); - inOrder.verify(mLatencyTracker).onActionEnd(eq(LatencyTracker.ACTION_UDFPS_ILLUMINATE)); + + if (sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) { + // AND onDisplayConfigured notifies FingerprintManager about onUiReady + mOnDisplayConfiguredCaptor.getValue().run(); + mBiometricsExecutor.runAllReady(); + InOrder inOrder = inOrder(mAlternateTouchProvider, mLatencyTracker); + inOrder.verify(mAlternateTouchProvider).onUiReady(); + inOrder.verify(mLatencyTracker).onActionEnd(eq(LatencyTracker.ACTION_UDFPS_ILLUMINATE)); + } else { + verify(mAlternateTouchProvider, never()).onUiReady(); + verify(mLatencyTracker, never()).onActionEnd( + eq(LatencyTracker.ACTION_UDFPS_ILLUMINATE)); + } } @Test - public void aodInterrupt() throws RemoteException { + public void aodInterrupt() { + runForAllUdfpsTypes(this::aodInterruptForSensor); + } + + private void aodInterruptForSensor(FingerprintSensorPropertiesInternal sensorProps) + throws RemoteException { + mUdfpsController.cancelAodInterrupt(); + reset(mUdfpsView, mAlternateTouchProvider, mFingerprintManager, mKeyguardUpdateMonitor); + when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(true); + // GIVEN that the overlay is showing and screen is on and fp is running - mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID, + mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, sensorProps.sensorId, BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback); mScreenObserver.onScreenTurnedOn(); mFgExecutor.runAllReady(); - when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(true); // WHEN fingerprint is requested because of AOD interrupt mUdfpsController.onAodInterrupt(0, 0, 2f, 3f); mFgExecutor.runAllReady(); - // THEN display configuration begins - // AND onDisplayConfigured notifies FingerprintManager about onUiReady - verify(mUdfpsView).configureDisplay(mOnDisplayConfiguredCaptor.capture()); - mOnDisplayConfiguredCaptor.getValue().run(); + if (sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) { + // THEN display configuration begins + // AND onDisplayConfigured notifies FingerprintManager about onUiReady + verify(mUdfpsView).configureDisplay(mOnDisplayConfiguredCaptor.capture()); + mOnDisplayConfiguredCaptor.getValue().run(); + } else { + verify(mUdfpsView, never()).configureDisplay(mOnDisplayConfiguredCaptor.capture()); + } mBiometricsExecutor.runAllReady(); verify(mAlternateTouchProvider).onPointerDown(eq(TEST_REQUEST_ID), eq(0), eq(0), eq(3f) /* minor */, eq(2f) /* major */); @@ -659,54 +723,92 @@ public class UdfpsControllerTest extends SysuiTestCase { } @Test - public void cancelAodInterrupt() throws RemoteException { + public void cancelAodInterrupt() { + runForAllUdfpsTypes(this::cancelAodInterruptForSensor); + } + + private void cancelAodInterruptForSensor(FingerprintSensorPropertiesInternal sensorProps) + throws RemoteException { + reset(mUdfpsView); + // GIVEN AOD interrupt - mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID, + mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, sensorProps.sensorId, BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback); mScreenObserver.onScreenTurnedOn(); mFgExecutor.runAllReady(); - when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(true); mUdfpsController.onAodInterrupt(0, 0, 0f, 0f); - when(mUdfpsView.isDisplayConfigured()).thenReturn(true); - // WHEN it is cancelled - mUdfpsController.cancelAodInterrupt(); - // THEN the display is unconfigured - verify(mUdfpsView).unconfigureDisplay(); + if (sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) { + when(mUdfpsView.isDisplayConfigured()).thenReturn(true); + // WHEN it is cancelled + mUdfpsController.cancelAodInterrupt(); + // THEN the display is unconfigured + verify(mUdfpsView).unconfigureDisplay(); + } else { + when(mUdfpsView.isDisplayConfigured()).thenReturn(false); + // WHEN it is cancelled + mUdfpsController.cancelAodInterrupt(); + // THEN the display configuration is unchanged. + verify(mUdfpsView, never()).unconfigureDisplay(); + } } @Test - public void aodInterruptTimeout() throws RemoteException { + public void aodInterruptTimeout() { + runForAllUdfpsTypes(this::aodInterruptTimeoutForSensor); + } + + private void aodInterruptTimeoutForSensor(FingerprintSensorPropertiesInternal sensorProps) + throws RemoteException { + reset(mUdfpsView); + // GIVEN AOD interrupt - mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID, + mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, sensorProps.sensorId, BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback); mScreenObserver.onScreenTurnedOn(); mFgExecutor.runAllReady(); - when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(true); mUdfpsController.onAodInterrupt(0, 0, 0f, 0f); mFgExecutor.runAllReady(); - when(mUdfpsView.isDisplayConfigured()).thenReturn(true); + if (sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) { + when(mUdfpsView.isDisplayConfigured()).thenReturn(true); + } else { + when(mUdfpsView.isDisplayConfigured()).thenReturn(false); + } // WHEN it times out mFgExecutor.advanceClockToNext(); mFgExecutor.runAllReady(); - // THEN the display is unconfigured - verify(mUdfpsView).unconfigureDisplay(); + if (sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) { + // THEN the display is unconfigured. + verify(mUdfpsView).unconfigureDisplay(); + } else { + // THEN the display configuration is unchanged. + verify(mUdfpsView, never()).unconfigureDisplay(); + } } @Test - public void aodInterruptCancelTimeoutActionOnFingerUp() throws RemoteException { + public void aodInterruptCancelTimeoutActionOnFingerUp() { + runForAllUdfpsTypes(this::aodInterruptCancelTimeoutActionOnFingerUpForSensor); + } + + private void aodInterruptCancelTimeoutActionOnFingerUpForSensor( + FingerprintSensorPropertiesInternal sensorProps) throws RemoteException { + reset(mUdfpsView); when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true); - when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(true); // GIVEN AOD interrupt - mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID, + mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, sensorProps.sensorId, BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback); mScreenObserver.onScreenTurnedOn(); mFgExecutor.runAllReady(); mUdfpsController.onAodInterrupt(0, 0, 0f, 0f); mFgExecutor.runAllReady(); - // Configure UdfpsView to accept the ACTION_UP event - when(mUdfpsView.isDisplayConfigured()).thenReturn(true); + if (sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) { + // Configure UdfpsView to accept the ACTION_UP event + when(mUdfpsView.isDisplayConfigured()).thenReturn(true); + } else { + when(mUdfpsView.isDisplayConfigured()).thenReturn(false); + } // WHEN ACTION_UP is received verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture()); @@ -731,37 +833,54 @@ public class UdfpsControllerTest extends SysuiTestCase { moveEvent.recycle(); mFgExecutor.runAllReady(); - // Configure UdfpsView to accept the finger up event - when(mUdfpsView.isDisplayConfigured()).thenReturn(true); + if (sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) { + // Configure UdfpsView to accept the finger up event + when(mUdfpsView.isDisplayConfigured()).thenReturn(true); + } else { + when(mUdfpsView.isDisplayConfigured()).thenReturn(false); + } // WHEN it times out mFgExecutor.advanceClockToNext(); mFgExecutor.runAllReady(); - // THEN the display should be unconfigured once. If the timeout action is not - // cancelled, the display would be unconfigured twice which would cause two - // FP attempts. - verify(mUdfpsView, times(1)).unconfigureDisplay(); + if (sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) { + // THEN the display should be unconfigured once. If the timeout action is not + // cancelled, the display would be unconfigured twice which would cause two + // FP attempts. + verify(mUdfpsView, times(1)).unconfigureDisplay(); + } else { + verify(mUdfpsView, never()).unconfigureDisplay(); + } } @Test - public void aodInterruptCancelTimeoutActionOnAcquired() throws RemoteException { + public void aodInterruptCancelTimeoutActionOnAcquired() { + runForAllUdfpsTypes(this::aodInterruptCancelTimeoutActionOnAcquiredForSensor); + } + + private void aodInterruptCancelTimeoutActionOnAcquiredForSensor( + FingerprintSensorPropertiesInternal sensorProps) throws RemoteException { + reset(mUdfpsView); when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true); - when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(true); // GIVEN AOD interrupt - mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID, + mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, sensorProps.sensorId, BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback); mScreenObserver.onScreenTurnedOn(); mFgExecutor.runAllReady(); mUdfpsController.onAodInterrupt(0, 0, 0f, 0f); mFgExecutor.runAllReady(); - // Configure UdfpsView to accept the acquired event - when(mUdfpsView.isDisplayConfigured()).thenReturn(true); + if (sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) { + // Configure UdfpsView to accept the acquired event + when(mUdfpsView.isDisplayConfigured()).thenReturn(true); + } else { + when(mUdfpsView.isDisplayConfigured()).thenReturn(false); + } // WHEN acquired is received - mOverlayController.onAcquired(TEST_UDFPS_SENSOR_ID, + mOverlayController.onAcquired(sensorProps.sensorId, BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_GOOD); // Configure UdfpsView to accept the ACTION_DOWN event @@ -781,29 +900,43 @@ public class UdfpsControllerTest extends SysuiTestCase { moveEvent.recycle(); mFgExecutor.runAllReady(); - // Configure UdfpsView to accept the finger up event - when(mUdfpsView.isDisplayConfigured()).thenReturn(true); + if (sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) { + // Configure UdfpsView to accept the finger up event + when(mUdfpsView.isDisplayConfigured()).thenReturn(true); + } else { + when(mUdfpsView.isDisplayConfigured()).thenReturn(false); + } // WHEN it times out mFgExecutor.advanceClockToNext(); mFgExecutor.runAllReady(); - // THEN the display should be unconfigured once. If the timeout action is not - // cancelled, the display would be unconfigured twice which would cause two - // FP attempts. - verify(mUdfpsView, times(1)).unconfigureDisplay(); + if (sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) { + // THEN the display should be unconfigured once. If the timeout action is not + // cancelled, the display would be unconfigured twice which would cause two + // FP attempts. + verify(mUdfpsView, times(1)).unconfigureDisplay(); + } else { + verify(mUdfpsView, never()).unconfigureDisplay(); + } } @Test - public void aodInterruptScreenOff() throws RemoteException { + public void aodInterruptScreenOff() { + runForAllUdfpsTypes(this::aodInterruptScreenOffForSensor); + } + + private void aodInterruptScreenOffForSensor(FingerprintSensorPropertiesInternal sensorProps) + throws RemoteException { + reset(mUdfpsView); + // GIVEN screen off - mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID, + mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, sensorProps.sensorId, BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback); mScreenObserver.onScreenTurnedOff(); mFgExecutor.runAllReady(); // WHEN aod interrupt is received - when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(true); mUdfpsController.onAodInterrupt(0, 0, 0f, 0f); // THEN display doesn't get configured because it's off @@ -811,9 +944,16 @@ public class UdfpsControllerTest extends SysuiTestCase { } @Test - public void aodInterrupt_fingerprintNotRunning() throws RemoteException { + public void aodInterrupt_fingerprintNotRunning() { + runForAllUdfpsTypes(this::aodInterrupt_fingerprintNotRunningForSensor); + } + + private void aodInterrupt_fingerprintNotRunningForSensor( + FingerprintSensorPropertiesInternal sensorProps) throws RemoteException { + reset(mUdfpsView); + // GIVEN showing overlay - mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID, + mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, sensorProps.sensorId, BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback); mScreenObserver.onScreenTurnedOn(); @@ -835,7 +975,7 @@ public class UdfpsControllerTest extends SysuiTestCase { // GIVEN that the overlay is showing and a11y touch exploration enabled when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(true); - mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID, + mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId, BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback); mFgExecutor.runAllReady(); @@ -870,7 +1010,7 @@ public class UdfpsControllerTest extends SysuiTestCase { // GIVEN that the overlay is showing and a11y touch exploration NOT enabled when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false); - mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID, + mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId, BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback); mFgExecutor.runAllReady(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerBaseTest.java index e5c7a42c06a6..75629f451526 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerBaseTest.java @@ -30,7 +30,7 @@ import com.android.systemui.dump.DumpManager; import com.android.systemui.flags.FakeFeatureFlags; import com.android.systemui.flags.Flags; import com.android.systemui.keyguard.KeyguardViewMediator; -import com.android.systemui.keyguard.domain.interactor.BouncerInteractor; +import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.shade.ShadeExpansionChangeEvent; import com.android.systemui.shade.ShadeExpansionListener; @@ -72,7 +72,7 @@ public class UdfpsKeyguardViewControllerBaseTest extends SysuiTestCase { protected @Mock UdfpsController mUdfpsController; protected @Mock ActivityLaunchAnimator mActivityLaunchAnimator; protected @Mock KeyguardBouncer mBouncer; - protected @Mock BouncerInteractor mBouncerInteractor; + protected @Mock PrimaryBouncerInteractor mPrimaryBouncerInteractor; protected FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags(); protected FakeSystemClock mSystemClock = new FakeSystemClock(); @@ -86,9 +86,9 @@ public class UdfpsKeyguardViewControllerBaseTest extends SysuiTestCase { private @Captor ArgumentCaptor<ShadeExpansionListener> mExpansionListenerCaptor; protected List<ShadeExpansionListener> mExpansionListeners; - private @Captor ArgumentCaptor<StatusBarKeyguardViewManager.AlternateAuthInterceptor> - mAltAuthInterceptorCaptor; - protected StatusBarKeyguardViewManager.AlternateAuthInterceptor mAltAuthInterceptor; + private @Captor ArgumentCaptor<StatusBarKeyguardViewManager.AlternateBouncer> + mAlternateBouncerCaptor; + protected StatusBarKeyguardViewManager.AlternateBouncer mAlternateBouncer; private @Captor ArgumentCaptor<KeyguardStateController.Callback> mKeyguardStateControllerCallbackCaptor; @@ -131,9 +131,9 @@ public class UdfpsKeyguardViewControllerBaseTest extends SysuiTestCase { } protected void captureAltAuthInterceptor() { - verify(mStatusBarKeyguardViewManager).setAlternateAuthInterceptor( - mAltAuthInterceptorCaptor.capture()); - mAltAuthInterceptor = mAltAuthInterceptorCaptor.getValue(); + verify(mStatusBarKeyguardViewManager).setAlternateBouncer( + mAlternateBouncerCaptor.capture()); + mAlternateBouncer = mAlternateBouncerCaptor.getValue(); } protected void captureKeyguardStateControllerCallback() { @@ -149,7 +149,7 @@ public class UdfpsKeyguardViewControllerBaseTest extends SysuiTestCase { protected UdfpsKeyguardViewController createUdfpsKeyguardViewController( boolean useModernBouncer) { mFeatureFlags.set(Flags.MODERN_BOUNCER, useModernBouncer); - when(mStatusBarKeyguardViewManager.getBouncer()).thenReturn( + when(mStatusBarKeyguardViewManager.getPrimaryBouncer()).thenReturn( useModernBouncer ? null : mBouncer); return new UdfpsKeyguardViewController( mView, @@ -167,6 +167,6 @@ public class UdfpsKeyguardViewControllerBaseTest extends SysuiTestCase { mUdfpsController, mActivityLaunchAnimator, mFeatureFlags, - mBouncerInteractor); + mPrimaryBouncerInteractor); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java index 55b61948ee45..16728b6f2ab9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java @@ -46,9 +46,9 @@ import org.mockito.Captor; @RunWith(AndroidTestingRunner.class) @RunWithLooper public class UdfpsKeyguardViewControllerTest extends UdfpsKeyguardViewControllerBaseTest { - private @Captor ArgumentCaptor<KeyguardBouncer.BouncerExpansionCallback> + private @Captor ArgumentCaptor<KeyguardBouncer.PrimaryBouncerExpansionCallback> mBouncerExpansionCallbackCaptor; - private KeyguardBouncer.BouncerExpansionCallback mBouncerExpansionCallback; + private KeyguardBouncer.PrimaryBouncerExpansionCallback mBouncerExpansionCallback; @Override public UdfpsKeyguardViewController createUdfpsKeyguardViewController() { @@ -63,7 +63,7 @@ public class UdfpsKeyguardViewControllerTest extends UdfpsKeyguardViewController captureBouncerExpansionCallback(); when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(true); - when(mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing()).thenReturn(true); + when(mStatusBarKeyguardViewManager.primaryBouncerIsOrWillBeShowing()).thenReturn(true); mBouncerExpansionCallback.onVisibilityChanged(true); assertTrue(mController.shouldPauseAuth()); @@ -239,13 +239,13 @@ public class UdfpsKeyguardViewControllerTest extends UdfpsKeyguardViewController sendStatusBarStateChanged(StatusBarState.SHADE_LOCKED); assertTrue(mController.shouldPauseAuth()); - mAltAuthInterceptor.showAlternateAuthBouncer(); // force show + mAlternateBouncer.showAlternateBouncer(); // force show assertFalse(mController.shouldPauseAuth()); - assertTrue(mAltAuthInterceptor.isShowingAlternateAuthBouncer()); + assertTrue(mAlternateBouncer.isShowingAlternateBouncer()); - mAltAuthInterceptor.hideAlternateAuthBouncer(); // stop force show + mAlternateBouncer.hideAlternateBouncer(); // stop force show assertTrue(mController.shouldPauseAuth()); - assertFalse(mAltAuthInterceptor.isShowingAlternateAuthBouncer()); + assertFalse(mAlternateBouncer.isShowingAlternateBouncer()); } @Test @@ -258,7 +258,7 @@ public class UdfpsKeyguardViewControllerTest extends UdfpsKeyguardViewController mController.onViewDetached(); // THEN remove alternate auth interceptor - verify(mStatusBarKeyguardViewManager).removeAlternateAuthInterceptor(mAltAuthInterceptor); + verify(mStatusBarKeyguardViewManager).removeAlternateAuthInterceptor(mAlternateBouncer); } @Test @@ -268,14 +268,15 @@ public class UdfpsKeyguardViewControllerTest extends UdfpsKeyguardViewController captureAltAuthInterceptor(); // GIVEN udfps bouncer isn't showing - mAltAuthInterceptor.hideAlternateAuthBouncer(); + mAlternateBouncer.hideAlternateBouncer(); // WHEN touch is observed outside the view mController.onTouchOutsideView(); // THEN bouncer / alt auth methods are never called + verify(mStatusBarKeyguardViewManager, never()).showPrimaryBouncer(anyBoolean()); verify(mStatusBarKeyguardViewManager, never()).showBouncer(anyBoolean()); - verify(mStatusBarKeyguardViewManager, never()).resetAlternateAuth(anyBoolean()); + verify(mStatusBarKeyguardViewManager, never()).hideAlternateBouncer(anyBoolean()); } @Test @@ -285,32 +286,33 @@ public class UdfpsKeyguardViewControllerTest extends UdfpsKeyguardViewController captureAltAuthInterceptor(); // GIVEN udfps bouncer is showing - mAltAuthInterceptor.showAlternateAuthBouncer(); + mAlternateBouncer.showAlternateBouncer(); // WHEN touch is observed outside the view 200ms later (just within threshold) mSystemClock.advanceTime(200); mController.onTouchOutsideView(); // THEN bouncer / alt auth methods are never called because not enough time has passed + verify(mStatusBarKeyguardViewManager, never()).showPrimaryBouncer(anyBoolean()); verify(mStatusBarKeyguardViewManager, never()).showBouncer(anyBoolean()); - verify(mStatusBarKeyguardViewManager, never()).resetAlternateAuth(anyBoolean()); + verify(mStatusBarKeyguardViewManager, never()).hideAlternateBouncer(anyBoolean()); } @Test - public void testShowingUdfpsBouncerOnTouchOutsideAboveThreshold_showInputBouncer() { + public void testShowingUdfpsBouncerOnTouchOutsideAboveThreshold_showPrimaryBouncer() { // GIVEN view is attached mController.onViewAttached(); captureAltAuthInterceptor(); // GIVEN udfps bouncer is showing - mAltAuthInterceptor.showAlternateAuthBouncer(); + mAlternateBouncer.showAlternateBouncer(); // WHEN touch is observed outside the view 205ms later mSystemClock.advanceTime(205); mController.onTouchOutsideView(); // THEN show the bouncer - verify(mStatusBarKeyguardViewManager).showBouncer(eq(true)); + verify(mStatusBarKeyguardViewManager).showPrimaryBouncer(eq(true)); } @Test @@ -341,7 +343,7 @@ public class UdfpsKeyguardViewControllerTest extends UdfpsKeyguardViewController when(mResourceContext.getString(anyInt())).thenReturn("test string"); // WHEN status bar expansion is 0 but udfps bouncer is requested - mAltAuthInterceptor.showAlternateAuthBouncer(); + mAlternateBouncer.showAlternateBouncer(); // THEN alpha is 255 verify(mView).setUnpausedAlpha(255); @@ -372,7 +374,7 @@ public class UdfpsKeyguardViewControllerTest extends UdfpsKeyguardViewController captureKeyguardStateControllerCallback(); captureAltAuthInterceptor(); updateStatusBarExpansion(1f, true); - mAltAuthInterceptor.showAlternateAuthBouncer(); + mAlternateBouncer.showAlternateBouncer(); reset(mView); // WHEN we're transitioning to the full shade diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt index 7b1976811868..68e744e53843 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt @@ -25,8 +25,8 @@ import com.android.systemui.classifier.FalsingCollector import com.android.systemui.keyguard.DismissCallbackRegistry import com.android.systemui.keyguard.data.BouncerView import com.android.systemui.keyguard.data.repository.KeyguardBouncerRepository -import com.android.systemui.keyguard.domain.interactor.BouncerCallbackInteractor -import com.android.systemui.keyguard.domain.interactor.BouncerInteractor +import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor +import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.phone.KeyguardBouncer import com.android.systemui.statusbar.phone.KeyguardBypassController @@ -59,14 +59,14 @@ class UdfpsKeyguardViewControllerWithCoroutinesTest : UdfpsKeyguardViewControlle } override fun createUdfpsKeyguardViewController(): UdfpsKeyguardViewController? { - mBouncerInteractor = - BouncerInteractor( + mPrimaryBouncerInteractor = + PrimaryBouncerInteractor( keyguardBouncerRepository, mock(BouncerView::class.java), mock(Handler::class.java), mKeyguardStateController, mock(KeyguardSecurityModel::class.java), - mock(BouncerCallbackInteractor::class.java), + mock(PrimaryBouncerCallbackInteractor::class.java), mock(FalsingCollector::class.java), mock(DismissCallbackRegistry::class.java), mock(KeyguardBypassController::class.java), @@ -86,7 +86,7 @@ class UdfpsKeyguardViewControllerWithCoroutinesTest : UdfpsKeyguardViewControlle // WHEN the bouncer expansion is VISIBLE val job = mController.listenForBouncerExpansion(this) - keyguardBouncerRepository.setVisible(true) + keyguardBouncerRepository.setPrimaryVisible(true) keyguardBouncerRepository.setPanelExpansion(KeyguardBouncer.EXPANSION_VISIBLE) yield() diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt index b78c06391057..d550b927154c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt @@ -40,8 +40,8 @@ import org.mockito.Mock import org.mockito.Mockito.never import org.mockito.Mockito.nullable import org.mockito.Mockito.verify -import org.mockito.Mockito.`when` as whenever import org.mockito.junit.MockitoJUnit +import org.mockito.Mockito.`when` as whenever private const val SENSOR_X = 50 private const val SENSOR_Y = 250 @@ -68,7 +68,8 @@ class UdfpsViewTest : SysuiTestCase() { view = LayoutInflater.from(context).inflate(R.layout.udfps_view, null) as UdfpsView view.animationViewController = animationViewController val sensorBounds = SensorLocationInternal("", SENSOR_X, SENSOR_Y, SENSOR_RADIUS).rect - view.overlayParams = UdfpsOverlayParams(sensorBounds, 1920, 1080, 1f, Surface.ROTATION_0) + view.overlayParams = UdfpsOverlayParams(sensorBounds, sensorBounds, 1920, + 1080, 1f, Surface.ROTATION_0) view.setUdfpsDisplayModeProvider(hbmProvider) ViewUtils.attachView(view) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java index 6bc7308a6a40..f8579fff488b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java @@ -39,6 +39,8 @@ import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.testing.FakeMetricsLogger; import com.android.systemui.SysuiTestCase; import com.android.systemui.classifier.FalsingDataProvider.GestureFinalizedListener; +import com.android.systemui.flags.FakeFeatureFlags; +import com.android.systemui.flags.Flags; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.time.FakeSystemClock; @@ -66,6 +68,8 @@ public class BrightLineClassifierTest extends SysuiTestCase { @Mock private SingleTapClassifier mSingleTapClassfier; @Mock + private LongTapClassifier mLongTapClassifier; + @Mock private DoubleTapClassifier mDoubleTapClassifier; @Mock private FalsingClassifier mClassifierA; @@ -80,6 +84,7 @@ public class BrightLineClassifierTest extends SysuiTestCase { private AccessibilityManager mAccessibilityManager; private final FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock()); + private final FakeFeatureFlags mFakeFeatureFlags = new FakeFeatureFlags(); private final FalsingClassifier.Result mFalsedResult = FalsingClassifier.Result.falsed(1, getClass().getSimpleName(), ""); @@ -94,6 +99,7 @@ public class BrightLineClassifierTest extends SysuiTestCase { when(mClassifierB.classifyGesture(anyInt(), anyDouble(), anyDouble())) .thenReturn(mPassedResult); when(mSingleTapClassfier.isTap(any(List.class), anyDouble())).thenReturn(mPassedResult); + when(mLongTapClassifier.isTap(any(List.class), anyDouble())).thenReturn(mFalsedResult); when(mDoubleTapClassifier.classifyGesture(anyInt(), anyDouble(), anyDouble())) .thenReturn(mPassedResult); mClassifiers.add(mClassifierA); @@ -101,9 +107,9 @@ public class BrightLineClassifierTest extends SysuiTestCase { when(mFalsingDataProvider.getRecentMotionEvents()).thenReturn(mMotionEventList); when(mKeyguardStateController.isShowing()).thenReturn(true); mBrightLineFalsingManager = new BrightLineFalsingManager(mFalsingDataProvider, - mMetricsLogger, mClassifiers, mSingleTapClassfier, mDoubleTapClassifier, - mHistoryTracker, mKeyguardStateController, mAccessibilityManager, - false); + mMetricsLogger, mClassifiers, mSingleTapClassfier, mLongTapClassifier, + mDoubleTapClassifier, mHistoryTracker, mKeyguardStateController, + mAccessibilityManager, false, mFakeFeatureFlags); ArgumentCaptor<GestureFinalizedListener> gestureCompleteListenerCaptor = @@ -113,6 +119,7 @@ public class BrightLineClassifierTest extends SysuiTestCase { gestureCompleteListenerCaptor.capture()); mGestureFinalizedListener = gestureCompleteListenerCaptor.getValue(); + mFakeFeatureFlags.set(Flags.FALSING_FOR_LONG_TAPS, true); } @Test @@ -212,7 +219,7 @@ public class BrightLineClassifierTest extends SysuiTestCase { } @Test - public void testIsFalseTap_EmptyRecentEvents() { + public void testIsFalseSingleTap_EmptyRecentEvents() { // Ensure we look at prior events if recent events has already been emptied. when(mFalsingDataProvider.getRecentMotionEvents()).thenReturn(new ArrayList<>()); when(mFalsingDataProvider.getPriorMotionEvents()).thenReturn(mMotionEventList); @@ -223,7 +230,7 @@ public class BrightLineClassifierTest extends SysuiTestCase { @Test - public void testIsFalseTap_RobustCheck_NoFaceAuth() { + public void testIsFalseSingleTap_RobustCheck_NoFaceAuth() { when(mSingleTapClassfier.isTap(mMotionEventList, 0)).thenReturn(mPassedResult); when(mDoubleTapClassifier.classifyGesture(anyInt(), anyDouble(), anyDouble())) .thenReturn(mFalsedResult); @@ -233,13 +240,50 @@ public class BrightLineClassifierTest extends SysuiTestCase { } @Test - public void testIsFalseTap_RobustCheck_FaceAuth() { + public void testIsFalseSingleTap_RobustCheck_FaceAuth() { when(mSingleTapClassfier.isTap(mMotionEventList, 0)).thenReturn(mPassedResult); when(mFalsingDataProvider.isJustUnlockedWithFace()).thenReturn(true); assertThat(mBrightLineFalsingManager.isFalseTap(NO_PENALTY)).isFalse(); } @Test + public void testIsFalseLongTap_EmptyRecentEvents() { + // Ensure we look at prior events if recent events has already been emptied. + when(mFalsingDataProvider.getRecentMotionEvents()).thenReturn(new ArrayList<>()); + when(mFalsingDataProvider.getPriorMotionEvents()).thenReturn(mMotionEventList); + + mBrightLineFalsingManager.isFalseLongTap(0); + verify(mLongTapClassifier).isTap(mMotionEventList, 0); + } + + @Test + public void testIsFalseLongTap_FalseLongTap_NotFlagged() { + mFakeFeatureFlags.set(Flags.FALSING_FOR_LONG_TAPS, false); + when(mLongTapClassifier.isTap(mMotionEventList, 0)).thenReturn(mFalsedResult); + assertThat(mBrightLineFalsingManager.isFalseLongTap(NO_PENALTY)).isFalse(); + } + + @Test + public void testIsFalseLongTap_FalseLongTap() { + when(mLongTapClassifier.isTap(mMotionEventList, 0)).thenReturn(mFalsedResult); + assertThat(mBrightLineFalsingManager.isFalseLongTap(NO_PENALTY)).isTrue(); + } + + @Test + public void testIsFalseLongTap_RobustCheck_NoFaceAuth() { + when(mLongTapClassifier.isTap(mMotionEventList, 0)).thenReturn(mPassedResult); + when(mFalsingDataProvider.isJustUnlockedWithFace()).thenReturn(false); + assertThat(mBrightLineFalsingManager.isFalseLongTap(NO_PENALTY)).isFalse(); + } + + @Test + public void testIsFalseLongTap_RobustCheck_FaceAuth() { + when(mLongTapClassifier.isTap(mMotionEventList, 0)).thenReturn(mPassedResult); + when(mFalsingDataProvider.isJustUnlockedWithFace()).thenReturn(true); + assertThat(mBrightLineFalsingManager.isFalseLongTap(NO_PENALTY)).isFalse(); + } + + @Test public void testIsFalseDoubleTap() { when(mDoubleTapClassifier.classifyGesture(anyInt(), anyDouble(), anyDouble())) .thenReturn(mPassedResult); diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineFalsingManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineFalsingManagerTest.java index b811aab6d35f..4281ee0f139f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineFalsingManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineFalsingManagerTest.java @@ -32,6 +32,8 @@ import androidx.test.filters.SmallTest; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.testing.FakeMetricsLogger; import com.android.systemui.SysuiTestCase; +import com.android.systemui.flags.FakeFeatureFlags; +import com.android.systemui.flags.Flags; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -57,6 +59,8 @@ public class BrightLineFalsingManagerTest extends SysuiTestCase { @Mock private SingleTapClassifier mSingleTapClassifier; @Mock + private LongTapClassifier mLongTapClassifier; + @Mock private DoubleTapClassifier mDoubleTapClassifier; @Mock private FalsingClassifier mClassifierA; @@ -71,6 +75,7 @@ public class BrightLineFalsingManagerTest extends SysuiTestCase { private final FalsingClassifier.Result mPassedResult = FalsingClassifier.Result.passed(1); private final FalsingClassifier.Result mFalsedResult = FalsingClassifier.Result.falsed(1, getClass().getSimpleName(), ""); + private final FakeFeatureFlags mFakeFeatureFlags = new FakeFeatureFlags(); @Before public void setup() { @@ -78,15 +83,17 @@ public class BrightLineFalsingManagerTest extends SysuiTestCase { when(mClassifierA.classifyGesture(anyInt(), anyDouble(), anyDouble())) .thenReturn(mFalsedResult); when(mSingleTapClassifier.isTap(any(List.class), anyDouble())).thenReturn(mFalsedResult); + when(mLongTapClassifier.isTap(any(List.class), anyDouble())).thenReturn(mFalsedResult); when(mDoubleTapClassifier.classifyGesture(anyInt(), anyDouble(), anyDouble())) .thenReturn(mFalsedResult); mClassifiers.add(mClassifierA); when(mFalsingDataProvider.getRecentMotionEvents()).thenReturn(mMotionEventList); when(mKeyguardStateController.isShowing()).thenReturn(true); mBrightLineFalsingManager = new BrightLineFalsingManager(mFalsingDataProvider, - mMetricsLogger, mClassifiers, mSingleTapClassifier, mDoubleTapClassifier, - mHistoryTracker, mKeyguardStateController, mAccessibilityManager, - false); + mMetricsLogger, mClassifiers, mSingleTapClassifier, mLongTapClassifier, + mDoubleTapClassifier, mHistoryTracker, mKeyguardStateController, + mAccessibilityManager, false, mFakeFeatureFlags); + mFakeFeatureFlags.set(Flags.FALSING_FOR_LONG_TAPS, true); } @Test @@ -105,6 +112,13 @@ public class BrightLineFalsingManagerTest extends SysuiTestCase { @Test + public void testA11yDisablesLongTap() { + assertThat(mBrightLineFalsingManager.isFalseLongTap(1)).isTrue(); + when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(true); + assertThat(mBrightLineFalsingManager.isFalseLongTap(1)).isFalse(); + } + + @Test public void testA11yDisablesDoubleTap() { assertThat(mBrightLineFalsingManager.isFalseDoubleTap()).isTrue(); when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(true); diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsEditingActivityTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsEditingActivityTest.kt new file mode 100644 index 000000000000..0b72a68005a6 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsEditingActivityTest.kt @@ -0,0 +1,112 @@ +package com.android.systemui.controls.management + +import android.content.ComponentName +import android.content.Intent +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper +import android.window.OnBackInvokedCallback +import android.window.OnBackInvokedDispatcher +import androidx.test.filters.SmallTest +import androidx.test.rule.ActivityTestRule +import androidx.test.runner.intercepting.SingleActivityFactory +import com.android.systemui.SysuiTestCase +import com.android.systemui.broadcast.BroadcastDispatcher +import com.android.systemui.controls.CustomIconCache +import com.android.systemui.controls.controller.ControlsControllerImpl +import com.android.systemui.controls.ui.ControlsUiController +import java.util.concurrent.CountDownLatch +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentCaptor +import org.mockito.ArgumentMatchers +import org.mockito.Captor +import org.mockito.Mock +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations + +@SmallTest +@RunWith(AndroidTestingRunner::class) +@TestableLooper.RunWithLooper +class ControlsEditingActivityTest : SysuiTestCase() { + @Mock lateinit var controller: ControlsControllerImpl + + @Mock lateinit var broadcastDispatcher: BroadcastDispatcher + + @Mock lateinit var customIconCache: CustomIconCache + + @Mock lateinit var uiController: ControlsUiController + + private lateinit var controlsEditingActivity: ControlsEditingActivity_Factory + private var latch: CountDownLatch = CountDownLatch(1) + + @Mock private lateinit var mockDispatcher: OnBackInvokedDispatcher + @Captor private lateinit var captureCallback: ArgumentCaptor<OnBackInvokedCallback> + + @Rule + @JvmField + var activityRule = + ActivityTestRule( + object : + SingleActivityFactory<TestableControlsEditingActivity>( + TestableControlsEditingActivity::class.java + ) { + override fun create(intent: Intent?): TestableControlsEditingActivity { + return TestableControlsEditingActivity( + controller, + broadcastDispatcher, + customIconCache, + uiController, + mockDispatcher, + latch + ) + } + }, + false, + false + ) + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + val intent = Intent() + intent.putExtra(ControlsEditingActivity.EXTRA_STRUCTURE, "TestTitle") + val cname = ComponentName("TestPackageName", "TestClassName") + intent.putExtra(Intent.EXTRA_COMPONENT_NAME, cname) + activityRule.launchActivity(intent) + } + + @Test + fun testBackCallbackRegistrationAndUnregistration() { + // 1. ensure that launching the activity results in it registering a callback + verify(mockDispatcher) + .registerOnBackInvokedCallback( + ArgumentMatchers.eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT), + captureCallback.capture() + ) + activityRule.finishActivity() + latch.await() // ensure activity is finished + // 2. ensure that when the activity is finished, it unregisters the same callback + verify(mockDispatcher).unregisterOnBackInvokedCallback(captureCallback.value) + } + + public class TestableControlsEditingActivity( + private val controller: ControlsControllerImpl, + private val broadcastDispatcher: BroadcastDispatcher, + private val customIconCache: CustomIconCache, + private val uiController: ControlsUiController, + private val mockDispatcher: OnBackInvokedDispatcher, + private val latch: CountDownLatch + ) : ControlsEditingActivity(controller, broadcastDispatcher, customIconCache, uiController) { + override fun getOnBackInvokedDispatcher(): OnBackInvokedDispatcher { + return mockDispatcher + } + + override fun onStop() { + super.onStop() + // ensures that test runner thread does not proceed until ui thread is done + latch.countDown() + } + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsFavoritingActivityTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsFavoritingActivityTest.kt new file mode 100644 index 000000000000..4b0f7e6cd736 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsFavoritingActivityTest.kt @@ -0,0 +1,122 @@ +package com.android.systemui.controls.management + +import android.content.Intent +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper +import android.window.OnBackInvokedCallback +import android.window.OnBackInvokedDispatcher +import androidx.test.filters.SmallTest +import androidx.test.rule.ActivityTestRule +import androidx.test.runner.intercepting.SingleActivityFactory +import com.android.systemui.SysuiTestCase +import com.android.systemui.broadcast.BroadcastDispatcher +import com.android.systemui.controls.controller.ControlsControllerImpl +import com.android.systemui.controls.ui.ControlsUiController +import com.android.systemui.dagger.qualifiers.Main +import com.google.common.util.concurrent.MoreExecutors +import java.util.concurrent.CountDownLatch +import java.util.concurrent.Executor +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentCaptor +import org.mockito.ArgumentMatchers +import org.mockito.Captor +import org.mockito.Mock +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations + +@SmallTest +@RunWith(AndroidTestingRunner::class) +@TestableLooper.RunWithLooper +class ControlsFavoritingActivityTest : SysuiTestCase() { + @Main private val executor: Executor = MoreExecutors.directExecutor() + + @Mock lateinit var controller: ControlsControllerImpl + + @Mock lateinit var listingController: ControlsListingController + + @Mock lateinit var broadcastDispatcher: BroadcastDispatcher + + @Mock lateinit var uiController: ControlsUiController + + private lateinit var controlsFavoritingActivity: ControlsFavoritingActivity_Factory + private var latch: CountDownLatch = CountDownLatch(1) + + @Mock private lateinit var mockDispatcher: OnBackInvokedDispatcher + @Captor private lateinit var captureCallback: ArgumentCaptor<OnBackInvokedCallback> + + @Rule + @JvmField + var activityRule = + ActivityTestRule( + object : + SingleActivityFactory<TestableControlsFavoritingActivity>( + TestableControlsFavoritingActivity::class.java + ) { + override fun create(intent: Intent?): TestableControlsFavoritingActivity { + return TestableControlsFavoritingActivity( + executor, + controller, + listingController, + broadcastDispatcher, + uiController, + mockDispatcher, + latch + ) + } + }, + false, + false + ) + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + val intent = Intent() + intent.putExtra(ControlsFavoritingActivity.EXTRA_FROM_PROVIDER_SELECTOR, true) + activityRule.launchActivity(intent) + } + + @Test + fun testBackCallbackRegistrationAndUnregistration() { + // 1. ensure that launching the activity results in it registering a callback + verify(mockDispatcher) + .registerOnBackInvokedCallback( + ArgumentMatchers.eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT), + captureCallback.capture() + ) + activityRule.finishActivity() + latch.await() // ensure activity is finished + // 2. ensure that when the activity is finished, it unregisters the same callback + verify(mockDispatcher).unregisterOnBackInvokedCallback(captureCallback.value) + } + + public class TestableControlsFavoritingActivity( + executor: Executor, + controller: ControlsControllerImpl, + listingController: ControlsListingController, + broadcastDispatcher: BroadcastDispatcher, + uiController: ControlsUiController, + private val mockDispatcher: OnBackInvokedDispatcher, + private val latch: CountDownLatch + ) : + ControlsFavoritingActivity( + executor, + controller, + listingController, + broadcastDispatcher, + uiController + ) { + override fun getOnBackInvokedDispatcher(): OnBackInvokedDispatcher { + return mockDispatcher + } + + override fun onStop() { + super.onStop() + // ensures that test runner thread does not proceed until ui thread is done + latch.countDown() + } + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsProviderSelectorActivityTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsProviderSelectorActivityTest.kt new file mode 100644 index 000000000000..acc62227cde6 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsProviderSelectorActivityTest.kt @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.controls.management + +import android.content.Intent +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper +import android.window.OnBackInvokedCallback +import android.window.OnBackInvokedDispatcher +import androidx.test.filters.SmallTest +import androidx.test.rule.ActivityTestRule +import androidx.test.runner.intercepting.SingleActivityFactory +import com.android.systemui.SysuiTestCase +import com.android.systemui.broadcast.BroadcastDispatcher +import com.android.systemui.controls.controller.ControlsController +import com.android.systemui.controls.ui.ControlsUiController +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.dagger.qualifiers.Main +import com.google.common.util.concurrent.MoreExecutors +import java.util.concurrent.CountDownLatch +import java.util.concurrent.Executor +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentCaptor +import org.mockito.ArgumentMatchers +import org.mockito.Captor +import org.mockito.Mock +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations + +@SmallTest +@RunWith(AndroidTestingRunner::class) +@TestableLooper.RunWithLooper +class ControlsProviderSelectorActivityTest : SysuiTestCase() { + @Main private val executor: Executor = MoreExecutors.directExecutor() + + @Background private val backExecutor: Executor = MoreExecutors.directExecutor() + + @Mock lateinit var listingController: ControlsListingController + + @Mock lateinit var controlsController: ControlsController + + @Mock lateinit var broadcastDispatcher: BroadcastDispatcher + + @Mock lateinit var uiController: ControlsUiController + + private lateinit var controlsProviderSelectorActivity: ControlsProviderSelectorActivity_Factory + private var latch: CountDownLatch = CountDownLatch(1) + + @Mock private lateinit var mockDispatcher: OnBackInvokedDispatcher + @Captor private lateinit var captureCallback: ArgumentCaptor<OnBackInvokedCallback> + + @Rule + @JvmField + var activityRule = + ActivityTestRule( + object : + SingleActivityFactory<TestableControlsProviderSelectorActivity>( + TestableControlsProviderSelectorActivity::class.java + ) { + override fun create(intent: Intent?): TestableControlsProviderSelectorActivity { + return TestableControlsProviderSelectorActivity( + executor, + backExecutor, + listingController, + controlsController, + broadcastDispatcher, + uiController, + mockDispatcher, + latch + ) + } + }, + false, + false + ) + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + val intent = Intent() + intent.putExtra(ControlsProviderSelectorActivity.BACK_SHOULD_EXIT, true) + activityRule.launchActivity(intent) + } + + @Test + fun testBackCallbackRegistrationAndUnregistration() { + // 1. ensure that launching the activity results in it registering a callback + verify(mockDispatcher) + .registerOnBackInvokedCallback( + ArgumentMatchers.eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT), + captureCallback.capture() + ) + activityRule.finishActivity() + latch.await() // ensure activity is finished + // 2. ensure that when the activity is finished, it unregisters the same callback + verify(mockDispatcher).unregisterOnBackInvokedCallback(captureCallback.value) + } + + public class TestableControlsProviderSelectorActivity( + executor: Executor, + backExecutor: Executor, + listingController: ControlsListingController, + controlsController: ControlsController, + broadcastDispatcher: BroadcastDispatcher, + uiController: ControlsUiController, + private val mockDispatcher: OnBackInvokedDispatcher, + private val latch: CountDownLatch + ) : + ControlsProviderSelectorActivity( + executor, + backExecutor, + listingController, + controlsController, + broadcastDispatcher, + uiController + ) { + override fun getOnBackInvokedDispatcher(): OnBackInvokedDispatcher { + return mockDispatcher + } + + override fun onStop() { + super.onStop() + // ensures that test runner thread does not proceed until ui thread is done + latch.countDown() + } + } +} 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 c5a7de410eb0..517804db2a70 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java @@ -36,10 +36,10 @@ import androidx.test.filters.SmallTest; import com.android.keyguard.BouncerPanelExpansionCalculator; import com.android.systemui.SysuiTestCase; import com.android.systemui.dreams.complication.ComplicationHostViewController; -import com.android.systemui.keyguard.domain.interactor.BouncerCallbackInteractor; +import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor; import com.android.systemui.statusbar.BlurUtils; import com.android.systemui.statusbar.phone.KeyguardBouncer; -import com.android.systemui.statusbar.phone.KeyguardBouncer.BouncerExpansionCallback; +import com.android.systemui.statusbar.phone.KeyguardBouncer.PrimaryBouncerExpansionCallback; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import org.junit.Before; @@ -90,7 +90,13 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase { ViewRootImpl mViewRoot; @Mock - BouncerCallbackInteractor mBouncerCallbackInteractor; + PrimaryBouncerCallbackInteractor mPrimaryBouncerCallbackInteractor; + + @Mock + DreamOverlayAnimationsController mAnimationsController; + + @Mock + DreamOverlayStateController mStateController; DreamOverlayContainerViewController mController; @@ -100,7 +106,7 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase { when(mDreamOverlayContainerView.getResources()).thenReturn(mResources); when(mDreamOverlayContainerView.getViewTreeObserver()).thenReturn(mViewTreeObserver); - when(mStatusBarKeyguardViewManager.getBouncer()).thenReturn(mBouncer); + when(mStatusBarKeyguardViewManager.getPrimaryBouncer()).thenReturn(mBouncer); when(mDreamOverlayContainerView.getViewRootImpl()).thenReturn(mViewRoot); mController = new DreamOverlayContainerViewController( @@ -115,7 +121,9 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase { MAX_BURN_IN_OFFSET, BURN_IN_PROTECTION_UPDATE_INTERVAL, MILLIS_UNTIL_FULL_JITTER, - mBouncerCallbackInteractor); + mPrimaryBouncerCallbackInteractor, + mAnimationsController, + mStateController); } @Test @@ -159,8 +167,8 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase { @Test public void testBouncerAnimation_doesNotApply() { - final ArgumentCaptor<BouncerExpansionCallback> bouncerExpansionCaptor = - ArgumentCaptor.forClass(BouncerExpansionCallback.class); + final ArgumentCaptor<PrimaryBouncerExpansionCallback> bouncerExpansionCaptor = + ArgumentCaptor.forClass(PrimaryBouncerExpansionCallback.class); mController.onViewAttached(); verify(mBouncer).addBouncerExpansionCallback(bouncerExpansionCaptor.capture()); @@ -170,8 +178,8 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase { @Test public void testBouncerAnimation_updateBlur() { - final ArgumentCaptor<BouncerExpansionCallback> bouncerExpansionCaptor = - ArgumentCaptor.forClass(BouncerExpansionCallback.class); + final ArgumentCaptor<PrimaryBouncerExpansionCallback> bouncerExpansionCaptor = + ArgumentCaptor.forClass(PrimaryBouncerExpansionCallback.class); mController.onViewAttached(); verify(mBouncer).addBouncerExpansionCallback(bouncerExpansionCaptor.capture()); @@ -188,4 +196,31 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase { verify(mBlurUtils).blurRadiusOfRatio(1 - scaledFraction); verify(mBlurUtils).applyBlur(mViewRoot, (int) blurRadius, false); } + + @Test + public void testStartDreamEntryAnimationsOnAttachedNonLowLight() { + when(mStateController.isLowLightActive()).thenReturn(false); + + mController.onViewAttached(); + + verify(mAnimationsController).startEntryAnimations(mDreamOverlayContainerView); + verify(mAnimationsController, never()).cancelRunningEntryAnimations(); + } + + @Test + public void testNeverStartDreamEntryAnimationsOnAttachedForLowLight() { + when(mStateController.isLowLightActive()).thenReturn(true); + + mController.onViewAttached(); + + verify(mAnimationsController, never()).startEntryAnimations(mDreamOverlayContainerView); + } + + @Test + public void testCancelDreamEntryAnimationsOnDetached() { + mController.onViewAttached(); + mController.onViewDetached(); + + verify(mAnimationsController).cancelRunningEntryAnimations(); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java index f370be190761..f04a37f4c3fa 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java @@ -253,6 +253,7 @@ public class DreamOverlayServiceTest extends SysuiTestCase { verify(mLifecycleRegistry).setCurrentState(Lifecycle.State.DESTROYED); verify(mStateController).setOverlayActive(false); verify(mStateController).setLowLightActive(false); + verify(mStateController).setEntryAnimationsFinished(false); } @Test @@ -273,24 +274,28 @@ public class DreamOverlayServiceTest extends SysuiTestCase { @Test public void testDecorViewNotAddedToWindowAfterDestroy() throws Exception { - when(mDreamOverlayContainerView.getParent()) - .thenReturn(mDreamOverlayContainerViewParent) - .thenReturn(null); - final IBinder proxy = mService.onBind(new Intent()); final IDreamOverlay overlay = IDreamOverlay.Stub.asInterface(proxy); + // Destroy the service. + mService.onDestroy(); + mMainExecutor.runAllReady(); + // Inform the overlay service of dream starting. overlay.startDream(mWindowParams, mDreamOverlayCallback, DREAM_COMPONENT, false /*shouldShowComplication*/); + mMainExecutor.runAllReady(); - // Destroy the service. - mService.onDestroy(); + verify(mWindowManager, never()).addView(any(), any()); + } - // Run executor tasks. + @Test + public void testNeverRemoveDecorViewIfNotAdded() { + // Service destroyed before dream started. + mService.onDestroy(); mMainExecutor.runAllReady(); - verify(mWindowManager, never()).addView(any(), any()); + verify(mWindowManager, never()).removeView(any()); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java index d1d32a13589a..c21c7a2aacbe 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java @@ -234,4 +234,20 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase { verify(mCallback, times(1)).onStateChanged(); assertThat(stateController.isLowLightActive()).isTrue(); } + + @Test + public void testNotifyEntryAnimationsFinishedChanged() { + final DreamOverlayStateController stateController = + new DreamOverlayStateController(mExecutor); + + stateController.addCallback(mCallback); + mExecutor.runAllReady(); + assertThat(stateController.areEntryAnimationsFinished()).isFalse(); + + stateController.setEntryAnimationsFinished(true); + mExecutor.runAllReady(); + + verify(mCallback, times(1)).onStateChanged(); + assertThat(stateController.areEntryAnimationsFinished()).isTrue(); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java index aa021781296a..85c28190d77b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java @@ -19,16 +19,20 @@ package com.android.systemui.dreams; import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN; import static android.app.StatusBarManager.WINDOW_STATE_SHOWING; +import static com.google.common.truth.Truth.assertThat; + import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.Mockito.doCallRealMethod; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.AlarmManager; +import android.content.Context; import android.content.res.Resources; import android.hardware.SensorPrivacyManager; import android.net.ConnectivityManager; @@ -55,6 +59,7 @@ 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; @@ -69,7 +74,7 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase { "{count, plural, =1 {# notification} other {# notifications}}"; @Mock - DreamOverlayStatusBarView mView; + MockDreamOverlayStatusBarView mView; @Mock ConnectivityManager mConnectivityManager; @Mock @@ -105,6 +110,9 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase { @Mock DreamOverlayStateController mDreamOverlayStateController; + @Captor + private ArgumentCaptor<DreamOverlayStateController.Callback> mCallbackCaptor; + private final Executor mMainExecutor = Runnable::run; DreamOverlayStatusBarViewController mController; @@ -115,6 +123,8 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase { when(mResources.getString(R.string.dream_overlay_status_bar_notification_indicator)) .thenReturn(NOTIFICATION_INDICATOR_FORMATTER_STRING); + doCallRealMethod().when(mView).setVisibility(anyInt()); + doCallRealMethod().when(mView).getVisibility(); mController = new DreamOverlayStatusBarViewController( mView, @@ -454,12 +464,10 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase { public void testStatusBarHiddenWhenSystemStatusBarShown() { mController.onViewAttached(); - final ArgumentCaptor<StatusBarWindowStateListener> - callbackCapture = ArgumentCaptor.forClass(StatusBarWindowStateListener.class); - verify(mStatusBarWindowStateController).addListener(callbackCapture.capture()); - callbackCapture.getValue().onStatusBarWindowStateChanged(WINDOW_STATE_SHOWING); + updateEntryAnimationsFinished(); + updateStatusBarWindowState(true); - verify(mView).setVisibility(View.INVISIBLE); + assertThat(mView.getVisibility()).isEqualTo(View.INVISIBLE); } @Test @@ -467,29 +475,43 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase { mController.onViewAttached(); reset(mView); - final ArgumentCaptor<StatusBarWindowStateListener> - callbackCapture = ArgumentCaptor.forClass(StatusBarWindowStateListener.class); - verify(mStatusBarWindowStateController).addListener(callbackCapture.capture()); - callbackCapture.getValue().onStatusBarWindowStateChanged(WINDOW_STATE_HIDDEN); + updateEntryAnimationsFinished(); + updateStatusBarWindowState(false); - verify(mView).setVisibility(View.VISIBLE); + assertThat(mView.getVisibility()).isEqualTo(View.VISIBLE); } @Test public void testUnattachedStatusBarVisibilityUnchangedWhenSystemStatusBarHidden() { mController.onViewAttached(); + updateEntryAnimationsFinished(); mController.onViewDetached(); reset(mView); - final ArgumentCaptor<StatusBarWindowStateListener> - callbackCapture = ArgumentCaptor.forClass(StatusBarWindowStateListener.class); - verify(mStatusBarWindowStateController).addListener(callbackCapture.capture()); - callbackCapture.getValue().onStatusBarWindowStateChanged(WINDOW_STATE_SHOWING); + updateStatusBarWindowState(true); verify(mView, never()).setVisibility(anyInt()); } @Test + public void testNoChangeToVisibilityBeforeDreamStartedWhenStatusBarHidden() { + mController.onViewAttached(); + + // Trigger status bar window state change. + final StatusBarWindowStateListener listener = updateStatusBarWindowState(false); + + // Verify no visibility change because dream not started. + verify(mView, never()).setVisibility(anyInt()); + + // Dream entry animations finished. + updateEntryAnimationsFinished(); + + // Trigger another status bar window state change, and verify visibility change. + listener.onStatusBarWindowStateChanged(WINDOW_STATE_HIDDEN); + assertThat(mView.getVisibility()).isEqualTo(View.VISIBLE); + } + + @Test public void testExtraStatusBarItemSetWhenItemsChange() { mController.onViewAttached(); when(mStatusBarItem.getView()).thenReturn(mStatusBarItemView); @@ -507,16 +529,75 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase { public void testLowLightHidesStatusBar() { when(mDreamOverlayStateController.isLowLightActive()).thenReturn(true); mController.onViewAttached(); + updateEntryAnimationsFinished(); + + final ArgumentCaptor<DreamOverlayStateController.Callback> callbackCapture = + ArgumentCaptor.forClass(DreamOverlayStateController.Callback.class); + verify(mDreamOverlayStateController).addCallback(callbackCapture.capture()); + callbackCapture.getValue().onStateChanged(); - verify(mView).setVisibility(View.INVISIBLE); + assertThat(mView.getVisibility()).isEqualTo(View.INVISIBLE); reset(mView); when(mDreamOverlayStateController.isLowLightActive()).thenReturn(false); + callbackCapture.getValue().onStateChanged(); + + assertThat(mView.getVisibility()).isEqualTo(View.VISIBLE); + } + + @Test + public void testNoChangeToVisibilityBeforeDreamStartedWhenLowLightStateChange() { + when(mDreamOverlayStateController.isLowLightActive()).thenReturn(false); + mController.onViewAttached(); + + // No change to visibility because dream not fully started. + verify(mView, never()).setVisibility(anyInt()); + + // Dream entry animations finished. + updateEntryAnimationsFinished(); + + // Trigger state change and verify visibility changed. final ArgumentCaptor<DreamOverlayStateController.Callback> callbackCapture = ArgumentCaptor.forClass(DreamOverlayStateController.Callback.class); verify(mDreamOverlayStateController).addCallback(callbackCapture.capture()); callbackCapture.getValue().onStateChanged(); - verify(mView).setVisibility(View.VISIBLE); + assertThat(mView.getVisibility()).isEqualTo(View.VISIBLE); + } + + private StatusBarWindowStateListener updateStatusBarWindowState(boolean show) { + when(mStatusBarWindowStateController.windowIsShowing()).thenReturn(show); + final ArgumentCaptor<StatusBarWindowStateListener> + callbackCapture = ArgumentCaptor.forClass(StatusBarWindowStateListener.class); + verify(mStatusBarWindowStateController).addListener(callbackCapture.capture()); + final StatusBarWindowStateListener listener = callbackCapture.getValue(); + listener.onStatusBarWindowStateChanged(show ? WINDOW_STATE_SHOWING : WINDOW_STATE_HIDDEN); + return listener; + } + + private void updateEntryAnimationsFinished() { + when(mDreamOverlayStateController.areEntryAnimationsFinished()).thenReturn(true); + + verify(mDreamOverlayStateController).addCallback(mCallbackCaptor.capture()); + final DreamOverlayStateController.Callback callback = mCallbackCaptor.getValue(); + callback.onStateChanged(); + } + + private static class MockDreamOverlayStatusBarView extends DreamOverlayStatusBarView { + private int mVisibility = View.VISIBLE; + + private MockDreamOverlayStatusBarView(Context context) { + super(context); + } + + @Override + public void setVisibility(int visibility) { + mVisibility = visibility; + } + + @Override + public int getVisibility() { + return mVisibility; + } } } 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 3b9e398141ee..b477592f8fbc 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 @@ -16,6 +16,7 @@ package com.android.systemui.dreams.complication; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -29,16 +30,18 @@ import androidx.lifecycle.Observer; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; +import com.android.systemui.dreams.DreamOverlayStateController; 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; -import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.HashSet; @SmallTest @@ -77,9 +80,20 @@ public class ComplicationHostViewControllerTest extends SysuiTestCase { @Mock ComplicationLayoutParams mComplicationLayoutParams; + @Mock + DreamOverlayStateController mDreamOverlayStateController; + + @Captor + private ArgumentCaptor<Observer<Collection<ComplicationViewModel>>> mObserverCaptor; + + @Captor + private ArgumentCaptor<DreamOverlayStateController.Callback> mCallbackCaptor; + @Complication.Category static final int COMPLICATION_CATEGORY = Complication.CATEGORY_SYSTEM; + private ComplicationHostViewController mController; + @Before public void setup() { MockitoAnnotations.initMocks(this); @@ -91,32 +105,28 @@ public class ComplicationHostViewControllerTest extends SysuiTestCase { when(mViewHolder.getCategory()).thenReturn(COMPLICATION_CATEGORY); when(mViewHolder.getLayoutParams()).thenReturn(mComplicationLayoutParams); when(mComplicationView.getParent()).thenReturn(mComplicationHostView); - } - /** - * Ensures the lifecycle of complications is properly handled. - */ - @Test - public void testViewModelObservation() { - final ArgumentCaptor<Observer<Collection<ComplicationViewModel>>> observerArgumentCaptor = - ArgumentCaptor.forClass(Observer.class); - final ComplicationHostViewController controller = new ComplicationHostViewController( + mController = new ComplicationHostViewController( mComplicationHostView, mLayoutEngine, + mDreamOverlayStateController, mLifecycleOwner, mViewModel); - controller.init(); - - verify(mComplicationViewModelLiveData).observe(eq(mLifecycleOwner), - observerArgumentCaptor.capture()); + mController.init(); + } + /** + * Ensures the lifecycle of complications is properly handled. + */ + @Test + public void testViewModelObservation() { final Observer<Collection<ComplicationViewModel>> observer = - observerArgumentCaptor.getValue(); + captureComplicationViewModelsObserver(); - // Add complication and ensure it is added to the view. + // Add a complication and ensure it is added to the view. final HashSet<ComplicationViewModel> complications = new HashSet<>( - Arrays.asList(mComplicationViewModel)); + Collections.singletonList(mComplicationViewModel)); observer.onChanged(complications); verify(mLayoutEngine).addComplication(eq(mComplicationId), eq(mComplicationView), @@ -127,4 +137,48 @@ public class ComplicationHostViewControllerTest extends SysuiTestCase { verify(mLayoutEngine).removeComplication(eq(mComplicationId)); } + + @Test + public void testNewComplicationsBeforeEntryAnimationsFinishSetToInvisible() { + 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 be set to invisible. + verify(mComplicationView).setVisibility(View.INVISIBLE); + } + + @Test + public void testNewComplicationsAfterEntryAnimationsFinishNotSetToInvisible() { + final Observer<Collection<ComplicationViewModel>> observer = + captureComplicationViewModelsObserver(); + + // Dream entry animations finished. + when(mDreamOverlayStateController.areEntryAnimationsFinished()).thenReturn(true); + final DreamOverlayStateController.Callback stateCallback = captureOverlayStateCallback(); + stateCallback.onStateChanged(); + + // Add a complication after 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()); + return mObserverCaptor.getValue(); + } + + private DreamOverlayStateController.Callback captureOverlayStateCallback() { + verify(mDreamOverlayStateController).addCallback(mCallbackCaptor.capture()); + return mCallbackCaptor.getValue(); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FakeFeatureFlagsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/FakeFeatureFlagsTest.kt index 318f2bc1c227..170a70f2fc40 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/flags/FakeFeatureFlagsTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FakeFeatureFlagsTest.kt @@ -20,7 +20,6 @@ import android.testing.AndroidTestingRunner import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.google.common.truth.Truth.assertThat -import java.lang.IllegalStateException import org.junit.Assert.fail import org.junit.Test import org.junit.runner.RunWith @@ -29,12 +28,12 @@ import org.junit.runner.RunWith @RunWith(AndroidTestingRunner::class) class FakeFeatureFlagsTest : SysuiTestCase() { - private val unreleasedFlag = UnreleasedFlag(-1000) - private val releasedFlag = ReleasedFlag(-1001) - private val stringFlag = StringFlag(-1002) - private val resourceBooleanFlag = ResourceBooleanFlag(-1003, resourceId = -1) - private val resourceStringFlag = ResourceStringFlag(-1004, resourceId = -1) - private val sysPropBooleanFlag = SysPropBooleanFlag(-1005, name = "test") + private val unreleasedFlag = UnreleasedFlag(-1000, "-1000", "test") + private val releasedFlag = ReleasedFlag(-1001, "-1001", "test") + private val stringFlag = StringFlag(-1002, "-1002", "test") + private val resourceBooleanFlag = ResourceBooleanFlag(-1003, "-1003", "test", resourceId = -1) + private val resourceStringFlag = ResourceStringFlag(-1004, "-1004", "test", resourceId = -1) + private val sysPropBooleanFlag = SysPropBooleanFlag(-1005, "test", "test") /** * FakeFeatureFlags does not honor any default values. All flags which are accessed must be @@ -47,7 +46,7 @@ class FakeFeatureFlagsTest : SysuiTestCase() { assertThat(flags.isEnabled(Flags.TEAMFOOD)).isFalse() fail("Expected an exception when accessing an unspecified flag.") } catch (ex: IllegalStateException) { - assertThat(ex.message).contains("TEAMFOOD") + assertThat(ex.message).contains("id=1") } try { assertThat(flags.isEnabled(unreleasedFlag)).isFalse() diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt index 4b3b70e3ae77..7592cc527190 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt @@ -20,6 +20,7 @@ import android.content.Context import android.content.Intent import android.content.pm.PackageManager.NameNotFoundException import android.content.res.Resources +import android.content.res.Resources.NotFoundException import android.test.suitebuilder.annotation.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.statusbar.commandline.CommandRegistry @@ -30,10 +31,6 @@ import com.android.systemui.util.mockito.nullable import com.android.systemui.util.mockito.withArgCaptor import com.android.systemui.util.settings.SecureSettings import com.google.common.truth.Truth.assertThat -import java.io.PrintWriter -import java.io.Serializable -import java.io.StringWriter -import java.util.function.Consumer import org.junit.Assert import org.junit.Before import org.junit.Test @@ -45,8 +42,12 @@ import org.mockito.Mockito.inOrder import org.mockito.Mockito.times import org.mockito.Mockito.verify import org.mockito.Mockito.verifyNoMoreInteractions -import org.mockito.Mockito.`when` as whenever import org.mockito.MockitoAnnotations +import java.io.PrintWriter +import java.io.Serializable +import java.io.StringWriter +import java.util.function.Consumer +import org.mockito.Mockito.`when` as whenever /** * NOTE: This test is for the version of FeatureFlagManager in src-debug, which allows overriding @@ -56,21 +57,32 @@ import org.mockito.MockitoAnnotations class FeatureFlagsDebugTest : SysuiTestCase() { private lateinit var mFeatureFlagsDebug: FeatureFlagsDebug - @Mock private lateinit var flagManager: FlagManager - @Mock private lateinit var mockContext: Context - @Mock private lateinit var secureSettings: SecureSettings - @Mock private lateinit var systemProperties: SystemPropertiesHelper - @Mock private lateinit var resources: Resources - @Mock private lateinit var commandRegistry: CommandRegistry - @Mock private lateinit var restarter: Restarter + @Mock + private lateinit var flagManager: FlagManager + @Mock + private lateinit var mockContext: Context + @Mock + private lateinit var secureSettings: SecureSettings + @Mock + private lateinit var systemProperties: SystemPropertiesHelper + @Mock + private lateinit var resources: Resources + @Mock + private lateinit var commandRegistry: CommandRegistry + @Mock + private lateinit var restarter: Restarter private val flagMap = mutableMapOf<Int, Flag<*>>() private lateinit var broadcastReceiver: BroadcastReceiver private lateinit var clearCacheAction: Consumer<Int> private val serverFlagReader = ServerFlagReaderFake() private val deviceConfig = DeviceConfigProxyFake() - private val teamfoodableFlagA = UnreleasedFlag(500, true) - private val teamfoodableFlagB = ReleasedFlag(501, true) + private val teamfoodableFlagA = UnreleasedFlag( + 500, name = "a", namespace = "test", teamfood = true + ) + private val teamfoodableFlagB = ReleasedFlag( + 501, name = "b", namespace = "test", teamfood = true + ) @Before fun setup() { @@ -83,7 +95,6 @@ class FeatureFlagsDebugTest : SysuiTestCase() { secureSettings, systemProperties, resources, - deviceConfig, serverFlagReader, flagMap, restarter @@ -91,8 +102,10 @@ class FeatureFlagsDebugTest : SysuiTestCase() { mFeatureFlagsDebug.init() verify(flagManager).onSettingsChangedAction = any() broadcastReceiver = withArgCaptor { - verify(mockContext).registerReceiver(capture(), any(), nullable(), nullable(), - any()) + verify(mockContext).registerReceiver( + capture(), any(), nullable(), nullable(), + any() + ) } clearCacheAction = withArgCaptor { verify(flagManager).clearCacheAction = capture() @@ -106,10 +119,42 @@ class FeatureFlagsDebugTest : SysuiTestCase() { whenever(flagManager.readFlagValue<Boolean>(eq(3), any())).thenReturn(true) whenever(flagManager.readFlagValue<Boolean>(eq(4), any())).thenReturn(false) - assertThat(mFeatureFlagsDebug.isEnabled(ReleasedFlag(2))).isTrue() - assertThat(mFeatureFlagsDebug.isEnabled(UnreleasedFlag(3))).isTrue() - assertThat(mFeatureFlagsDebug.isEnabled(ReleasedFlag(4))).isFalse() - assertThat(mFeatureFlagsDebug.isEnabled(UnreleasedFlag(5))).isFalse() + assertThat( + mFeatureFlagsDebug.isEnabled( + ReleasedFlag( + 2, + name = "2", + namespace = "test" + ) + ) + ).isTrue() + assertThat( + mFeatureFlagsDebug.isEnabled( + UnreleasedFlag( + 3, + name = "3", + namespace = "test" + ) + ) + ).isTrue() + assertThat( + mFeatureFlagsDebug.isEnabled( + ReleasedFlag( + 4, + name = "3", + namespace = "test" + ) + ) + ).isFalse() + assertThat( + mFeatureFlagsDebug.isEnabled( + UnreleasedFlag( + 5, + name = "4", + namespace = "test" + ) + ) + ).isFalse() } @Test @@ -137,9 +182,9 @@ class FeatureFlagsDebugTest : SysuiTestCase() { @Test fun teamFoodFlag_Overridden() { whenever(flagManager.readFlagValue<Boolean>(eq(teamfoodableFlagA.id), any())) - .thenReturn(true) + .thenReturn(true) whenever(flagManager.readFlagValue<Boolean>(eq(teamfoodableFlagB.id), any())) - .thenReturn(false) + .thenReturn(false) whenever(flagManager.readFlagValue<Boolean>(eq(1), any())).thenReturn(true) assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagA)).isTrue() assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagB)).isFalse() @@ -160,17 +205,26 @@ class FeatureFlagsDebugTest : SysuiTestCase() { whenever(flagManager.readFlagValue<Boolean>(eq(3), any())).thenReturn(true) whenever(flagManager.readFlagValue<Boolean>(eq(5), any())).thenReturn(false) - assertThat(mFeatureFlagsDebug.isEnabled(ResourceBooleanFlag(1, 1001))).isFalse() - assertThat(mFeatureFlagsDebug.isEnabled(ResourceBooleanFlag(2, 1002))).isTrue() - assertThat(mFeatureFlagsDebug.isEnabled(ResourceBooleanFlag(3, 1003))).isTrue() + assertThat( + mFeatureFlagsDebug.isEnabled( + ResourceBooleanFlag( + 1, + "1", + "test", + 1001 + ) + ) + ).isFalse() + assertThat(mFeatureFlagsDebug.isEnabled(ResourceBooleanFlag(2, "2", "test", 1002))).isTrue() + assertThat(mFeatureFlagsDebug.isEnabled(ResourceBooleanFlag(3, "3", "test", 1003))).isTrue() Assert.assertThrows(NameNotFoundException::class.java) { - mFeatureFlagsDebug.isEnabled(ResourceBooleanFlag(4, 1004)) + mFeatureFlagsDebug.isEnabled(ResourceBooleanFlag(4, "4", "test", 1004)) } // Test that resource is loaded (and validated) even when the setting is set. // This prevents developers from not noticing when they reference an invalid resource. Assert.assertThrows(NameNotFoundException::class.java) { - mFeatureFlagsDebug.isEnabled(ResourceBooleanFlag(5, 1005)) + mFeatureFlagsDebug.isEnabled(ResourceBooleanFlag(5, "5", "test", 1005)) } } @@ -183,36 +237,30 @@ class FeatureFlagsDebugTest : SysuiTestCase() { return@thenAnswer it.getArgument(1) } - assertThat(mFeatureFlagsDebug.isEnabled(SysPropBooleanFlag(1, "a"))).isFalse() - assertThat(mFeatureFlagsDebug.isEnabled(SysPropBooleanFlag(2, "b"))).isTrue() - assertThat(mFeatureFlagsDebug.isEnabled(SysPropBooleanFlag(3, "c", true))).isTrue() - assertThat(mFeatureFlagsDebug.isEnabled(SysPropBooleanFlag(4, "d", false))).isFalse() - assertThat(mFeatureFlagsDebug.isEnabled(SysPropBooleanFlag(5, "e"))).isFalse() - } - - @Test - fun readDeviceConfigBooleanFlag() { - val namespace = "test_namespace" - deviceConfig.setProperty(namespace, "a", "true", false) - deviceConfig.setProperty(namespace, "b", "false", false) - deviceConfig.setProperty(namespace, "c", null, false) - - assertThat(mFeatureFlagsDebug.isEnabled(DeviceConfigBooleanFlag(1, "a", namespace))) - .isTrue() - assertThat(mFeatureFlagsDebug.isEnabled(DeviceConfigBooleanFlag(2, "b", namespace))) - .isFalse() - assertThat(mFeatureFlagsDebug.isEnabled(DeviceConfigBooleanFlag(3, "c", namespace))) - .isFalse() + assertThat(mFeatureFlagsDebug.isEnabled(SysPropBooleanFlag(1, "a", "test"))).isFalse() + assertThat(mFeatureFlagsDebug.isEnabled(SysPropBooleanFlag(2, "b", "test"))).isTrue() + assertThat(mFeatureFlagsDebug.isEnabled(SysPropBooleanFlag(3, "c", "test", true))).isTrue() + assertThat( + mFeatureFlagsDebug.isEnabled( + SysPropBooleanFlag( + 4, + "d", + "test", + false + ) + ) + ).isFalse() + assertThat(mFeatureFlagsDebug.isEnabled(SysPropBooleanFlag(5, "e", "test"))).isFalse() } @Test fun readStringFlag() { whenever(flagManager.readFlagValue<String>(eq(3), any())).thenReturn("foo") whenever(flagManager.readFlagValue<String>(eq(4), any())).thenReturn("bar") - assertThat(mFeatureFlagsDebug.getString(StringFlag(1, "biz"))).isEqualTo("biz") - assertThat(mFeatureFlagsDebug.getString(StringFlag(2, "baz"))).isEqualTo("baz") - assertThat(mFeatureFlagsDebug.getString(StringFlag(3, "buz"))).isEqualTo("foo") - assertThat(mFeatureFlagsDebug.getString(StringFlag(4, "buz"))).isEqualTo("bar") + assertThat(mFeatureFlagsDebug.getString(StringFlag(1, "1", "test", "biz"))).isEqualTo("biz") + assertThat(mFeatureFlagsDebug.getString(StringFlag(2, "2", "test", "baz"))).isEqualTo("baz") + assertThat(mFeatureFlagsDebug.getString(StringFlag(3, "3", "test", "buz"))).isEqualTo("foo") + assertThat(mFeatureFlagsDebug.getString(StringFlag(4, "4", "test", "buz"))).isEqualTo("bar") } @Test @@ -228,29 +276,93 @@ class FeatureFlagsDebugTest : SysuiTestCase() { whenever(flagManager.readFlagValue<String>(eq(4), any())).thenReturn("override4") whenever(flagManager.readFlagValue<String>(eq(6), any())).thenReturn("override6") - assertThat(mFeatureFlagsDebug.getString(ResourceStringFlag(1, 1001))).isEqualTo("") - assertThat(mFeatureFlagsDebug.getString(ResourceStringFlag(2, 1002))).isEqualTo("resource2") - assertThat(mFeatureFlagsDebug.getString(ResourceStringFlag(3, 1003))).isEqualTo("override3") + assertThat( + mFeatureFlagsDebug.getString( + ResourceStringFlag( + 1, + "1", + "test", + 1001 + ) + ) + ).isEqualTo("") + assertThat( + mFeatureFlagsDebug.getString( + ResourceStringFlag( + 2, + "2", + "test", + 1002 + ) + ) + ).isEqualTo("resource2") + assertThat( + mFeatureFlagsDebug.getString( + ResourceStringFlag( + 3, + "3", + "test", + 1003 + ) + ) + ).isEqualTo("override3") Assert.assertThrows(NullPointerException::class.java) { - mFeatureFlagsDebug.getString(ResourceStringFlag(4, 1004)) + mFeatureFlagsDebug.getString(ResourceStringFlag(4, "4", "test", 1004)) } Assert.assertThrows(NameNotFoundException::class.java) { - mFeatureFlagsDebug.getString(ResourceStringFlag(5, 1005)) + mFeatureFlagsDebug.getString(ResourceStringFlag(5, "5", "test", 1005)) } // Test that resource is loaded (and validated) even when the setting is set. // This prevents developers from not noticing when they reference an invalid resource. Assert.assertThrows(NameNotFoundException::class.java) { - mFeatureFlagsDebug.getString(ResourceStringFlag(6, 1005)) + mFeatureFlagsDebug.getString(ResourceStringFlag(6, "6", "test", 1005)) + } + } + + @Test + fun readIntFlag() { + whenever(flagManager.readFlagValue<Int>(eq(3), any())).thenReturn(22) + whenever(flagManager.readFlagValue<Int>(eq(4), any())).thenReturn(48) + assertThat(mFeatureFlagsDebug.getInt(IntFlag(1, "1", "test", 12))).isEqualTo(12) + assertThat(mFeatureFlagsDebug.getInt(IntFlag(2, "2", "test", 93))).isEqualTo(93) + assertThat(mFeatureFlagsDebug.getInt(IntFlag(3, "3", "test", 8))).isEqualTo(22) + assertThat(mFeatureFlagsDebug.getInt(IntFlag(4, "4", "test", 234))).isEqualTo(48) + } + + @Test + fun readResourceIntFlag() { + whenever(resources.getInteger(1001)).thenReturn(88) + whenever(resources.getInteger(1002)).thenReturn(61) + whenever(resources.getInteger(1003)).thenReturn(9342) + whenever(resources.getInteger(1004)).thenThrow(NotFoundException("unknown resource")) + whenever(resources.getInteger(1005)).thenThrow(NotFoundException("unknown resource")) + whenever(resources.getInteger(1006)).thenThrow(NotFoundException("unknown resource")) + + whenever(flagManager.readFlagValue<Int>(eq(3), any())).thenReturn(20) + whenever(flagManager.readFlagValue<Int>(eq(4), any())).thenReturn(500) + whenever(flagManager.readFlagValue<Int>(eq(5), any())).thenReturn(9519) + + assertThat(mFeatureFlagsDebug.getInt(ResourceIntFlag(1, "1", "test", 1001))).isEqualTo(88) + assertThat(mFeatureFlagsDebug.getInt(ResourceIntFlag(2, "2", "test", 1002))).isEqualTo(61) + assertThat(mFeatureFlagsDebug.getInt(ResourceIntFlag(3, "3", "test", 1003))).isEqualTo(20) + + Assert.assertThrows(NotFoundException::class.java) { + mFeatureFlagsDebug.getInt(ResourceIntFlag(4, "4", "test", 1004)) + } + // Test that resource is loaded (and validated) even when the setting is set. + // This prevents developers from not noticing when they reference an invalid resource. + Assert.assertThrows(NotFoundException::class.java) { + mFeatureFlagsDebug.getInt(ResourceIntFlag(5, "5", "test", 1005)) } } @Test fun broadcastReceiver_IgnoresInvalidData() { - addFlag(UnreleasedFlag(1)) - addFlag(ResourceBooleanFlag(2, 1002)) - addFlag(StringFlag(3, "flag3")) - addFlag(ResourceStringFlag(4, 1004)) + addFlag(UnreleasedFlag(1, "1", "test")) + addFlag(ResourceBooleanFlag(2, "2", "test", 1002)) + addFlag(StringFlag(3, "3", "test", "flag3")) + addFlag(ResourceStringFlag(4, "4", "test", 1004)) broadcastReceiver.onReceive(mockContext, null) broadcastReceiver.onReceive(mockContext, Intent()) @@ -266,7 +378,7 @@ class FeatureFlagsDebugTest : SysuiTestCase() { @Test fun intentWithId_NoValueKeyClears() { - addFlag(UnreleasedFlag(1)) + addFlag(UnreleasedFlag(1, name = "1", namespace = "test")) // trying to erase an id not in the map does nothing broadcastReceiver.onReceive( @@ -285,10 +397,10 @@ class FeatureFlagsDebugTest : SysuiTestCase() { @Test fun setBooleanFlag() { - addFlag(UnreleasedFlag(1)) - addFlag(UnreleasedFlag(2)) - addFlag(ResourceBooleanFlag(3, 1003)) - addFlag(ResourceBooleanFlag(4, 1004)) + addFlag(UnreleasedFlag(1, "1", "test")) + addFlag(UnreleasedFlag(2, "2", "test")) + addFlag(ResourceBooleanFlag(3, "3", "test", 1003)) + addFlag(ResourceBooleanFlag(4, "4", "test", 1004)) setByBroadcast(1, false) verifyPutData(1, "{\"type\":\"boolean\",\"value\":false}") @@ -305,8 +417,8 @@ class FeatureFlagsDebugTest : SysuiTestCase() { @Test fun setStringFlag() { - addFlag(StringFlag(1, "flag1")) - addFlag(ResourceStringFlag(2, 1002)) + addFlag(StringFlag(1, "flag1", "1", "test")) + addFlag(ResourceStringFlag(2, "2", "test", 1002)) setByBroadcast(1, "override1") verifyPutData(1, "{\"type\":\"string\",\"value\":\"override1\"}") @@ -317,7 +429,7 @@ class FeatureFlagsDebugTest : SysuiTestCase() { @Test fun setFlag_ClearsCache() { - val flag1 = addFlag(StringFlag(1, "flag1")) + val flag1 = addFlag(StringFlag(1, "1", "test", "flag1")) whenever(flagManager.readFlagValue<String>(eq(1), any())).thenReturn("original") // gets the flag & cache it @@ -339,31 +451,31 @@ class FeatureFlagsDebugTest : SysuiTestCase() { @Test fun serverSide_Overrides_MakesFalse() { - val flag = ReleasedFlag(100) + val flag = ReleasedFlag(100, "100", "test") - serverFlagReader.setFlagValue(flag.id, false) + serverFlagReader.setFlagValue(flag.namespace, flag.name, false) assertThat(mFeatureFlagsDebug.isEnabled(flag)).isFalse() } @Test fun serverSide_Overrides_MakesTrue() { - val flag = UnreleasedFlag(100) + val flag = UnreleasedFlag(100, name = "100", namespace = "test") - serverFlagReader.setFlagValue(flag.id, true) + serverFlagReader.setFlagValue(flag.namespace, flag.name, true) assertThat(mFeatureFlagsDebug.isEnabled(flag)).isTrue() } @Test fun dumpFormat() { - val flag1 = ReleasedFlag(1) - val flag2 = ResourceBooleanFlag(2, 1002) - val flag3 = UnreleasedFlag(3) - val flag4 = StringFlag(4, "") - val flag5 = StringFlag(5, "flag5default") - val flag6 = ResourceStringFlag(6, 1006) - val flag7 = ResourceStringFlag(7, 1007) + val flag1 = ReleasedFlag(1, "1", "test") + val flag2 = ResourceBooleanFlag(2, "2", "test", 1002) + val flag3 = UnreleasedFlag(3, "3", "test") + val flag4 = StringFlag(4, "4", "test", "") + val flag5 = StringFlag(5, "5", "test", "flag5default") + val flag6 = ResourceStringFlag(6, "6", "test", 1006) + val flag7 = ResourceStringFlag(7, "7", "test", 1007) whenever(resources.getBoolean(1002)).thenReturn(true) whenever(resources.getString(1006)).thenReturn("resource1006") diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsReleaseTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsReleaseTest.kt index b2dd60c9566d..d5b5a4a4101e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsReleaseTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsReleaseTest.kt @@ -25,8 +25,8 @@ import org.junit.Assert.assertThrows import org.junit.Before import org.junit.Test import org.mockito.Mock -import org.mockito.Mockito.`when` as whenever import org.mockito.MockitoAnnotations +import org.mockito.Mockito.`when` as whenever /** * NOTE: This test is for the version of FeatureFlagManager in src-release, which should not allow @@ -59,7 +59,9 @@ class FeatureFlagsReleaseTest : SysuiTestCase() { fun testBooleanResourceFlag() { val flagId = 213 val flagResourceId = 3 - val flag = ResourceBooleanFlag(flagId, flagResourceId) + val flagName = "213" + val flagNamespace = "test" + val flag = ResourceBooleanFlag(flagId, flagName, flagNamespace, flagResourceId) whenever(mResources.getBoolean(flagResourceId)).thenReturn(true) assertThat(mFeatureFlagsRelease.isEnabled(flag)).isTrue() } @@ -71,57 +73,45 @@ class FeatureFlagsReleaseTest : SysuiTestCase() { whenever(mResources.getString(1003)).thenReturn(null) whenever(mResources.getString(1004)).thenAnswer { throw NameNotFoundException() } - assertThat(mFeatureFlagsRelease.getString(ResourceStringFlag(1, 1001))).isEqualTo("") - assertThat(mFeatureFlagsRelease.getString(ResourceStringFlag(2, 1002))).isEqualTo("res2") + assertThat(mFeatureFlagsRelease.getString( + ResourceStringFlag(1, "1", "test", 1001))).isEqualTo("") + assertThat(mFeatureFlagsRelease.getString( + ResourceStringFlag(2, "2", "test", 1002))).isEqualTo("res2") assertThrows(NullPointerException::class.java) { - mFeatureFlagsRelease.getString(ResourceStringFlag(3, 1003)) + mFeatureFlagsRelease.getString(ResourceStringFlag(3, "3", "test", 1003)) } assertThrows(NameNotFoundException::class.java) { - mFeatureFlagsRelease.getString(ResourceStringFlag(4, 1004)) + mFeatureFlagsRelease.getString(ResourceStringFlag(4, "4", "test", 1004)) } } @Test - fun testReadDeviceConfigBooleanFlag() { - val namespace = "test_namespace" - deviceConfig.setProperty(namespace, "a", "true", false) - deviceConfig.setProperty(namespace, "b", "false", false) - deviceConfig.setProperty(namespace, "c", null, false) - - assertThat(mFeatureFlagsRelease.isEnabled(DeviceConfigBooleanFlag(1, "a", namespace))) - .isTrue() - assertThat(mFeatureFlagsRelease.isEnabled(DeviceConfigBooleanFlag(2, "b", namespace))) - .isFalse() - assertThat(mFeatureFlagsRelease.isEnabled(DeviceConfigBooleanFlag(3, "c", namespace))) - .isFalse() - } - - @Test fun testSysPropBooleanFlag() { val flagId = 213 val flagName = "sys_prop_flag" + val flagNamespace = "test" val flagDefault = true - val flag = SysPropBooleanFlag(flagId, flagName, flagDefault) + val flag = SysPropBooleanFlag(flagId, flagName, flagNamespace, flagDefault) whenever(mSystemProperties.getBoolean(flagName, flagDefault)).thenReturn(flagDefault) assertThat(mFeatureFlagsRelease.isEnabled(flag)).isEqualTo(flagDefault) } @Test fun serverSide_OverridesReleased_MakesFalse() { - val flag = ReleasedFlag(100) + val flag = ReleasedFlag(100, "100", "test") - serverFlagReader.setFlagValue(flag.id, false) + serverFlagReader.setFlagValue(flag.namespace, flag.name, false) assertThat(mFeatureFlagsRelease.isEnabled(flag)).isFalse() } @Test fun serverSide_OverridesUnreleased_Ignored() { - val flag = UnreleasedFlag(100) + val flag = UnreleasedFlag(100, "100", "test") - serverFlagReader.setFlagValue(flag.id, true) + serverFlagReader.setFlagValue(flag.namespace, flag.name, true) assertThat(mFeatureFlagsRelease.isEnabled(flag)).isFalse() } diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FlagCommandTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/FlagCommandTest.kt index 9628ee93ceff..fea91c53424d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/flags/FlagCommandTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FlagCommandTest.kt @@ -33,8 +33,10 @@ class FlagCommandTest : SysuiTestCase() { @Mock private lateinit var featureFlags: FeatureFlagsDebug @Mock private lateinit var pw: PrintWriter private val flagMap = mutableMapOf<Int, Flag<*>>() - private val flagA = UnreleasedFlag(500) - private val flagB = ReleasedFlag(501) + private val flagA = UnreleasedFlag(500, "500", "test") + private val flagB = ReleasedFlag(501, "501", "test") + private val stringFlag = StringFlag(502, "502", "test", "abracadabra") + private val intFlag = IntFlag(503, "503", "test", 12) private lateinit var cmd: FlagCommand @@ -44,26 +46,59 @@ class FlagCommandTest : SysuiTestCase() { whenever(featureFlags.isEnabled(any(UnreleasedFlag::class.java))).thenReturn(false) whenever(featureFlags.isEnabled(any(ReleasedFlag::class.java))).thenReturn(true) + whenever(featureFlags.getString(any(StringFlag::class.java))).thenAnswer { invocation -> + (invocation.getArgument(0) as StringFlag).default + } + whenever(featureFlags.getInt(any(IntFlag::class.java))).thenAnswer { invocation -> + (invocation.getArgument(0) as IntFlag).default + } + flagMap.put(flagA.id, flagA) flagMap.put(flagB.id, flagB) + flagMap.put(stringFlag.id, stringFlag) + flagMap.put(intFlag.id, intFlag) cmd = FlagCommand(featureFlags, flagMap) } @Test - fun readFlagCommand() { + fun readBooleanFlagCommand() { cmd.execute(pw, listOf(flagA.id.toString())) Mockito.verify(featureFlags).isEnabled(flagA) } @Test - fun setFlagCommand() { + fun readStringFlagCommand() { + cmd.execute(pw, listOf(stringFlag.id.toString())) + Mockito.verify(featureFlags).getString(stringFlag) + } + + @Test + fun readIntFlag() { + cmd.execute(pw, listOf(intFlag.id.toString())) + Mockito.verify(featureFlags).getInt(intFlag) + } + + @Test + fun setBooleanFlagCommand() { cmd.execute(pw, listOf(flagB.id.toString(), "on")) Mockito.verify(featureFlags).setBooleanFlagInternal(flagB, true) } @Test - fun toggleFlagCommand() { + fun setStringFlagCommand() { + cmd.execute(pw, listOf(stringFlag.id.toString(), "set", "foobar")) + Mockito.verify(featureFlags).setStringFlagInternal(stringFlag, "foobar") + } + + @Test + fun setIntFlag() { + cmd.execute(pw, listOf(intFlag.id.toString(), "put", "123")) + Mockito.verify(featureFlags).setIntFlagInternal(intFlag, 123) + } + + @Test + fun toggleBooleanFlagCommand() { cmd.execute(pw, listOf(flagB.id.toString(), "toggle")) Mockito.verify(featureFlags).setBooleanFlagInternal(flagB, false) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FlagManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/FlagManagerTest.kt index 17324a01502b..fca7e96fb148 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/flags/FlagManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FlagManagerTest.kt @@ -64,14 +64,14 @@ class FlagManagerTest : SysuiTestCase() { verifyNoMoreInteractions(mFlagSettingsHelper) // adding the first listener registers the observer - mFlagManager.addListener(ReleasedFlag(1), listener1) + mFlagManager.addListener(ReleasedFlag(1, "1", "test"), listener1) val observer = withArgCaptor<ContentObserver> { verify(mFlagSettingsHelper).registerContentObserver(any(), any(), capture()) } verifyNoMoreInteractions(mFlagSettingsHelper) // adding another listener does nothing - mFlagManager.addListener(ReleasedFlag(2), listener2) + mFlagManager.addListener(ReleasedFlag(2, "2", "test"), listener2) verifyNoMoreInteractions(mFlagSettingsHelper) // removing the original listener does nothing with second one still present @@ -89,7 +89,7 @@ class FlagManagerTest : SysuiTestCase() { val listener = mock<FlagListenable.Listener>() val clearCacheAction = mock<Consumer<Int>>() mFlagManager.clearCacheAction = clearCacheAction - mFlagManager.addListener(ReleasedFlag(1), listener) + mFlagManager.addListener(ReleasedFlag(1, "1", "test"), listener) val observer = withArgCaptor<ContentObserver> { verify(mFlagSettingsHelper).registerContentObserver(any(), any(), capture()) } @@ -101,8 +101,8 @@ class FlagManagerTest : SysuiTestCase() { fun testObserverInvokesListeners() { val listener1 = mock<FlagListenable.Listener>() val listener10 = mock<FlagListenable.Listener>() - mFlagManager.addListener(ReleasedFlag(1), listener1) - mFlagManager.addListener(ReleasedFlag(10), listener10) + mFlagManager.addListener(ReleasedFlag(1, "1", "test"), listener1) + mFlagManager.addListener(ReleasedFlag(10, "10", "test"), listener10) val observer = withArgCaptor<ContentObserver> { verify(mFlagSettingsHelper).registerContentObserver(any(), any(), capture()) } @@ -127,8 +127,8 @@ class FlagManagerTest : SysuiTestCase() { fun testOnlySpecificFlagListenerIsInvoked() { val listener1 = mock<FlagListenable.Listener>() val listener10 = mock<FlagListenable.Listener>() - mFlagManager.addListener(ReleasedFlag(1), listener1) - mFlagManager.addListener(ReleasedFlag(10), listener10) + mFlagManager.addListener(ReleasedFlag(1, "1", "test"), listener1) + mFlagManager.addListener(ReleasedFlag(10, "10", "test"), listener10) mFlagManager.dispatchListenersAndMaybeRestart(1, null) val flagEvent1 = withArgCaptor<FlagListenable.FlagEvent> { @@ -148,8 +148,8 @@ class FlagManagerTest : SysuiTestCase() { @Test fun testSameListenerCanBeUsedForMultipleFlags() { val listener = mock<FlagListenable.Listener>() - mFlagManager.addListener(ReleasedFlag(1), listener) - mFlagManager.addListener(ReleasedFlag(10), listener) + mFlagManager.addListener(ReleasedFlag(1, "1", "test"), listener) + mFlagManager.addListener(ReleasedFlag(10, "10", "test"), listener) mFlagManager.dispatchListenersAndMaybeRestart(1, null) val flagEvent1 = withArgCaptor<FlagListenable.FlagEvent> { @@ -177,7 +177,7 @@ class FlagManagerTest : SysuiTestCase() { @Test fun testListenerCanSuppressRestart() { val restartAction = mock<Consumer<Boolean>>() - mFlagManager.addListener(ReleasedFlag(1)) { event -> + mFlagManager.addListener(ReleasedFlag(1, "1", "test")) { event -> event.requestNoRestart() } mFlagManager.dispatchListenersAndMaybeRestart(1, restartAction) @@ -188,7 +188,7 @@ class FlagManagerTest : SysuiTestCase() { @Test fun testListenerOnlySuppressesRestartForOwnFlag() { val restartAction = mock<Consumer<Boolean>>() - mFlagManager.addListener(ReleasedFlag(10)) { event -> + mFlagManager.addListener(ReleasedFlag(10, "10", "test")) { event -> event.requestNoRestart() } mFlagManager.dispatchListenersAndMaybeRestart(1, restartAction) @@ -199,10 +199,10 @@ class FlagManagerTest : SysuiTestCase() { @Test fun testRestartWhenNotAllListenersRequestSuppress() { val restartAction = mock<Consumer<Boolean>>() - mFlagManager.addListener(ReleasedFlag(10)) { event -> + mFlagManager.addListener(ReleasedFlag(10, "10", "test")) { event -> event.requestNoRestart() } - mFlagManager.addListener(ReleasedFlag(10)) { + mFlagManager.addListener(ReleasedFlag(10, "10", "test")) { // do not request } mFlagManager.dispatchListenersAndMaybeRestart(1, restartAction) diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FlagsTest.java b/packages/SystemUI/tests/src/com/android/systemui/flags/FlagsTest.java deleted file mode 100644 index 250cc48fece3..000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/flags/FlagsTest.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.flags; - -import static com.google.common.truth.Truth.assertWithMessage; - -import android.util.Pair; - -import androidx.test.filters.SmallTest; - -import com.android.systemui.SysuiTestCase; - -import org.junit.Test; - -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -@SmallTest -public class FlagsTest extends SysuiTestCase { - - @Test - public void testDuplicateFlagIdCheckWorks() { - List<Pair<String, Flag<?>>> flags = collectFlags(DuplicateFlagContainer.class); - Map<Integer, List<String>> duplicates = groupDuplicateFlags(flags); - - assertWithMessage(generateAssertionMessage(duplicates)) - .that(duplicates.size()).isEqualTo(2); - } - - @Test - public void testNoDuplicateFlagIds() { - List<Pair<String, Flag<?>>> flags = collectFlags(Flags.class); - Map<Integer, List<String>> duplicates = groupDuplicateFlags(flags); - - assertWithMessage(generateAssertionMessage(duplicates)) - .that(duplicates.size()).isEqualTo(0); - } - - private String generateAssertionMessage(Map<Integer, List<String>> duplicates) { - StringBuilder stringBuilder = new StringBuilder(); - stringBuilder.append("Duplicate flag keys found: {"); - for (int id : duplicates.keySet()) { - stringBuilder - .append(" ") - .append(id) - .append(": [") - .append(String.join(", ", duplicates.get(id))) - .append("]"); - } - stringBuilder.append(" }"); - - return stringBuilder.toString(); - } - - private List<Pair<String, Flag<?>>> collectFlags(Class<?> clz) { - List<Pair<String, Flag<?>>> flags = new ArrayList<>(); - - Field[] fields = clz.getFields(); - - for (Field field : fields) { - Class<?> t = field.getType(); - if (Flag.class.isAssignableFrom(t)) { - try { - flags.add(Pair.create(field.getName(), (Flag<?>) field.get(null))); - } catch (IllegalAccessException e) { - // no-op - } - } - } - - return flags; - } - - private Map<Integer, List<String>> groupDuplicateFlags(List<Pair<String, Flag<?>>> flags) { - Map<Integer, List<String>> grouping = new HashMap<>(); - - for (Pair<String, Flag<?>> flag : flags) { - grouping.putIfAbsent(flag.second.getId(), new ArrayList<>()); - grouping.get(flag.second.getId()).add(flag.first); - } - - Map<Integer, List<String>> result = new HashMap<>(); - for (Integer id : grouping.keySet()) { - if (grouping.get(id).size() > 1) { - result.put(id, grouping.get(id)); - } - } - - return result; - } - - private static class DuplicateFlagContainer { - public static final BooleanFlag A_FLAG = new UnreleasedFlag(0); - public static final BooleanFlag B_FLAG = new UnreleasedFlag(0); - public static final StringFlag C_FLAG = new StringFlag(0); - - public static final BooleanFlag D_FLAG = new UnreleasedFlag(1); - - public static final DoubleFlag E_FLAG = new DoubleFlag(3); - public static final DoubleFlag F_FLAG = new DoubleFlag(3); - } -} diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/ServerFlagReaderImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/ServerFlagReaderImplTest.kt index 6f5f460d41c4..1633912abec7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/flags/ServerFlagReaderImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/flags/ServerFlagReaderImplTest.kt @@ -50,7 +50,7 @@ class ServerFlagReaderImplTest : SysuiTestCase() { @Test fun testChange_alertsListener() { - val flag = ReleasedFlag(1) + val flag = ReleasedFlag(1, "1", "test") serverFlagReader.listenForChanges(listOf(flag), changeListener) deviceConfig.setProperty(NAMESPACE, "flag_override_1", "1", false) diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java index 2c3ddd574b0f..b6780a12e6a9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java @@ -57,6 +57,7 @@ import com.android.systemui.classifier.FalsingCollectorFake; import com.android.systemui.dreams.DreamOverlayStateController; import com.android.systemui.dump.DumpManager; import com.android.systemui.navigationbar.NavigationModeController; +import com.android.systemui.shade.ShadeController; import com.android.systemui.statusbar.NotificationShadeDepthController; import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.SysuiStatusBarStateController; @@ -105,6 +106,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { private @Mock ScreenOffAnimationController mScreenOffAnimationController; private @Mock InteractionJankMonitor mInteractionJankMonitor; private @Mock ScreenOnCoordinator mScreenOnCoordinator; + private @Mock ShadeController mShadeController; private @Mock Lazy<NotificationShadeWindowController> mNotificationShadeWindowControllerLazy; private @Mock DreamOverlayStateController mDreamOverlayStateController; private @Mock ActivityLaunchAnimator mActivityLaunchAnimator; @@ -307,6 +309,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { mScreenOnCoordinator, mInteractionJankMonitor, mDreamOverlayStateController, + () -> mShadeController, mNotificationShadeWindowControllerLazy, () -> mActivityLaunchAnimator); mViewMediator.start(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityTest.java deleted file mode 100644 index 640e6dc0461d..000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityTest.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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; - -import static org.junit.Assert.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.eq; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.annotation.UserIdInt; -import android.content.Context; -import android.content.Intent; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.graphics.drawable.Drawable; -import android.os.Looper; -import android.os.UserHandle; -import android.os.UserManager; - -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - -import com.android.systemui.SysuiTestCase; -import com.android.systemui.broadcast.BroadcastDispatcher; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -/** - * runtest systemui -c com.android.systemui.keyguard.WorkLockActivityTest - */ -@SmallTest -@RunWith(AndroidJUnit4.class) -public class WorkLockActivityTest extends SysuiTestCase { - private static final @UserIdInt int USER_ID = 270; - private static final String CALLING_PACKAGE_NAME = "com.android.test"; - - private @Mock UserManager mUserManager; - private @Mock PackageManager mPackageManager; - private @Mock Context mContext; - private @Mock BroadcastDispatcher mBroadcastDispatcher; - private @Mock Drawable mDrawable; - private @Mock Drawable mBadgedDrawable; - - private WorkLockActivity mActivity; - - private static class WorkLockActivityTestable extends WorkLockActivity { - WorkLockActivityTestable(Context baseContext, BroadcastDispatcher broadcastDispatcher, - UserManager userManager, PackageManager packageManager) { - super(broadcastDispatcher, userManager, packageManager); - attachBaseContext(baseContext); - } - } - - @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - - if (Looper.myLooper() == null) { - Looper.prepare(); - } - mActivity = new WorkLockActivityTestable(mContext, mBroadcastDispatcher, mUserManager, - mPackageManager); - } - - @Test - public void testGetBadgedIcon() throws Exception { - ApplicationInfo info = new ApplicationInfo(); - when(mPackageManager.getApplicationInfoAsUser(eq(CALLING_PACKAGE_NAME), any(), - eq(USER_ID))).thenReturn(info); - when(mPackageManager.getApplicationIcon(eq(info))).thenReturn(mDrawable); - when(mUserManager.getBadgedIconForUser(any(), eq(UserHandle.of(USER_ID)))).thenReturn( - mBadgedDrawable); - mActivity.setIntent(new Intent() - .putExtra(Intent.EXTRA_USER_ID, USER_ID) - .putExtra(Intent.EXTRA_PACKAGE_NAME, CALLING_PACKAGE_NAME)); - - assertEquals(mBadgedDrawable, mActivity.getBadgedIcon()); - } - - @Test - public void testUnregisteredFromDispatcher() { - mActivity.unregisterBroadcastReceiver(); - verify(mBroadcastDispatcher).unregisterReceiver(any()); - verify(mContext, never()).unregisterReceiver(any()); - } -} diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityTest.kt new file mode 100644 index 000000000000..c7f1decac670 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityTest.kt @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 + +import android.annotation.UserIdInt +import android.content.Context +import android.content.Intent +import android.content.pm.ApplicationInfo +import android.content.pm.PackageManager +import android.content.pm.PackageManager.ApplicationInfoFlags +import android.graphics.drawable.Drawable +import android.os.Looper +import android.os.UserHandle +import android.os.UserManager +import androidx.test.filters.SmallTest +import androidx.test.runner.AndroidJUnit4 +import com.android.systemui.SysuiTestCase +import com.android.systemui.broadcast.BroadcastDispatcher +import com.android.systemui.util.mockito.any +import com.android.systemui.util.mockito.eq +import com.android.systemui.util.mockito.mock +import com.android.systemui.util.mockito.nullable +import com.android.systemui.util.mockito.whenever +import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers +import org.mockito.Mockito.never +import org.mockito.Mockito.verify + +/** runtest systemui -c com.android.systemui.keyguard.WorkLockActivityTest */ +@SmallTest +@RunWith(AndroidJUnit4::class) +class WorkLockActivityTest : SysuiTestCase() { + private val context: Context = mock() + private val userManager: UserManager = mock() + private val packageManager: PackageManager = mock() + private val broadcastDispatcher: BroadcastDispatcher = mock() + private val drawable: Drawable = mock() + private val badgedDrawable: Drawable = mock() + private lateinit var activity: WorkLockActivity + + private class WorkLockActivityTestable + constructor( + baseContext: Context, + broadcastDispatcher: BroadcastDispatcher, + userManager: UserManager, + packageManager: PackageManager, + ) : WorkLockActivity(broadcastDispatcher, userManager, packageManager) { + init { + attachBaseContext(baseContext) + } + } + + @Before + fun setUp() { + if (Looper.myLooper() == null) { + Looper.prepare() + } + activity = + WorkLockActivityTestable( + baseContext = context, + broadcastDispatcher = broadcastDispatcher, + userManager = userManager, + packageManager = packageManager + ) + } + + @Test + fun testGetBadgedIcon() { + val info = ApplicationInfo() + whenever( + packageManager.getApplicationInfoAsUser( + eq(CALLING_PACKAGE_NAME), + any<ApplicationInfoFlags>(), + eq(USER_ID) + ) + ) + .thenReturn(info) + whenever(packageManager.getApplicationIcon(ArgumentMatchers.eq(info))).thenReturn(drawable) + whenever(userManager.getBadgedIconForUser(any(), eq(UserHandle.of(USER_ID)))) + .thenReturn(badgedDrawable) + activity.intent = + Intent() + .putExtra(Intent.EXTRA_USER_ID, USER_ID) + .putExtra(Intent.EXTRA_PACKAGE_NAME, CALLING_PACKAGE_NAME) + assertEquals(badgedDrawable, activity.badgedIcon) + } + + @Test + fun testUnregisteredFromDispatcher() { + activity.unregisterBroadcastReceiver() + verify(broadcastDispatcher).unregisterReceiver(any()) + verify(context, never()).unregisterReceiver(nullable()) + } + + @Test + fun onBackPressed_finishActivity() { + assertFalse(activity.isFinishing) + + activity.onBackPressed() + + assertFalse(activity.isFinishing) + } + + companion object { + @UserIdInt private val USER_ID = 270 + private const val CALLING_PACKAGE_NAME = "com.android.test" + } +} 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 53d9b87b2346..ade83cf58e6e 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 @@ -17,6 +17,7 @@ package com.android.systemui.keyguard.data.repository import androidx.test.filters.SmallTest +import com.android.keyguard.KeyguardUpdateMonitor import com.android.systemui.SysuiTestCase import com.android.systemui.common.shared.model.Position import com.android.systemui.doze.DozeHost @@ -48,6 +49,7 @@ class KeyguardRepositoryImplTest : SysuiTestCase() { @Mock private lateinit var dozeHost: DozeHost @Mock private lateinit var keyguardStateController: KeyguardStateController @Mock private lateinit var wakefulnessLifecycle: WakefulnessLifecycle + @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor @Mock private lateinit var biometricUnlockController: BiometricUnlockController private lateinit var underTest: KeyguardRepositoryImpl @@ -58,11 +60,12 @@ class KeyguardRepositoryImplTest : SysuiTestCase() { underTest = KeyguardRepositoryImpl( - statusBarStateController, - keyguardStateController, - dozeHost, - wakefulnessLifecycle, - biometricUnlockController, + statusBarStateController, + dozeHost, + wakefulnessLifecycle, + biometricUnlockController, + keyguardStateController, + keyguardUpdateMonitor, ) } @@ -223,6 +226,15 @@ class KeyguardRepositoryImplTest : SysuiTestCase() { } @Test + fun isUdfpsSupported() = runBlockingTest { + whenever(keyguardUpdateMonitor.isUdfpsSupported).thenReturn(true) + assertThat(underTest.isUdfpsSupported()).isTrue() + + whenever(keyguardUpdateMonitor.isUdfpsSupported).thenReturn(false) + assertThat(underTest.isUdfpsSupported()).isFalse() + } + + @Test fun isBouncerShowing() = runBlockingTest { whenever(keyguardStateController.isBouncerShowing).thenReturn(false) var latest: Boolean? = null diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/BouncerCallbackInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerCallbackInteractorTest.kt index 3a61c57d086f..db9c4e713e37 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/BouncerCallbackInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerCallbackInteractorTest.kt @@ -30,57 +30,61 @@ import org.mockito.MockitoAnnotations @SmallTest @RunWith(JUnit4::class) -class BouncerCallbackInteractorTest : SysuiTestCase() { - private val bouncerCallbackInteractor = BouncerCallbackInteractor() - @Mock private lateinit var bouncerExpansionCallback: KeyguardBouncer.BouncerExpansionCallback +class PrimaryBouncerCallbackInteractorTest : SysuiTestCase() { + private val mPrimaryBouncerCallbackInteractor = PrimaryBouncerCallbackInteractor() + @Mock + private lateinit var mPrimaryBouncerExpansionCallback: + KeyguardBouncer.PrimaryBouncerExpansionCallback @Mock private lateinit var keyguardResetCallback: KeyguardBouncer.KeyguardResetCallback @Before fun setup() { MockitoAnnotations.initMocks(this) - bouncerCallbackInteractor.addBouncerExpansionCallback(bouncerExpansionCallback) - bouncerCallbackInteractor.addKeyguardResetCallback(keyguardResetCallback) + mPrimaryBouncerCallbackInteractor.addBouncerExpansionCallback( + mPrimaryBouncerExpansionCallback + ) + mPrimaryBouncerCallbackInteractor.addKeyguardResetCallback(keyguardResetCallback) } @Test fun testOnFullyShown() { - bouncerCallbackInteractor.dispatchFullyShown() - verify(bouncerExpansionCallback).onFullyShown() + mPrimaryBouncerCallbackInteractor.dispatchFullyShown() + verify(mPrimaryBouncerExpansionCallback).onFullyShown() } @Test fun testOnFullyHidden() { - bouncerCallbackInteractor.dispatchFullyHidden() - verify(bouncerExpansionCallback).onFullyHidden() + mPrimaryBouncerCallbackInteractor.dispatchFullyHidden() + verify(mPrimaryBouncerExpansionCallback).onFullyHidden() } @Test fun testOnExpansionChanged() { - bouncerCallbackInteractor.dispatchExpansionChanged(5f) - verify(bouncerExpansionCallback).onExpansionChanged(5f) + mPrimaryBouncerCallbackInteractor.dispatchExpansionChanged(5f) + verify(mPrimaryBouncerExpansionCallback).onExpansionChanged(5f) } @Test fun testOnVisibilityChanged() { - bouncerCallbackInteractor.dispatchVisibilityChanged(View.INVISIBLE) - verify(bouncerExpansionCallback).onVisibilityChanged(false) + mPrimaryBouncerCallbackInteractor.dispatchVisibilityChanged(View.INVISIBLE) + verify(mPrimaryBouncerExpansionCallback).onVisibilityChanged(false) } @Test fun testOnStartingToHide() { - bouncerCallbackInteractor.dispatchStartingToHide() - verify(bouncerExpansionCallback).onStartingToHide() + mPrimaryBouncerCallbackInteractor.dispatchStartingToHide() + verify(mPrimaryBouncerExpansionCallback).onStartingToHide() } @Test fun testOnStartingToShow() { - bouncerCallbackInteractor.dispatchStartingToShow() - verify(bouncerExpansionCallback).onStartingToShow() + mPrimaryBouncerCallbackInteractor.dispatchStartingToShow() + verify(mPrimaryBouncerExpansionCallback).onStartingToShow() } @Test fun testOnKeyguardReset() { - bouncerCallbackInteractor.dispatchReset() + mPrimaryBouncerCallbackInteractor.dispatchReset() verify(keyguardResetCallback).onKeyguardReset() } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/BouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorTest.kt index 5743b2f03d3a..c85f7b9e6885 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/BouncerInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorTest.kt @@ -53,59 +53,59 @@ import org.mockito.MockitoAnnotations @SmallTest @RunWithLooper(setAsMainLooper = true) @RunWith(AndroidTestingRunner::class) -class BouncerInteractorTest : SysuiTestCase() { +class PrimaryBouncerInteractorTest : SysuiTestCase() { @Mock(answer = Answers.RETURNS_DEEP_STUBS) private lateinit var repository: KeyguardBouncerRepository @Mock(answer = Answers.RETURNS_DEEP_STUBS) private lateinit var bouncerView: BouncerView @Mock private lateinit var bouncerViewDelegate: BouncerViewDelegate @Mock private lateinit var keyguardStateController: KeyguardStateController @Mock private lateinit var keyguardSecurityModel: KeyguardSecurityModel - @Mock private lateinit var bouncerCallbackInteractor: BouncerCallbackInteractor + @Mock private lateinit var mPrimaryBouncerCallbackInteractor: PrimaryBouncerCallbackInteractor @Mock private lateinit var falsingCollector: FalsingCollector @Mock private lateinit var dismissCallbackRegistry: DismissCallbackRegistry @Mock private lateinit var keyguardBypassController: KeyguardBypassController @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor private val mainHandler = FakeHandler(Looper.getMainLooper()) - private lateinit var bouncerInteractor: BouncerInteractor + private lateinit var mPrimaryBouncerInteractor: PrimaryBouncerInteractor @Before fun setUp() { MockitoAnnotations.initMocks(this) DejankUtils.setImmediate(true) - bouncerInteractor = - BouncerInteractor( + mPrimaryBouncerInteractor = + PrimaryBouncerInteractor( repository, bouncerView, mainHandler, keyguardStateController, keyguardSecurityModel, - bouncerCallbackInteractor, + mPrimaryBouncerCallbackInteractor, falsingCollector, dismissCallbackRegistry, keyguardBypassController, keyguardUpdateMonitor, ) - `when`(repository.startingDisappearAnimation.value).thenReturn(null) - `when`(repository.show.value).thenReturn(null) + `when`(repository.primaryBouncerStartingDisappearAnimation.value).thenReturn(null) + `when`(repository.primaryBouncerShow.value).thenReturn(null) `when`(bouncerView.delegate).thenReturn(bouncerViewDelegate) } @Test fun testShow_isScrimmed() { - bouncerInteractor.show(true) + mPrimaryBouncerInteractor.show(true) verify(repository).setShowMessage(null) verify(repository).setOnScreenTurnedOff(false) verify(repository).setKeyguardAuthenticated(null) - verify(repository).setHide(false) - verify(repository).setStartingToHide(false) - verify(repository).setScrimmed(true) + verify(repository).setPrimaryHide(false) + verify(repository).setPrimaryStartingToHide(false) + verify(repository).setPrimaryScrimmed(true) verify(repository).setPanelExpansion(EXPANSION_VISIBLE) - verify(repository).setShowingSoon(true) + verify(repository).setPrimaryShowingSoon(true) verify(keyguardStateController).notifyBouncerShowing(true) - verify(bouncerCallbackInteractor).dispatchStartingToShow() - verify(repository).setVisible(true) - verify(repository).setShow(any(KeyguardBouncerModel::class.java)) - verify(repository).setShowingSoon(false) + verify(mPrimaryBouncerCallbackInteractor).dispatchStartingToShow() + verify(repository).setPrimaryVisible(true) + verify(repository).setPrimaryShow(any(KeyguardBouncerModel::class.java)) + verify(repository).setPrimaryShowingSoon(false) } @Test @@ -117,60 +117,60 @@ class BouncerInteractorTest : SysuiTestCase() { fun testShow_keyguardIsDone() { `when`(bouncerView.delegate?.showNextSecurityScreenOrFinish()).thenReturn(true) verify(keyguardStateController, never()).notifyBouncerShowing(true) - verify(bouncerCallbackInteractor, never()).dispatchStartingToShow() + verify(mPrimaryBouncerCallbackInteractor, never()).dispatchStartingToShow() } @Test fun testHide() { - bouncerInteractor.hide() + mPrimaryBouncerInteractor.hide() verify(falsingCollector).onBouncerHidden() verify(keyguardStateController).notifyBouncerShowing(false) - verify(repository).setShowingSoon(false) - verify(repository).setVisible(false) - verify(repository).setHide(true) - verify(repository).setShow(null) + verify(repository).setPrimaryShowingSoon(false) + verify(repository).setPrimaryVisible(false) + verify(repository).setPrimaryHide(true) + verify(repository).setPrimaryShow(null) } @Test fun testExpansion() { `when`(repository.panelExpansionAmount.value).thenReturn(0.5f) - bouncerInteractor.setPanelExpansion(0.6f) + mPrimaryBouncerInteractor.setPanelExpansion(0.6f) verify(repository).setPanelExpansion(0.6f) - verify(bouncerCallbackInteractor).dispatchExpansionChanged(0.6f) + verify(mPrimaryBouncerCallbackInteractor).dispatchExpansionChanged(0.6f) } @Test fun testExpansion_fullyShown() { `when`(repository.panelExpansionAmount.value).thenReturn(0.5f) - `when`(repository.startingDisappearAnimation.value).thenReturn(null) - bouncerInteractor.setPanelExpansion(EXPANSION_VISIBLE) + `when`(repository.primaryBouncerStartingDisappearAnimation.value).thenReturn(null) + mPrimaryBouncerInteractor.setPanelExpansion(EXPANSION_VISIBLE) verify(falsingCollector).onBouncerShown() - verify(bouncerCallbackInteractor).dispatchFullyShown() + verify(mPrimaryBouncerCallbackInteractor).dispatchFullyShown() } @Test fun testExpansion_fullyHidden() { `when`(repository.panelExpansionAmount.value).thenReturn(0.5f) - `when`(repository.startingDisappearAnimation.value).thenReturn(null) - bouncerInteractor.setPanelExpansion(EXPANSION_HIDDEN) - verify(repository).setVisible(false) - verify(repository).setShow(null) + `when`(repository.primaryBouncerStartingDisappearAnimation.value).thenReturn(null) + mPrimaryBouncerInteractor.setPanelExpansion(EXPANSION_HIDDEN) + verify(repository).setPrimaryVisible(false) + verify(repository).setPrimaryShow(null) verify(falsingCollector).onBouncerHidden() - verify(bouncerCallbackInteractor).dispatchReset() - verify(bouncerCallbackInteractor).dispatchFullyHidden() + verify(mPrimaryBouncerCallbackInteractor).dispatchReset() + verify(mPrimaryBouncerCallbackInteractor).dispatchFullyHidden() } @Test fun testExpansion_startingToHide() { `when`(repository.panelExpansionAmount.value).thenReturn(EXPANSION_VISIBLE) - bouncerInteractor.setPanelExpansion(0.1f) - verify(repository).setStartingToHide(true) - verify(bouncerCallbackInteractor).dispatchStartingToHide() + mPrimaryBouncerInteractor.setPanelExpansion(0.1f) + verify(repository).setPrimaryStartingToHide(true) + verify(mPrimaryBouncerCallbackInteractor).dispatchStartingToHide() } @Test fun testShowMessage() { - bouncerInteractor.showMessage("abc", null) + mPrimaryBouncerInteractor.showMessage("abc", null) verify(repository).setShowMessage(BouncerShowMessageModel("abc", null)) } @@ -178,100 +178,100 @@ class BouncerInteractorTest : SysuiTestCase() { fun testDismissAction() { val onDismissAction = mock(ActivityStarter.OnDismissAction::class.java) val cancelAction = mock(Runnable::class.java) - bouncerInteractor.setDismissAction(onDismissAction, cancelAction) + mPrimaryBouncerInteractor.setDismissAction(onDismissAction, cancelAction) verify(bouncerViewDelegate).setDismissAction(onDismissAction, cancelAction) } @Test fun testUpdateResources() { - bouncerInteractor.updateResources() + mPrimaryBouncerInteractor.updateResources() verify(repository).setResourceUpdateRequests(true) } @Test fun testNotifyKeyguardAuthenticated() { - bouncerInteractor.notifyKeyguardAuthenticated(true) + mPrimaryBouncerInteractor.notifyKeyguardAuthenticated(true) verify(repository).setKeyguardAuthenticated(true) } @Test fun testOnScreenTurnedOff() { - bouncerInteractor.onScreenTurnedOff() + mPrimaryBouncerInteractor.onScreenTurnedOff() verify(repository).setOnScreenTurnedOff(true) } @Test fun testSetKeyguardPosition() { - bouncerInteractor.setKeyguardPosition(0f) + mPrimaryBouncerInteractor.setKeyguardPosition(0f) verify(repository).setKeyguardPosition(0f) } @Test fun testNotifyKeyguardAuthenticatedHandled() { - bouncerInteractor.notifyKeyguardAuthenticatedHandled() + mPrimaryBouncerInteractor.notifyKeyguardAuthenticatedHandled() verify(repository).setKeyguardAuthenticated(null) } @Test fun testNotifyUpdatedResources() { - bouncerInteractor.notifyUpdatedResources() + mPrimaryBouncerInteractor.notifyUpdatedResources() verify(repository).setResourceUpdateRequests(false) } @Test fun testSetBackButtonEnabled() { - bouncerInteractor.setBackButtonEnabled(true) + mPrimaryBouncerInteractor.setBackButtonEnabled(true) verify(repository).setIsBackButtonEnabled(true) } @Test fun testStartDisappearAnimation() { val runnable = mock(Runnable::class.java) - bouncerInteractor.startDisappearAnimation(runnable) - verify(repository).setStartDisappearAnimation(any(Runnable::class.java)) + mPrimaryBouncerInteractor.startDisappearAnimation(runnable) + verify(repository).setPrimaryStartDisappearAnimation(any(Runnable::class.java)) } @Test fun testIsFullShowing() { - `when`(repository.isVisible.value).thenReturn(true) + `when`(repository.primaryBouncerVisible.value).thenReturn(true) `when`(repository.panelExpansionAmount.value).thenReturn(EXPANSION_VISIBLE) - `when`(repository.startingDisappearAnimation.value).thenReturn(null) - assertThat(bouncerInteractor.isFullyShowing()).isTrue() - `when`(repository.isVisible.value).thenReturn(false) - assertThat(bouncerInteractor.isFullyShowing()).isFalse() + `when`(repository.primaryBouncerStartingDisappearAnimation.value).thenReturn(null) + assertThat(mPrimaryBouncerInteractor.isFullyShowing()).isTrue() + `when`(repository.primaryBouncerVisible.value).thenReturn(false) + assertThat(mPrimaryBouncerInteractor.isFullyShowing()).isFalse() } @Test fun testIsScrimmed() { - `when`(repository.isScrimmed.value).thenReturn(true) - assertThat(bouncerInteractor.isScrimmed()).isTrue() - `when`(repository.isScrimmed.value).thenReturn(false) - assertThat(bouncerInteractor.isScrimmed()).isFalse() + `when`(repository.primaryBouncerScrimmed.value).thenReturn(true) + assertThat(mPrimaryBouncerInteractor.isScrimmed()).isTrue() + `when`(repository.primaryBouncerScrimmed.value).thenReturn(false) + assertThat(mPrimaryBouncerInteractor.isScrimmed()).isFalse() } @Test fun testIsInTransit() { - `when`(repository.showingSoon.value).thenReturn(true) - assertThat(bouncerInteractor.isInTransit()).isTrue() - `when`(repository.showingSoon.value).thenReturn(false) - assertThat(bouncerInteractor.isInTransit()).isFalse() + `when`(repository.primaryBouncerShowingSoon.value).thenReturn(true) + assertThat(mPrimaryBouncerInteractor.isInTransit()).isTrue() + `when`(repository.primaryBouncerShowingSoon.value).thenReturn(false) + assertThat(mPrimaryBouncerInteractor.isInTransit()).isFalse() `when`(repository.panelExpansionAmount.value).thenReturn(0.5f) - assertThat(bouncerInteractor.isInTransit()).isTrue() + assertThat(mPrimaryBouncerInteractor.isInTransit()).isTrue() } @Test fun testIsAnimatingAway() { - `when`(repository.startingDisappearAnimation.value).thenReturn(Runnable {}) - assertThat(bouncerInteractor.isAnimatingAway()).isTrue() - `when`(repository.startingDisappearAnimation.value).thenReturn(null) - assertThat(bouncerInteractor.isAnimatingAway()).isFalse() + `when`(repository.primaryBouncerStartingDisappearAnimation.value).thenReturn(Runnable {}) + assertThat(mPrimaryBouncerInteractor.isAnimatingAway()).isTrue() + `when`(repository.primaryBouncerStartingDisappearAnimation.value).thenReturn(null) + assertThat(mPrimaryBouncerInteractor.isAnimatingAway()).isFalse() } @Test fun testWillDismissWithAction() { `when`(bouncerViewDelegate.willDismissWithActions()).thenReturn(true) - assertThat(bouncerInteractor.willDismissWithAction()).isTrue() + assertThat(mPrimaryBouncerInteractor.willDismissWithAction()).isTrue() `when`(bouncerViewDelegate.willDismissWithActions()).thenReturn(false) - assertThat(bouncerInteractor.willDismissWithAction()).isFalse() + assertThat(mPrimaryBouncerInteractor.willDismissWithAction()).isFalse() } } 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 c8e8943689c9..6ca34e0bb7ce 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 @@ -49,6 +49,7 @@ import javax.inject.Provider import junit.framework.Assert.assertEquals import junit.framework.Assert.assertTrue import org.junit.Before +import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor @@ -119,6 +120,7 @@ class MediaCarouselControllerTest : SysuiTestCase() { MediaPlayerData.clear() } + @Ignore("b/253229241") @Test fun testPlayerOrdering() { // Test values: key, data, last active time @@ -295,6 +297,7 @@ class MediaCarouselControllerTest : SysuiTestCase() { } } + @Ignore("b/253229241") @Test fun testOrderWithSmartspace_prioritized() { testPlayerOrdering() @@ -312,6 +315,7 @@ class MediaCarouselControllerTest : SysuiTestCase() { assertTrue(MediaPlayerData.playerKeys().elementAt(2).isSsMediaRec) } + @Ignore("b/253229241") @Test fun testOrderWithSmartspace_prioritized_updatingVisibleMediaPlayers() { testPlayerOrdering() @@ -328,6 +332,7 @@ class MediaCarouselControllerTest : SysuiTestCase() { assertTrue(MediaPlayerData.visiblePlayerKeys().elementAt(2).isSsMediaRec) } + @Ignore("b/253229241") @Test fun testOrderWithSmartspace_notPrioritized() { testPlayerOrdering() @@ -346,6 +351,7 @@ class MediaCarouselControllerTest : SysuiTestCase() { assertTrue(MediaPlayerData.playerKeys().elementAt(idx).isSsMediaRec) } + @Ignore("b/253229241") @Test fun testPlayingExistingMediaPlayerFromCarousel_visibleMediaPlayersNotUpdated() { testPlayerOrdering() @@ -382,6 +388,8 @@ class MediaCarouselControllerTest : SysuiTestCase() { MediaPlayerData.playerKeys().elementAt(0) ) } + + @Ignore("b/253229241") @Test fun testSwipeDismiss_logged() { mediaCarouselController.mediaCarouselScrollHandler.dismissCallback.invoke() @@ -389,6 +397,7 @@ class MediaCarouselControllerTest : SysuiTestCase() { verify(logger).logSwipeDismiss() } + @Ignore("b/253229241") @Test fun testSettingsButton_logged() { mediaCarouselController.settingsButton.callOnClick() @@ -396,6 +405,7 @@ class MediaCarouselControllerTest : SysuiTestCase() { verify(logger).logCarouselSettings() } + @Ignore("b/253229241") @Test fun testLocationChangeQs_logged() { mediaCarouselController.onDesiredLocationChanged( @@ -406,6 +416,7 @@ class MediaCarouselControllerTest : SysuiTestCase() { verify(logger).logCarouselPosition(MediaHierarchyManager.LOCATION_QS) } + @Ignore("b/253229241") @Test fun testLocationChangeQqs_logged() { mediaCarouselController.onDesiredLocationChanged( @@ -416,6 +427,7 @@ class MediaCarouselControllerTest : SysuiTestCase() { verify(logger).logCarouselPosition(MediaHierarchyManager.LOCATION_QQS) } + @Ignore("b/253229241") @Test fun testLocationChangeLockscreen_logged() { mediaCarouselController.onDesiredLocationChanged( @@ -426,6 +438,7 @@ class MediaCarouselControllerTest : SysuiTestCase() { verify(logger).logCarouselPosition(MediaHierarchyManager.LOCATION_LOCKSCREEN) } + @Ignore("b/253229241") @Test fun testLocationChangeDream_logged() { mediaCarouselController.onDesiredLocationChanged( @@ -436,6 +449,7 @@ class MediaCarouselControllerTest : SysuiTestCase() { verify(logger).logCarouselPosition(MediaHierarchyManager.LOCATION_DREAM_OVERLAY) } + @Ignore("b/253229241") @Test fun testRecommendationRemoved_logged() { val packageName = "smartspace package" @@ -449,6 +463,7 @@ class MediaCarouselControllerTest : SysuiTestCase() { verify(logger).logRecommendationRemoved(eq(packageName), eq(instanceId!!)) } + @Ignore("b/253229241") @Test fun testMediaLoaded_ScrollToActivePlayer() { listener.value.onMediaDataLoaded( @@ -506,6 +521,7 @@ class MediaCarouselControllerTest : SysuiTestCase() { ) } + @Ignore("b/253229241") @Test fun testMediaLoadedFromRecommendationCard_ScrollToActivePlayer() { listener.value.onSmartspaceMediaDataLoaded( @@ -549,6 +565,7 @@ class MediaCarouselControllerTest : SysuiTestCase() { assertEquals(playerIndex, 0) } + @Ignore("b/253229241") @Test fun testRecommendationRemovedWhileNotVisible_updateHostVisibility() { var result = false @@ -560,6 +577,7 @@ class MediaCarouselControllerTest : SysuiTestCase() { assertEquals(true, result) } + @Ignore("b/253229241") @Test fun testRecommendationRemovedWhileVisible_thenReorders_updateHostVisibility() { var result = false @@ -573,6 +591,7 @@ class MediaCarouselControllerTest : SysuiTestCase() { assertEquals(true, result) } + @Ignore("b/253229241") @Test fun testGetCurrentVisibleMediaContentIntent() { val clickIntent1 = mock(PendingIntent::class.java) @@ -619,6 +638,7 @@ class MediaCarouselControllerTest : SysuiTestCase() { assertEquals(mediaCarouselController.getCurrentVisibleMediaContentIntent(), clickIntent2) } + @Ignore("b/253229241") @Test fun testSetCurrentState_UpdatePageIndicatorAlphaWhenSquish() { val delta = 0.0001F 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 81901569bde8..1ad2ca9b9db3 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 @@ -1137,6 +1137,19 @@ public class MediaControlPanelTest : SysuiTestCase() { /* ***** Guts tests for the player ***** */ @Test + fun player_longClick_isFalse() { + whenever(falsingManager.isFalseLongTap(FalsingManager.LOW_PENALTY)).thenReturn(true) + player.attachPlayer(viewHolder) + + val captor = ArgumentCaptor.forClass(View.OnLongClickListener::class.java) + verify(viewHolder.player).onLongClickListener = captor.capture() + + captor.value.onLongClick(viewHolder.player) + verify(mediaViewController, never()).openGuts() + verify(mediaViewController, never()).closeGuts() + } + + @Test fun player_longClickWhenGutsClosed_gutsOpens() { player.attachPlayer(viewHolder) player.bindPlayer(mediaData, KEY) @@ -1316,6 +1329,20 @@ public class MediaControlPanelTest : SysuiTestCase() { /* ***** Guts tests for the recommendations ***** */ @Test + fun recommendations_longClick_isFalse() { + whenever(falsingManager.isFalseLongTap(FalsingManager.LOW_PENALTY)).thenReturn(true) + player.attachRecommendation(recommendationViewHolder) + player.bindRecommendation(smartspaceData) + + val captor = ArgumentCaptor.forClass(View.OnLongClickListener::class.java) + verify(viewHolder.player).onLongClickListener = captor.capture() + + captor.value.onLongClick(viewHolder.player) + verify(mediaViewController, never()).openGuts() + verify(mediaViewController, never()).closeGuts() + } + + @Test fun recommendations_longClickWhenGutsClosed_gutsOpens() { player.attachRecommendation(recommendationViewHolder) player.bindRecommendation(smartspaceData) diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt index 8c3ae3d01f1d..68a5f47c5e0b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt @@ -43,6 +43,7 @@ import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.eq import com.android.systemui.util.time.FakeSystemClock import com.android.systemui.util.view.ViewUtil +import com.android.systemui.util.wakelock.WakeLockFake import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Test @@ -85,6 +86,10 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() { private lateinit var fakeAppIconDrawable: Drawable private lateinit var uiEventLoggerFake: UiEventLoggerFake private lateinit var receiverUiEventLogger: MediaTttReceiverUiEventLogger + private lateinit var fakeClock: FakeSystemClock + private lateinit var fakeExecutor: FakeExecutor + private lateinit var fakeWakeLockBuilder: WakeLockFake.Builder + private lateinit var fakeWakeLock: WakeLockFake @Before fun setUp() { @@ -99,15 +104,22 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() { )).thenReturn(applicationInfo) context.setMockPackageManager(packageManager) + fakeClock = FakeSystemClock() + fakeExecutor = FakeExecutor(fakeClock) + uiEventLoggerFake = UiEventLoggerFake() receiverUiEventLogger = MediaTttReceiverUiEventLogger(uiEventLoggerFake) + fakeWakeLock = WakeLockFake() + fakeWakeLockBuilder = WakeLockFake.Builder(context) + fakeWakeLockBuilder.setWakeLock(fakeWakeLock) + controllerReceiver = MediaTttChipControllerReceiver( commandQueue, context, logger, windowManager, - FakeExecutor(FakeSystemClock()), + fakeExecutor, accessibilityManager, configurationController, powerManager, @@ -115,6 +127,7 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() { mediaTttFlags, receiverUiEventLogger, viewUtil, + fakeWakeLockBuilder, ) controllerReceiver.start() @@ -141,6 +154,7 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() { mediaTttFlags, receiverUiEventLogger, viewUtil, + fakeWakeLockBuilder, ) controllerReceiver.start() @@ -200,6 +214,39 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() { } @Test + fun commandQueueCallback_closeThenFar_wakeLockAcquiredThenReleased() { + commandQueueCallback.updateMediaTapToTransferReceiverDisplay( + StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER, + routeInfo, + null, + null + ) + + assertThat(fakeWakeLock.isHeld).isTrue() + + commandQueueCallback.updateMediaTapToTransferReceiverDisplay( + StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_FAR_FROM_SENDER, + routeInfo, + null, + null + ) + + assertThat(fakeWakeLock.isHeld).isFalse() + } + + @Test + fun commandQueueCallback_closeThenFar_wakeLockNeverAcquired() { + commandQueueCallback.updateMediaTapToTransferReceiverDisplay( + StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_FAR_FROM_SENDER, + routeInfo, + null, + null + ) + + assertThat(fakeWakeLock.isHeld).isFalse() + } + + @Test fun receivesNewStateFromCommandQueue_isLogged() { commandQueueCallback.updateMediaTapToTransferReceiverDisplay( StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER, diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinatorTest.kt index ad19bc2a80e0..4437394da943 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinatorTest.kt @@ -52,6 +52,7 @@ import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.eq import com.android.systemui.util.time.FakeSystemClock import com.android.systemui.util.view.ViewUtil +import com.android.systemui.util.wakelock.WakeLockFake import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Test @@ -89,6 +90,8 @@ class MediaTttSenderCoordinatorTest : SysuiTestCase() { @Mock private lateinit var viewUtil: ViewUtil @Mock private lateinit var windowManager: WindowManager @Mock private lateinit var vibratorHelper: VibratorHelper + private lateinit var fakeWakeLockBuilder: WakeLockFake.Builder + private lateinit var fakeWakeLock: WakeLockFake private lateinit var chipbarCoordinator: ChipbarCoordinator private lateinit var commandQueueCallback: CommandQueue.Callbacks private lateinit var fakeAppIconDrawable: Drawable @@ -118,6 +121,10 @@ class MediaTttSenderCoordinatorTest : SysuiTestCase() { fakeClock = FakeSystemClock() fakeExecutor = FakeExecutor(fakeClock) + fakeWakeLock = WakeLockFake() + fakeWakeLockBuilder = WakeLockFake.Builder(context) + fakeWakeLockBuilder.setWakeLock(fakeWakeLock) + uiEventLoggerFake = UiEventLoggerFake() uiEventLogger = MediaTttSenderUiEventLogger(uiEventLoggerFake) @@ -134,6 +141,7 @@ class MediaTttSenderCoordinatorTest : SysuiTestCase() { falsingCollector, viewUtil, vibratorHelper, + fakeWakeLockBuilder, ) chipbarCoordinator.start() @@ -472,6 +480,36 @@ class MediaTttSenderCoordinatorTest : SysuiTestCase() { } @Test + fun commandQueueCallback_almostCloseThenFarFromReceiver_wakeLockAcquiredThenReleased() { + commandQueueCallback.updateMediaTapToTransferSenderDisplay( + StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST, + routeInfo, + null + ) + + assertThat(fakeWakeLock.isHeld).isTrue() + + commandQueueCallback.updateMediaTapToTransferSenderDisplay( + StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER, + routeInfo, + null + ) + + assertThat(fakeWakeLock.isHeld).isFalse() + } + + @Test + fun commandQueueCallback_FarFromReceiver_wakeLockNeverReleased() { + commandQueueCallback.updateMediaTapToTransferSenderDisplay( + StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER, + routeInfo, + null + ) + + assertThat(fakeWakeLock.isHeld).isFalse() + } + + @Test fun commandQueueCallback_invalidStateParam_noChipShown() { commandQueueCallback.updateMediaTapToTransferSenderDisplay(100, routeInfo, null) diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/IconLoaderLibAppIconLoaderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/IconLoaderLibAppIconLoaderTest.kt new file mode 100644 index 000000000000..9b346d0120ef --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/IconLoaderLibAppIconLoaderTest.kt @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.mediaprojection.appselector.data + +import android.content.ComponentName +import android.content.pm.ActivityInfo +import android.content.pm.PackageManager +import android.graphics.Bitmap +import android.graphics.drawable.Drawable +import androidx.test.filters.SmallTest +import com.android.launcher3.icons.BitmapInfo +import com.android.launcher3.icons.FastBitmapDrawable +import com.android.launcher3.icons.IconFactory +import com.android.systemui.SysuiTestCase +import com.android.systemui.shared.system.PackageManagerWrapper +import com.android.systemui.util.mockito.any +import com.android.systemui.util.mockito.eq +import com.android.systemui.util.mockito.mock +import com.android.systemui.util.mockito.whenever +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.runBlocking +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +@SmallTest +@RunWith(JUnit4::class) +class IconLoaderLibAppIconLoaderTest : SysuiTestCase() { + + private val iconFactory: IconFactory = mock() + private val packageManagerWrapper: PackageManagerWrapper = mock() + private val packageManager: PackageManager = mock() + private val dispatcher = Dispatchers.Unconfined + + private val appIconLoader = + IconLoaderLibAppIconLoader( + backgroundDispatcher = dispatcher, + context = context, + packageManagerWrapper = packageManagerWrapper, + packageManager = packageManager, + iconFactoryProvider = { iconFactory } + ) + + @Test + fun loadIcon_loadsIconUsingTheSameUserId() { + val icon = createIcon() + val component = ComponentName("com.test", "TestApplication") + givenIcon(component, userId = 123, icon = icon) + + val loadedIcon = runBlocking { appIconLoader.loadIcon(userId = 123, component = component) } + + assertThat(loadedIcon).isEqualTo(icon) + } + + private fun givenIcon(component: ComponentName, userId: Int, icon: FastBitmapDrawable) { + val activityInfo = mock<ActivityInfo>() + whenever(packageManagerWrapper.getActivityInfo(component, userId)).thenReturn(activityInfo) + val rawIcon = mock<Drawable>() + whenever(activityInfo.loadIcon(packageManager)).thenReturn(rawIcon) + + val bitmapInfo = mock<BitmapInfo>() + whenever(iconFactory.createBadgedIconBitmap(eq(rawIcon), any())).thenReturn(bitmapInfo) + whenever(bitmapInfo.newIcon(context)).thenReturn(icon) + } + + private fun createIcon(): FastBitmapDrawable = + FastBitmapDrawable(Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888)) +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt index f20c6a29b840..9758842d1e35 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt @@ -25,8 +25,8 @@ import androidx.test.runner.AndroidJUnit4 import com.android.systemui.SysuiTestCase import com.android.systemui.notetask.NoteTaskIntentResolver.Companion.NOTES_ACTION import com.android.systemui.util.mockito.whenever -import com.android.wm.shell.floating.FloatingTasks -import java.util.* +import com.android.wm.shell.bubbles.Bubbles +import java.util.Optional import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -49,8 +49,8 @@ internal class NoteTaskControllerTest : SysuiTestCase() { @Mock lateinit var context: Context @Mock lateinit var noteTaskIntentResolver: NoteTaskIntentResolver - @Mock lateinit var floatingTasks: FloatingTasks - @Mock lateinit var optionalFloatingTasks: Optional<FloatingTasks> + @Mock lateinit var bubbles: Bubbles + @Mock lateinit var optionalBubbles: Optional<Bubbles> @Mock lateinit var keyguardManager: KeyguardManager @Mock lateinit var optionalKeyguardManager: Optional<KeyguardManager> @Mock lateinit var optionalUserManager: Optional<UserManager> @@ -61,7 +61,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() { MockitoAnnotations.initMocks(this) whenever(noteTaskIntentResolver.resolveIntent()).thenReturn(notesIntent) - whenever(optionalFloatingTasks.orElse(null)).thenReturn(floatingTasks) + whenever(optionalBubbles.orElse(null)).thenReturn(bubbles) whenever(optionalKeyguardManager.orElse(null)).thenReturn(keyguardManager) whenever(optionalUserManager.orElse(null)).thenReturn(userManager) whenever(userManager.isUserUnlocked).thenReturn(true) @@ -71,7 +71,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() { return NoteTaskController( context = context, intentResolver = noteTaskIntentResolver, - optionalFloatingTasks = optionalFloatingTasks, + optionalBubbles = optionalBubbles, optionalKeyguardManager = optionalKeyguardManager, optionalUserManager = optionalUserManager, isEnabled = isEnabled, @@ -85,16 +85,16 @@ internal class NoteTaskControllerTest : SysuiTestCase() { createNoteTaskController().handleSystemKey(KeyEvent.KEYCODE_VIDEO_APP_1) verify(context).startActivity(notesIntent) - verify(floatingTasks, never()).showOrSetStashed(notesIntent) + verify(bubbles, never()).showAppBubble(notesIntent) } @Test - fun handleSystemKey_keyguardIsUnlocked_shouldStartFloatingTask() { + fun handleSystemKey_keyguardIsUnlocked_shouldStartBubbles() { whenever(keyguardManager.isKeyguardLocked).thenReturn(false) createNoteTaskController().handleSystemKey(KeyEvent.KEYCODE_VIDEO_APP_1) - verify(floatingTasks).showOrSetStashed(notesIntent) + verify(bubbles).showAppBubble(notesIntent) verify(context, never()).startActivity(notesIntent) } @@ -103,17 +103,17 @@ internal class NoteTaskControllerTest : SysuiTestCase() { createNoteTaskController().handleSystemKey(KeyEvent.KEYCODE_UNKNOWN) verify(context, never()).startActivity(notesIntent) - verify(floatingTasks, never()).showOrSetStashed(notesIntent) + verify(bubbles, never()).showAppBubble(notesIntent) } @Test - fun handleSystemKey_floatingTasksIsNull_shouldDoNothing() { - whenever(optionalFloatingTasks.orElse(null)).thenReturn(null) + fun handleSystemKey_bubblesIsNull_shouldDoNothing() { + whenever(optionalBubbles.orElse(null)).thenReturn(null) createNoteTaskController().handleSystemKey(KeyEvent.KEYCODE_VIDEO_APP_1) verify(context, never()).startActivity(notesIntent) - verify(floatingTasks, never()).showOrSetStashed(notesIntent) + verify(bubbles, never()).showAppBubble(notesIntent) } @Test @@ -123,7 +123,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() { createNoteTaskController().handleSystemKey(KeyEvent.KEYCODE_VIDEO_APP_1) verify(context, never()).startActivity(notesIntent) - verify(floatingTasks, never()).showOrSetStashed(notesIntent) + verify(bubbles, never()).showAppBubble(notesIntent) } @Test @@ -133,7 +133,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() { createNoteTaskController().handleSystemKey(KeyEvent.KEYCODE_VIDEO_APP_1) verify(context, never()).startActivity(notesIntent) - verify(floatingTasks, never()).showOrSetStashed(notesIntent) + verify(bubbles, never()).showAppBubble(notesIntent) } @Test @@ -143,7 +143,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() { createNoteTaskController().handleSystemKey(KeyEvent.KEYCODE_VIDEO_APP_1) verify(context, never()).startActivity(notesIntent) - verify(floatingTasks, never()).showOrSetStashed(notesIntent) + verify(bubbles, never()).showAppBubble(notesIntent) } @Test @@ -151,7 +151,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() { createNoteTaskController(isEnabled = false).handleSystemKey(KeyEvent.KEYCODE_VIDEO_APP_1) verify(context, never()).startActivity(notesIntent) - verify(floatingTasks, never()).showOrSetStashed(notesIntent) + verify(bubbles, never()).showAppBubble(notesIntent) } @Test @@ -161,6 +161,6 @@ internal class NoteTaskControllerTest : SysuiTestCase() { createNoteTaskController().handleSystemKey(KeyEvent.KEYCODE_VIDEO_APP_1) verify(context, never()).startActivity(notesIntent) - verify(floatingTasks, never()).showOrSetStashed(notesIntent) + verify(bubbles, never()).showAppBubble(notesIntent) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInitializerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInitializerTest.kt index f344c8d9eec4..334089c43e27 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInitializerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInitializerTest.kt @@ -21,8 +21,8 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.statusbar.CommandQueue import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever -import com.android.wm.shell.floating.FloatingTasks -import java.util.* +import com.android.wm.shell.bubbles.Bubbles +import java.util.Optional import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -43,20 +43,20 @@ import org.mockito.MockitoAnnotations internal class NoteTaskInitializerTest : SysuiTestCase() { @Mock lateinit var commandQueue: CommandQueue - @Mock lateinit var floatingTasks: FloatingTasks - @Mock lateinit var optionalFloatingTasks: Optional<FloatingTasks> + @Mock lateinit var bubbles: Bubbles + @Mock lateinit var optionalBubbles: Optional<Bubbles> @Before fun setUp() { MockitoAnnotations.initMocks(this) - whenever(optionalFloatingTasks.isPresent).thenReturn(true) - whenever(optionalFloatingTasks.orElse(null)).thenReturn(floatingTasks) + whenever(optionalBubbles.isPresent).thenReturn(true) + whenever(optionalBubbles.orElse(null)).thenReturn(bubbles) } private fun createNoteTaskInitializer(isEnabled: Boolean = true): NoteTaskInitializer { return NoteTaskInitializer( - optionalFloatingTasks = optionalFloatingTasks, + optionalBubbles = optionalBubbles, lazyNoteTaskController = mock(), commandQueue = commandQueue, isEnabled = isEnabled, @@ -78,8 +78,8 @@ internal class NoteTaskInitializerTest : SysuiTestCase() { } @Test - fun initialize_floatingTasksNotPresent_shouldDoNothing() { - whenever(optionalFloatingTasks.isPresent).thenReturn(false) + fun initialize_bubblesNotPresent_shouldDoNothing() { + whenever(optionalBubbles.isPresent).thenReturn(false) createNoteTaskInitializer().initialize() diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/HeaderPrivacyIconsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/HeaderPrivacyIconsControllerTest.kt index 4c7240673fb0..3620233fc9df 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/HeaderPrivacyIconsControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/HeaderPrivacyIconsControllerTest.kt @@ -19,6 +19,7 @@ import com.android.systemui.privacy.PrivacyDialogController import com.android.systemui.privacy.PrivacyItemController import com.android.systemui.privacy.logging.PrivacyLogger import com.android.systemui.statusbar.phone.StatusIconContainer +import com.android.systemui.statusbar.policy.DeviceProvisionedController import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.argumentCaptor @@ -66,6 +67,8 @@ class HeaderPrivacyIconsControllerTest : SysuiTestCase() { private lateinit var broadcastDispatcher: BroadcastDispatcher @Mock private lateinit var safetyCenterManager: SafetyCenterManager + @Mock + private lateinit var deviceProvisionedController: DeviceProvisionedController private val uiExecutor = FakeExecutor(FakeSystemClock()) private val backgroundExecutor = FakeExecutor(FakeSystemClock()) @@ -80,6 +83,7 @@ class HeaderPrivacyIconsControllerTest : SysuiTestCase() { whenever(privacyChip.context).thenReturn(context) whenever(privacyChip.resources).thenReturn(context.resources) whenever(privacyChip.isAttachedToWindow).thenReturn(true) + whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true) cameraSlotName = context.getString(com.android.internal.R.string.status_bar_camera) microphoneSlotName = context.getString(com.android.internal.R.string.status_bar_microphone) @@ -98,7 +102,8 @@ class HeaderPrivacyIconsControllerTest : SysuiTestCase() { activityStarter, appOpsController, broadcastDispatcher, - safetyCenterManager + safetyCenterManager, + deviceProvisionedController ) backgroundExecutor.runAllReady() @@ -199,6 +204,18 @@ class HeaderPrivacyIconsControllerTest : SysuiTestCase() { ) } + @Test + fun testNoDialogWhenDeviceNotProvisioned() { + whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(false) + controller.onParentVisible() + + val captor = argumentCaptor<View.OnClickListener>() + verify(privacyChip).setOnClickListener(capture(captor)) + + captor.value.onClick(privacyChip) + verify(privacyDialogController, never()).showDialog(any(Context::class.java)) + } + private fun setPrivacyController(micCamera: Boolean, location: Boolean) { whenever(privacyItemController.micCameraAvailable).thenReturn(micCamera) whenever(privacyItemController.locationAvailable).thenReturn(location) diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt index 3c867ab32725..9f28708a388e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt @@ -64,7 +64,7 @@ class QSPanelControllerTest : SysuiTestCase() { whenever(brightnessSliderFactory.create(any(), any())).thenReturn(brightnessSlider) whenever(brightnessControllerFactory.create(any())).thenReturn(brightnessController) whenever(qsPanel.resources).thenReturn(mContext.orCreateTestableResources.resources) - whenever(statusBarKeyguardViewManager.isBouncerInTransit()).thenReturn(false) + whenever(statusBarKeyguardViewManager.isPrimaryBouncerInTransit()).thenReturn(false) whenever(qsPanel.setListening(anyBoolean())).then { whenever(qsPanel.isListening).thenReturn(it.getArgument(0)) } @@ -116,9 +116,9 @@ class QSPanelControllerTest : SysuiTestCase() { @Test fun testIsBouncerInTransit() { - whenever(statusBarKeyguardViewManager.isBouncerInTransit()).thenReturn(true) + whenever(statusBarKeyguardViewManager.isPrimaryBouncerInTransit()).thenReturn(true) assertThat(controller.isBouncerInTransit()).isEqualTo(true) - whenever(statusBarKeyguardViewManager.isBouncerInTransit()).thenReturn(false) + whenever(statusBarKeyguardViewManager.isPrimaryBouncerInTransit()).thenReturn(false) assertThat(controller.isBouncerInTransit()).isEqualTo(false) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest.java index b067ee76f3b3..f55d262cfc0d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest.java @@ -40,6 +40,8 @@ import com.android.systemui.plugins.qs.QSTile.State; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.InOrder; +import org.mockito.Mockito; @RunWith(AndroidTestingRunner.class) @UiThreadTest @@ -138,7 +140,7 @@ public class QSIconViewImplTest extends SysuiTestCase { } @Test - public void testIconNotAnimatedWhenAllowAnimationsFalse() { + public void testIconStartedAndStoppedWhenAllowAnimationsFalse() { ImageView iv = new ImageView(mContext); AnimatedVectorDrawable d = mock(AnimatedVectorDrawable.class); State s = new State(); @@ -148,7 +150,9 @@ public class QSIconViewImplTest extends SysuiTestCase { mIconView.updateIcon(iv, s, false); - verify(d, never()).start(); + InOrder inOrder = Mockito.inOrder(d); + inOrder.verify(d).start(); + inOrder.verify(d).stop(); } private static Drawable.ConstantState fakeConstantState(Drawable otherDrawable) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QRCodeScannerTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QRCodeScannerTileTest.java index b652aee0f6aa..cac90a14096e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QRCodeScannerTileTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QRCodeScannerTileTest.java @@ -119,6 +119,6 @@ public class QRCodeScannerTileTest extends SysuiTestCase { when(mController.isEnabledForQuickSettings()).thenReturn(true); QSTile.State state = new QSTile.State(); mTile.handleUpdateState(state, null); - assertEquals(state.state, Tile.STATE_ACTIVE); + assertEquals(state.state, Tile.STATE_INACTIVE); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt index bd4b94eef2dd..52462c7186d4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt @@ -311,6 +311,37 @@ class UserTrackerImplTest : SysuiTestCase() { } @Test + fun testCallbackCalledOnUserInfoChanged() { + tracker.initialize(0) + val callback = TestCallback() + tracker.addCallback(callback, executor) + val profileID = tracker.userId + 10 + + `when`(userManager.getProfiles(anyInt())).thenAnswer { invocation -> + val id = invocation.getArgument<Int>(0) + val info = UserInfo(id, "", UserInfo.FLAG_FULL) + val infoProfile = UserInfo( + id + 10, + "", + "", + UserInfo.FLAG_MANAGED_PROFILE, + UserManager.USER_TYPE_PROFILE_MANAGED + ) + infoProfile.profileGroupId = id + listOf(info, infoProfile) + } + + val intent = Intent(Intent.ACTION_USER_INFO_CHANGED) + .putExtra(Intent.EXTRA_USER, UserHandle.of(profileID)) + + tracker.onReceive(context, intent) + + assertThat(callback.calledOnUserChanged).isEqualTo(0) + assertThat(callback.calledOnProfilesChanged).isEqualTo(1) + assertThat(callback.lastUserProfiles.map { it.id }).containsExactly(0, profileID) + } + + @Test fun testCallbackRemoved() { tracker.initialize(0) val newID = 5 diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java index c98c1f2bc97e..1f71e3c64ec4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java @@ -308,7 +308,7 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { MockitoAnnotations.initMocks(this); SystemClock systemClock = new FakeSystemClock(); mStatusBarStateController = new StatusBarStateControllerImpl(mUiEventLogger, mDumpManager, - mInteractionJankMonitor); + mInteractionJankMonitor, mShadeExpansionStateManager); KeyguardStatusView keyguardStatusView = new KeyguardStatusView(mContext); keyguardStatusView.setId(R.id.keyguard_status_view); @@ -379,7 +379,7 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { mDumpManager, mock(HeadsUpManagerPhone.class), new StatusBarStateControllerImpl(new UiEventLoggerFake(), mDumpManager, - mInteractionJankMonitor), + mInteractionJankMonitor, mShadeExpansionStateManager), mKeyguardBypassController, mDozeParameters, mScreenOffAnimationController); @@ -494,7 +494,8 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { systemClock, mock(CameraGestureHelper.class), mKeyguardBottomAreaViewModel, - mKeyguardBottomAreaInteractor); + mKeyguardBottomAreaInteractor, + mDumpManager); mNotificationPanelViewController.initDependencies( mCentralSurfaces, () -> {}, @@ -854,7 +855,7 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD.getId(), null); - verify(mStatusBarKeyguardViewManager).showBouncer(true); + verify(mStatusBarKeyguardViewManager).showPrimaryBouncer(true); } @Test @@ -864,7 +865,7 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_UP.getId(), null); - verify(mStatusBarKeyguardViewManager).showBouncer(true); + verify(mStatusBarKeyguardViewManager).showPrimaryBouncer(true); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java index 95cf9d60b511..d7d17b5132cb 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java @@ -239,9 +239,9 @@ public class NotificationShadeWindowControllerImplTest extends SysuiTestCase { @Test public void setPanelExpanded_notFocusable_altFocusable_whenPanelIsOpen() { - mNotificationShadeWindowController.setPanelExpanded(true); + mNotificationShadeWindowController.onShadeExpansionFullyChanged(true); clearInvocations(mWindowManager); - mNotificationShadeWindowController.setPanelExpanded(true); + mNotificationShadeWindowController.onShadeExpansionFullyChanged(true); verifyNoMoreInteractions(mWindowManager); mNotificationShadeWindowController.setNotificationShadeFocusable(true); @@ -313,7 +313,7 @@ public class NotificationShadeWindowControllerImplTest extends SysuiTestCase { verifyNoMoreInteractions(mWindowManager); clearInvocations(mWindowManager); - mNotificationShadeWindowController.batchApplyWindowLayoutParams(()-> { + mNotificationShadeWindowController.batchApplyWindowLayoutParams(() -> { mNotificationShadeWindowController.setForceDozeBrightness(false); verify(mWindowManager, never()).updateViewLayout(any(), any()); }); 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 a4a7995ae3c8..a6c80ab649e5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java @@ -152,7 +152,7 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase { // WHEN showing alt auth, not dozing, drag down helper doesn't want to intercept when(mStatusBarStateController.isDozing()).thenReturn(false); - when(mStatusBarKeyguardViewManager.isShowingAlternateAuth()).thenReturn(true); + when(mStatusBarKeyguardViewManager.isShowingAlternateBouncer()).thenReturn(true); when(mDragDownHelper.onInterceptTouchEvent(any())).thenReturn(false); // THEN we should intercept touch @@ -165,7 +165,7 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase { // WHEN not showing alt auth, not dozing, drag down helper doesn't want to intercept when(mStatusBarStateController.isDozing()).thenReturn(false); - when(mStatusBarKeyguardViewManager.isShowingAlternateAuth()).thenReturn(false); + when(mStatusBarKeyguardViewManager.isShowingAlternateBouncer()).thenReturn(false); when(mDragDownHelper.onInterceptTouchEvent(any())).thenReturn(false); // THEN we shouldn't intercept touch @@ -178,7 +178,7 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase { // WHEN showing alt auth, not dozing, drag down helper doesn't want to intercept when(mStatusBarStateController.isDozing()).thenReturn(false); - when(mStatusBarKeyguardViewManager.isShowingAlternateAuth()).thenReturn(true); + when(mStatusBarKeyguardViewManager.isShowingAlternateBouncer()).thenReturn(true); when(mDragDownHelper.onInterceptTouchEvent(any())).thenReturn(false); // THEN we should handle the touch diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt index 70cbc64c79f1..28bd26a9094b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt @@ -33,6 +33,7 @@ import com.android.systemui.util.mockito.argumentCaptor import com.android.systemui.util.mockito.eq import junit.framework.Assert.assertEquals import junit.framework.Assert.fail +import org.json.JSONException import org.junit.Before import org.junit.Rule import org.junit.Test @@ -238,4 +239,52 @@ class ClockRegistryTest : SysuiTestCase() { pluginListener.onPluginDisconnected(plugin2) assertEquals(1, changeCallCount) } + + @Test + fun jsonDeserialization_gotExpectedObject() { + val expected = ClockRegistry.ClockSetting("ID", 500) + val actual = ClockRegistry.ClockSetting.deserialize("""{ + "clockId":"ID", + "_applied_timestamp":500 + }""") + assertEquals(expected, actual) + } + + @Test + fun jsonDeserialization_noTimestamp_gotExpectedObject() { + val expected = ClockRegistry.ClockSetting("ID", null) + val actual = ClockRegistry.ClockSetting.deserialize("{\"clockId\":\"ID\"}") + assertEquals(expected, actual) + } + + @Test + fun jsonDeserialization_nullTimestamp_gotExpectedObject() { + val expected = ClockRegistry.ClockSetting("ID", null) + val actual = ClockRegistry.ClockSetting.deserialize("""{ + "clockId":"ID", + "_applied_timestamp":null + }""") + assertEquals(expected, actual) + } + + @Test(expected = JSONException::class) + fun jsonDeserialization_noId_threwException() { + val expected = ClockRegistry.ClockSetting("ID", 500) + val actual = ClockRegistry.ClockSetting.deserialize("{\"_applied_timestamp\":500}") + assertEquals(expected, actual) + } + + @Test + fun jsonSerialization_gotExpectedString() { + val expected = "{\"clockId\":\"ID\",\"_applied_timestamp\":500}" + val actual = ClockRegistry.ClockSetting.serialize( ClockRegistry.ClockSetting("ID", 500)) + assertEquals(expected, actual) + } + + @Test + fun jsonSerialization_noTimestamp_gotExpectedString() { + val expected = "{\"clockId\":\"ID\"}" + val actual = ClockRegistry.ClockSetting.serialize( ClockRegistry.ClockSetting("ID", null)) + assertEquals(expected, actual) + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java index 9a13e93ebcfc..9b17cc296081 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java @@ -20,6 +20,7 @@ import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_DEFAULT; import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_FINANCED; import static android.content.pm.UserInfo.FLAG_MANAGED_PROFILE; import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_TOO_DARK; +import static android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_LOCKOUT_PERMANENT; import static android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_TIMEOUT; import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED; @@ -54,6 +55,7 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import android.app.Instrumentation; @@ -88,6 +90,7 @@ import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.settingslib.fuelgauge.BatteryStatus; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; +import com.android.systemui.biometrics.AuthController; import com.android.systemui.biometrics.FaceHelpMessageDeferral; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dock.DockManager; @@ -173,6 +176,8 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { private FaceHelpMessageDeferral mFaceHelpMessageDeferral; @Mock private ScreenLifecycle mScreenLifecycle; + @Mock + private AuthController mAuthController; @Captor private ArgumentCaptor<DockManager.AlignmentStateListener> mAlignmentListener; @Captor @@ -263,8 +268,9 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { mWakeLockBuilder, mKeyguardStateController, mStatusBarStateController, mKeyguardUpdateMonitor, mDockManager, mBroadcastDispatcher, mDevicePolicyManager, mIBatteryStats, - mUserManager, mExecutor, mExecutor, mFalsingManager, mLockPatternUtils, - mScreenLifecycle, mKeyguardBypassController, mAccessibilityManager, + mUserManager, mExecutor, mExecutor, mFalsingManager, + mAuthController, mLockPatternUtils, mScreenLifecycle, + mKeyguardBypassController, mAccessibilityManager, mFaceHelpMessageDeferral); mController.init(); mController.setIndicationArea(mIndicationArea); @@ -1371,6 +1377,110 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { } + @Test + public void onBiometricError_faceLockedOutFirstTime_showsThePassedInMessage() { + createController(); + onFaceLockoutError("first lockout"); + + verifyIndicationShown(INDICATION_TYPE_BIOMETRIC_MESSAGE, "first lockout"); + } + + @Test + public void onBiometricError_faceLockedOutFirstTimeAndFpAllowed_showsTheFpFollowupMessage() { + createController(); + fingerprintUnlockIsPossible(); + onFaceLockoutError("first lockout"); + + verifyIndicationShown(INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP, + mContext.getString(R.string.keyguard_suggest_fingerprint)); + } + + @Test + public void onBiometricError_faceLockedOutFirstTimeAndFpNotAllowed_showsDefaultFollowup() { + createController(); + fingerprintUnlockIsNotPossible(); + onFaceLockoutError("first lockout"); + + verifyIndicationShown(INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP, + mContext.getString(R.string.keyguard_unlock)); + } + + @Test + public void onBiometricError_faceLockedOutSecondTimeInSession_showsUnavailableMessage() { + createController(); + onFaceLockoutError("first lockout"); + clearInvocations(mRotateTextViewController); + + onFaceLockoutError("second lockout"); + + verifyIndicationShown(INDICATION_TYPE_BIOMETRIC_MESSAGE, + mContext.getString(R.string.keyguard_face_unlock_unavailable)); + } + + @Test + public void onBiometricError_faceLockedOutSecondTimeButUdfpsActive_showsNoMessage() { + createController(); + onFaceLockoutError("first lockout"); + clearInvocations(mRotateTextViewController); + + when(mAuthController.isUdfpsFingerDown()).thenReturn(true); + onFaceLockoutError("second lockout"); + + verifyNoMoreInteractions(mRotateTextViewController); + } + + @Test + public void onBiometricError_faceLockedOutAgainAndFpAllowed_showsTheFpFollowupMessage() { + createController(); + fingerprintUnlockIsPossible(); + onFaceLockoutError("first lockout"); + clearInvocations(mRotateTextViewController); + + onFaceLockoutError("second lockout"); + + verifyIndicationShown(INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP, + mContext.getString(R.string.keyguard_suggest_fingerprint)); + } + + @Test + public void onBiometricError_faceLockedOutAgainAndFpNotAllowed_showsDefaultFollowup() { + createController(); + fingerprintUnlockIsNotPossible(); + onFaceLockoutError("first lockout"); + clearInvocations(mRotateTextViewController); + + onFaceLockoutError("second lockout"); + + verifyIndicationShown(INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP, + mContext.getString(R.string.keyguard_unlock)); + } + + @Test + public void onBiometricError_whenFaceLockoutReset_onLockOutError_showsPassedInMessage() { + createController(); + onFaceLockoutError("first lockout"); + clearInvocations(mRotateTextViewController); + when(mKeyguardUpdateMonitor.isFaceLockedOut()).thenReturn(false); + mKeyguardUpdateMonitorCallback.onLockedOutStateChanged(BiometricSourceType.FACE); + + onFaceLockoutError("second lockout"); + + verifyIndicationShown(INDICATION_TYPE_BIOMETRIC_MESSAGE, "second lockout"); + } + + @Test + public void onBiometricError_whenFaceIsLocked_onMultipleLockOutErrors_showUnavailableMessage() { + createController(); + onFaceLockoutError("first lockout"); + clearInvocations(mRotateTextViewController); + when(mKeyguardUpdateMonitor.isFaceLockedOut()).thenReturn(true); + mKeyguardUpdateMonitorCallback.onLockedOutStateChanged(BiometricSourceType.FACE); + + onFaceLockoutError("second lockout"); + + verifyIndicationShown(INDICATION_TYPE_BIOMETRIC_MESSAGE, + mContext.getString(R.string.keyguard_face_unlock_unavailable)); + } private void sendUpdateDisclosureBroadcast() { mBroadcastReceiver.onReceive(mContext, new Intent()); @@ -1419,4 +1529,33 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { anyObject(), anyBoolean()); } } + + private void verifyIndicationShown(int indicationType, String message) { + verify(mRotateTextViewController) + .updateIndication(eq(indicationType), + mKeyguardIndicationCaptor.capture(), + eq(true)); + assertThat(mKeyguardIndicationCaptor.getValue().getMessage().toString()) + .isEqualTo(message); + } + + private void fingerprintUnlockIsNotPossible() { + setupFingerprintUnlockPossible(false); + } + + private void fingerprintUnlockIsPossible() { + setupFingerprintUnlockPossible(true); + } + + private void setupFingerprintUnlockPossible(boolean possible) { + when(mKeyguardUpdateMonitor + .getCachedIsUnlockWithFingerprintPossible(KeyguardUpdateMonitor.getCurrentUser())) + .thenReturn(possible); + } + + private void onFaceLockoutError(String errMsg) { + mKeyguardUpdateMonitorCallback.onBiometricError(FACE_ERROR_LOCKOUT_PERMANENT, + errMsg, + BiometricSourceType.FACE); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt index 1d8e5dec5c50..5124eb992dc0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt @@ -25,6 +25,7 @@ import com.android.internal.logging.testing.UiEventLoggerFake import com.android.systemui.SysuiTestCase import com.android.systemui.dump.DumpManager import com.android.systemui.plugins.statusbar.StatusBarStateController +import com.android.systemui.shade.ShadeExpansionStateManager import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue @@ -48,6 +49,7 @@ class StatusBarStateControllerImplTest : SysuiTestCase() { @Mock lateinit var interactionJankMonitor: InteractionJankMonitor @Mock private lateinit var mockDarkAnimator: ObjectAnimator + @Mock private lateinit var shadeExpansionStateManager: ShadeExpansionStateManager private lateinit var controller: StatusBarStateControllerImpl private lateinit var uiEventLogger: UiEventLoggerFake @@ -62,7 +64,7 @@ class StatusBarStateControllerImplTest : SysuiTestCase() { controller = object : StatusBarStateControllerImpl( uiEventLogger, mock(DumpManager::class.java), - interactionJankMonitor + interactionJankMonitor, shadeExpansionStateManager ) { override fun createDarkAnimator(): ObjectAnimator { return mockDarkAnimator } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt index f96c39f007dd..aa1114b8736e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt @@ -34,6 +34,7 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.plugga import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender.OnEndLifetimeExtensionCallback +import com.android.systemui.statusbar.notification.collection.provider.LaunchFullScreenIntentProvider import com.android.systemui.statusbar.notification.collection.render.NodeController import com.android.systemui.statusbar.notification.interruption.HeadsUpViewBinder import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider @@ -86,6 +87,7 @@ class HeadsUpCoordinatorTest : SysuiTestCase() { private val mRemoteInputManager: NotificationRemoteInputManager = mock() private val mEndLifetimeExtension: OnEndLifetimeExtensionCallback = mock() private val mHeaderController: NodeController = mock() + private val mLaunchFullScreenIntentProvider: LaunchFullScreenIntentProvider = mock() private lateinit var mEntry: NotificationEntry private lateinit var mGroupSummary: NotificationEntry @@ -110,6 +112,7 @@ class HeadsUpCoordinatorTest : SysuiTestCase() { mHeadsUpViewBinder, mNotificationInterruptStateProvider, mRemoteInputManager, + mLaunchFullScreenIntentProvider, mHeaderController, mExecutor) mCoordinator.attach(mNotifPipeline) @@ -242,6 +245,20 @@ class HeadsUpCoordinatorTest : SysuiTestCase() { } @Test + fun testOnEntryAdded_shouldFullScreen() { + setShouldFullScreen(mEntry) + mCollectionListener.onEntryAdded(mEntry) + verify(mLaunchFullScreenIntentProvider).launchFullScreenIntent(mEntry) + } + + @Test + fun testOnEntryAdded_shouldNotFullScreen() { + setShouldFullScreen(mEntry, should = false) + mCollectionListener.onEntryAdded(mEntry) + verify(mLaunchFullScreenIntentProvider, never()).launchFullScreenIntent(any()) + } + + @Test fun testPromotesAddedHUN() { // GIVEN the current entry should heads up whenever(mNotificationInterruptStateProvider.shouldHeadsUp(mEntry)).thenReturn(true) @@ -794,6 +811,11 @@ class HeadsUpCoordinatorTest : SysuiTestCase() { .thenReturn(should) } + private fun setShouldFullScreen(entry: NotificationEntry, should: Boolean = true) { + whenever(mNotificationInterruptStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry)) + .thenReturn(should) + } + private fun finishBind(entry: NotificationEntry) { verify(mHeadsUpManager, never()).showNotification(entry) withArgCaptor<BindCallback> { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java index b2dc842bc942..7117c233c8c5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java @@ -41,6 +41,7 @@ import com.android.internal.logging.InstanceId; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.statusbar.NotificationVisibility; import com.android.systemui.SysuiTestCase; +import com.android.systemui.shade.ShadeExpansionStateManager; import com.android.systemui.statusbar.NotificationListener; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.StatusBarStateControllerImpl; @@ -88,6 +89,7 @@ public class NotificationLoggerTest extends SysuiTestCase { @Mock private NotificationVisibilityProvider mVisibilityProvider; @Mock private NotifPipeline mNotifPipeline; @Mock private NotificationListener mListener; + @Mock private ShadeExpansionStateManager mShadeExpansionStateManager; private NotificationEntry mEntry; private TestableNotificationLogger mLogger; @@ -118,6 +120,7 @@ public class NotificationLoggerTest extends SysuiTestCase { mVisibilityProvider, mNotifPipeline, mock(StatusBarStateControllerImpl.class), + mShadeExpansionStateManager, mBarService, mExpansionStateLogger ); @@ -152,7 +155,7 @@ public class NotificationLoggerTest extends SysuiTestCase { when(mListContainer.isInVisibleLocation(any())).thenReturn(true); when(mActiveNotifEntries.getValue()).thenReturn(Lists.newArrayList(mEntry)); - mLogger.getChildLocationsChangedListenerForTest().onChildLocationsChanged(); + mLogger.onChildLocationsChanged(); TestableLooper.get(this).processAllMessages(); mUiBgExecutor.runAllReady(); @@ -162,7 +165,7 @@ public class NotificationLoggerTest extends SysuiTestCase { // |mEntry| won't change visibility, so it shouldn't be reported again: Mockito.reset(mBarService); - mLogger.getChildLocationsChangedListenerForTest().onChildLocationsChanged(); + mLogger.onChildLocationsChanged(); TestableLooper.get(this).processAllMessages(); mUiBgExecutor.runAllReady(); @@ -174,7 +177,7 @@ public class NotificationLoggerTest extends SysuiTestCase { throws Exception { when(mListContainer.isInVisibleLocation(any())).thenReturn(true); when(mActiveNotifEntries.getValue()).thenReturn(Lists.newArrayList(mEntry)); - mLogger.getChildLocationsChangedListenerForTest().onChildLocationsChanged(); + mLogger.onChildLocationsChanged(); TestableLooper.get(this).processAllMessages(); mUiBgExecutor.runAllReady(); Mockito.reset(mBarService); @@ -189,13 +192,13 @@ public class NotificationLoggerTest extends SysuiTestCase { } private void setStateAsleep() { - mLogger.onPanelExpandedChanged(true); + mLogger.onShadeExpansionFullyChanged(true); mLogger.onDozingChanged(true); mLogger.onStateChanged(StatusBarState.KEYGUARD); } private void setStateAwake() { - mLogger.onPanelExpandedChanged(false); + mLogger.onShadeExpansionFullyChanged(false); mLogger.onDozingChanged(false); mLogger.onStateChanged(StatusBarState.SHADE); } @@ -221,7 +224,7 @@ public class NotificationLoggerTest extends SysuiTestCase { when(mActiveNotifEntries.getValue()).thenReturn(Lists.newArrayList(mEntry)); setStateAwake(); // Now expand panel - mLogger.onPanelExpandedChanged(true); + mLogger.onShadeExpansionFullyChanged(true); assertEquals(1, mNotificationPanelLoggerFake.getCalls().size()); assertFalse(mNotificationPanelLoggerFake.get(0).isLockscreen); assertEquals(1, mNotificationPanelLoggerFake.get(0).list.notifications.length); @@ -263,6 +266,7 @@ public class NotificationLoggerTest extends SysuiTestCase { NotificationVisibilityProvider visibilityProvider, NotifPipeline notifPipeline, StatusBarStateControllerImpl statusBarStateController, + ShadeExpansionStateManager shadeExpansionStateManager, IStatusBarService barService, ExpansionStateLogger expansionStateLogger) { super( @@ -272,6 +276,7 @@ public class NotificationLoggerTest extends SysuiTestCase { visibilityProvider, notifPipeline, statusBarStateController, + shadeExpansionStateManager, expansionStateLogger, mNotificationPanelLoggerFake ); @@ -280,9 +285,5 @@ public class NotificationLoggerTest extends SysuiTestCase { // Make this on the current thread so we can wait for it during tests. mHandler = Handler.createAsync(Looper.myLooper()); } - - OnChildLocationsChangedListener getChildLocationsChangedListenerForTest() { - return mNotificationLocationsChangedListener; - } } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java index 137842ef314f..12cc11450ede 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java @@ -232,7 +232,6 @@ public class ExpandableNotificationRowTest extends SysuiTestCase { @Test public void testUserLockedResetEvenWhenNoChildren() { mGroupRow.setUserLocked(true); - mGroupRow.removeAllChildren(); mGroupRow.setUserLocked(false); assertFalse("The childrencontainer should not be userlocked but is, the state " + "seems out of sync.", mGroupRow.getChildrenContainer().isUserLocked()); @@ -240,12 +239,11 @@ public class ExpandableNotificationRowTest extends SysuiTestCase { @Test public void testReinflatedOnDensityChange() { - mGroupRow.setUserLocked(true); - mGroupRow.removeAllChildren(); - mGroupRow.setUserLocked(false); NotificationChildrenContainer mockContainer = mock(NotificationChildrenContainer.class); - mGroupRow.setChildrenContainer(mockContainer); - mGroupRow.onDensityOrFontScaleChanged(); + mNotifRow.setChildrenContainer(mockContainer); + + mNotifRow.onDensityOrFontScaleChanged(); + verify(mockContainer).reInflateViews(any(), any()); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java index 7478e4c1f878..ab4ae6a9216b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java @@ -56,6 +56,7 @@ import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.media.controls.util.MediaFeatureFlag; import com.android.systemui.media.dialog.MediaOutputDialogFactory; import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.shade.ShadeExpansionStateManager; import com.android.systemui.statusbar.NotificationMediaManager; import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.NotificationShadeWindowController; @@ -151,7 +152,8 @@ public class NotificationTestHelper { mock(ConfigurationControllerImpl.class), new Handler(mTestLooper.getLooper()), mock(AccessibilityManagerWrapper.class), - mock(UiEventLogger.class) + mock(UiEventLogger.class), + mock(ShadeExpansionStateManager.class) ); mHeadsUpManager.mHandler.removeCallbacksAndMessages(null); mHeadsUpManager.mHandler = new Handler(mTestLooper.getLooper()); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt index 40aec82f5a85..743e7d69cfc0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt @@ -118,7 +118,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() { @Test fun resetViewStates_expansionChanging_notificationBecomesTransparent() { - whenever(mStatusBarKeyguardViewManager.isBouncerInTransit).thenReturn(false) + whenever(mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit).thenReturn(false) resetViewStates_expansionChanging_notificationAlphaUpdated( expansionFraction = 0.25f, expectedAlpha = 0.0f @@ -127,7 +127,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() { @Test fun resetViewStates_expansionChangingWhileBouncerInTransit_viewBecomesTransparent() { - whenever(mStatusBarKeyguardViewManager.isBouncerInTransit).thenReturn(true) + whenever(mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit).thenReturn(true) resetViewStates_expansionChanging_notificationAlphaUpdated( expansionFraction = 0.85f, expectedAlpha = 0.0f @@ -136,7 +136,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() { @Test fun resetViewStates_expansionChanging_notificationAlphaUpdated() { - whenever(mStatusBarKeyguardViewManager.isBouncerInTransit).thenReturn(false) + whenever(mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit).thenReturn(false) resetViewStates_expansionChanging_notificationAlphaUpdated( expansionFraction = 0.6f, expectedAlpha = getContentAlpha(0.6f) @@ -145,7 +145,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() { @Test fun resetViewStates_expansionChangingWhileBouncerInTransit_notificationAlphaUpdated() { - whenever(mStatusBarKeyguardViewManager.isBouncerInTransit).thenReturn(true) + whenever(mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit).thenReturn(true) resetViewStates_expansionChanging_notificationAlphaUpdated( expansionFraction = 0.95f, expectedAlpha = aboutToShowBouncerProgress(0.95f) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java index b17747ad2d92..75a3b21724ef 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java @@ -147,24 +147,24 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase { } @Test - public void onBiometricAuthenticated_whenFingerprintAndBiometricsDisallowed_showBouncer() { + public void onBiometricAuthenticated_fingerprintAndBiometricsDisallowed_showPrimaryBouncer() { when(mUpdateMonitor.isUnlockingWithBiometricAllowed(true /* isStrongBiometric */)) .thenReturn(false); mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT, BiometricSourceType.FINGERPRINT, true /* isStrongBiometric */); - verify(mStatusBarKeyguardViewManager).showBouncer(anyBoolean()); + verify(mStatusBarKeyguardViewManager).showPrimaryBouncer(anyBoolean()); verify(mStatusBarKeyguardViewManager, never()).notifyKeyguardAuthenticated(anyBoolean()); assertThat(mBiometricUnlockController.getMode()) .isEqualTo(BiometricUnlockController.MODE_SHOW_BOUNCER); } @Test - public void onBiometricAuthenticated_whenFingerprint_nonStrongBioDisallowed_showBouncer() { + public void onBiometricAuthenticated_fingerprint_nonStrongBioDisallowed_showPrimaryBouncer() { when(mUpdateMonitor.isUnlockingWithBiometricAllowed(false /* isStrongBiometric */)) .thenReturn(false); mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT, BiometricSourceType.FINGERPRINT, false /* isStrongBiometric */); - verify(mStatusBarKeyguardViewManager).showBouncer(anyBoolean()); + verify(mStatusBarKeyguardViewManager).showPrimaryBouncer(anyBoolean()); assertThat(mBiometricUnlockController.getMode()) .isEqualTo(BiometricUnlockController.MODE_SHOW_BOUNCER); assertThat(mBiometricUnlockController.getBiometricType()) @@ -214,7 +214,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase { mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT, BiometricSourceType.FINGERPRINT, true /* isStrongBiometric */); - verify(mStatusBarKeyguardViewManager, never()).showBouncer(anyBoolean()); + verify(mStatusBarKeyguardViewManager, never()).showPrimaryBouncer(anyBoolean()); verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(eq(false)); assertThat(mBiometricUnlockController.getMode()) .isEqualTo(BiometricUnlockController.MODE_UNLOCK_COLLAPSING); @@ -223,7 +223,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase { @Test public void onBiometricAuthenticated_whenFingerprintOnBouncer_dismissBouncer() { when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true); - when(mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing()).thenReturn(true); + when(mStatusBarKeyguardViewManager.primaryBouncerIsOrWillBeShowing()).thenReturn(true); // the value of isStrongBiometric doesn't matter here since we only care about the returned // value of isUnlockingWithBiometricAllowed() mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT, @@ -283,7 +283,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase { } @Test - public void onBiometricAuthenticated_whenFace_andBypass_encrypted_showBouncer() { + public void onBiometricAuthenticated_whenFace_andBypass_encrypted_showPrimaryBouncer() { reset(mUpdateMonitor); when(mKeyguardBypassController.getBypassEnabled()).thenReturn(true); mBiometricUnlockController.setKeyguardViewController(mStatusBarKeyguardViewManager); @@ -294,7 +294,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase { mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT, BiometricSourceType.FACE, true /* isStrongBiometric */); - verify(mStatusBarKeyguardViewManager).showBouncer(anyBoolean()); + verify(mStatusBarKeyguardViewManager).showPrimaryBouncer(anyBoolean()); assertThat(mBiometricUnlockController.getMode()) .isEqualTo(BiometricUnlockController.MODE_SHOW_BOUNCER); } @@ -330,7 +330,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase { mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT, BiometricSourceType.FACE, true /* isStrongBiometric */); - verify(mStatusBarKeyguardViewManager, never()).showBouncer(anyBoolean()); + verify(mStatusBarKeyguardViewManager, never()).showPrimaryBouncer(anyBoolean()); verify(mShadeController, never()).animateCollapsePanels(anyInt(), anyBoolean(), anyBoolean(), anyFloat()); assertThat(mBiometricUnlockController.getMode()) @@ -340,7 +340,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase { @Test public void onBiometricAuthenticated_whenFaceOnBouncer_dismissBouncer() { when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true); - when(mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing()).thenReturn(true); + when(mStatusBarKeyguardViewManager.primaryBouncerIsOrWillBeShowing()).thenReturn(true); // the value of isStrongBiometric doesn't matter here since we only care about the returned // value of isUnlockingWithBiometricAllowed() mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT, @@ -360,7 +360,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase { when(mKeyguardBypassController.getBypassEnabled()).thenReturn(true); when(mKeyguardBypassController.onBiometricAuthenticated(any(), anyBoolean())) .thenReturn(true); - when(mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing()).thenReturn(true); + when(mStatusBarKeyguardViewManager.primaryBouncerIsOrWillBeShowing()).thenReturn(true); // the value of isStrongBiometric doesn't matter here since we only care about the returned // value of isUnlockingWithBiometricAllowed() mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT, @@ -389,23 +389,23 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase { } @Test - public void onUdfpsConsecutivelyFailedThreeTimes_showBouncer() { + public void onUdfpsConsecutivelyFailedThreeTimes_showPrimaryBouncer() { // GIVEN UDFPS is supported when(mUpdateMonitor.isUdfpsSupported()).thenReturn(true); // WHEN udfps fails once - then don't show the bouncer yet mBiometricUnlockController.onBiometricAuthFailed(BiometricSourceType.FINGERPRINT); - verify(mStatusBarKeyguardViewManager, never()).showBouncer(anyBoolean()); + verify(mStatusBarKeyguardViewManager, never()).showPrimaryBouncer(anyBoolean()); // WHEN udfps fails the second time - then don't show the bouncer yet mBiometricUnlockController.onBiometricAuthFailed(BiometricSourceType.FINGERPRINT); - verify(mStatusBarKeyguardViewManager, never()).showBouncer(anyBoolean()); + verify(mStatusBarKeyguardViewManager, never()).showPrimaryBouncer(anyBoolean()); // WHEN udpfs fails the third time mBiometricUnlockController.onBiometricAuthFailed(BiometricSourceType.FINGERPRINT); // THEN show the bouncer - verify(mStatusBarKeyguardViewManager).showBouncer(true); + verify(mStatusBarKeyguardViewManager).showPrimaryBouncer(true); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java index 7ce3a67ce835..5ad1431cc8d8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java @@ -220,6 +220,7 @@ public class CentralSurfacesImplTest extends SysuiTestCase { @Mock private NotificationLockscreenUserManager mLockscreenUserManager; @Mock private NotificationRemoteInputManager mRemoteInputManager; @Mock private StatusBarStateControllerImpl mStatusBarStateController; + @Mock private ShadeExpansionStateManager mShadeExpansionStateManager; @Mock private BatteryController mBatteryController; @Mock private DeviceProvisionedController mDeviceProvisionedController; @Mock private StatusBarNotificationPresenter mNotificationPresenter; @@ -339,6 +340,7 @@ public class CentralSurfacesImplTest extends SysuiTestCase { mVisibilityProvider, mock(NotifPipeline.class), mStatusBarStateController, + mShadeExpansionStateManager, mExpansionStateLogger, new NotificationPanelLoggerFake() ); @@ -1025,7 +1027,7 @@ public class CentralSurfacesImplTest extends SysuiTestCase { @Test public void collapseShade_callsAnimateCollapsePanels_whenExpanded() { // GIVEN the shade is expanded - mCentralSurfaces.setPanelExpanded(true); + mCentralSurfaces.onShadeExpansionFullyChanged(true); mCentralSurfaces.setBarStateForTest(StatusBarState.SHADE); // WHEN collapseShade is called @@ -1038,7 +1040,7 @@ public class CentralSurfacesImplTest extends SysuiTestCase { @Test public void collapseShade_doesNotCallAnimateCollapsePanels_whenCollapsed() { // GIVEN the shade is collapsed - mCentralSurfaces.setPanelExpanded(false); + mCentralSurfaces.onShadeExpansionFullyChanged(false); mCentralSurfaces.setBarStateForTest(StatusBarState.SHADE); // WHEN collapseShade is called @@ -1051,7 +1053,7 @@ public class CentralSurfacesImplTest extends SysuiTestCase { @Test public void collapseShadeForBugReport_callsAnimateCollapsePanels_whenFlagDisabled() { // GIVEN the shade is expanded & flag enabled - mCentralSurfaces.setPanelExpanded(true); + mCentralSurfaces.onShadeExpansionFullyChanged(true); mCentralSurfaces.setBarStateForTest(StatusBarState.SHADE); mFeatureFlags.set(Flags.LEAVE_SHADE_OPEN_FOR_BUGREPORT, false); @@ -1065,7 +1067,7 @@ public class CentralSurfacesImplTest extends SysuiTestCase { @Test public void collapseShadeForBugReport_doesNotCallAnimateCollapsePanels_whenFlagEnabled() { // GIVEN the shade is expanded & flag enabled - mCentralSurfaces.setPanelExpanded(true); + mCentralSurfaces.onShadeExpansionFullyChanged(true); mCentralSurfaces.setBarStateForTest(StatusBarState.SHADE); mFeatureFlags.set(Flags.LEAVE_SHADE_OPEN_FOR_BUGREPORT, true); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java index e252401d328c..780e0c56a239 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java @@ -31,6 +31,7 @@ import androidx.test.filters.SmallTest; import com.android.internal.logging.UiEventLogger; import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.shade.ShadeExpansionStateManager; import com.android.systemui.statusbar.AlertingNotificationManager; import com.android.systemui.statusbar.AlertingNotificationManagerTest; import com.android.systemui.statusbar.NotificationShadeWindowController; @@ -67,6 +68,7 @@ public class HeadsUpManagerPhoneTest extends AlertingNotificationManagerTest { @Mock private KeyguardBypassController mBypassController; @Mock private ConfigurationControllerImpl mConfigurationController; @Mock private AccessibilityManagerWrapper mAccessibilityManagerWrapper; + @Mock private ShadeExpansionStateManager mShadeExpansionStateManager; @Mock private UiEventLogger mUiEventLogger; private boolean mLivesPastNormalTime; @@ -81,7 +83,8 @@ public class HeadsUpManagerPhoneTest extends AlertingNotificationManagerTest { ConfigurationController configurationController, Handler handler, AccessibilityManagerWrapper accessibilityManagerWrapper, - UiEventLogger uiEventLogger + UiEventLogger uiEventLogger, + ShadeExpansionStateManager shadeExpansionStateManager ) { super( context, @@ -93,7 +96,8 @@ public class HeadsUpManagerPhoneTest extends AlertingNotificationManagerTest { configurationController, handler, accessibilityManagerWrapper, - uiEventLogger + uiEventLogger, + shadeExpansionStateManager ); mMinimumDisplayTime = TEST_MINIMUM_DISPLAY_TIME; mAutoDismissNotificationDecay = TEST_AUTO_DISMISS_TIME; @@ -125,7 +129,8 @@ public class HeadsUpManagerPhoneTest extends AlertingNotificationManagerTest { mConfigurationController, mTestHandler, mAccessibilityManagerWrapper, - mUiEventLogger + mUiEventLogger, + mShadeExpansionStateManager ); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java index ab209d130b2f..d3b541899635 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java @@ -58,7 +58,7 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.keyguard.DismissCallbackRegistry; import com.android.systemui.plugins.ActivityStarter.OnDismissAction; -import com.android.systemui.statusbar.phone.KeyguardBouncer.BouncerExpansionCallback; +import com.android.systemui.statusbar.phone.KeyguardBouncer.PrimaryBouncerExpansionCallback; import com.android.systemui.statusbar.policy.KeyguardStateController; import org.junit.Assert; @@ -86,7 +86,7 @@ public class KeyguardBouncerTest extends SysuiTestCase { @Mock private KeyguardHostViewController mKeyguardHostViewController; @Mock - private BouncerExpansionCallback mExpansionCallback; + private KeyguardBouncer.PrimaryBouncerExpansionCallback mExpansionCallback; @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor; @Mock @@ -476,7 +476,8 @@ public class KeyguardBouncerTest extends SysuiTestCase { mBouncer.ensureView(); mBouncer.setExpansion(0.5f); - final BouncerExpansionCallback callback = mock(BouncerExpansionCallback.class); + final PrimaryBouncerExpansionCallback callback = + mock(PrimaryBouncerExpansionCallback.class); mBouncer.addBouncerExpansionCallback(callback); mBouncer.setExpansion(EXPANSION_HIDDEN); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt index 086e5df50f3f..b80b825d87dc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt @@ -92,7 +92,7 @@ class NotificationIconContainerTest : SysuiTestCase() { iconContainer.calculateIconXTranslations() assertEquals(10f, iconState.xTranslation) - assertFalse(iconContainer.hasOverflow()) + assertFalse(iconContainer.areIconsOverflowing()) } @Test @@ -121,7 +121,7 @@ class NotificationIconContainerTest : SysuiTestCase() { assertEquals(30f, iconContainer.getIconState(iconThree).xTranslation) assertEquals(40f, iconContainer.getIconState(iconFour).xTranslation) - assertFalse(iconContainer.hasOverflow()) + assertFalse(iconContainer.areIconsOverflowing()) } @Test @@ -150,7 +150,7 @@ class NotificationIconContainerTest : SysuiTestCase() { assertEquals(10f, iconContainer.getIconState(iconOne).xTranslation) assertEquals(20f, iconContainer.getIconState(iconTwo).xTranslation) assertEquals(30f, iconContainer.getIconState(iconThree).xTranslation) - assertTrue(iconContainer.hasOverflow()) + assertTrue(iconContainer.areIconsOverflowing()) } @Test 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 a5deaa45bf0f..df48e1d43584 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 @@ -1150,7 +1150,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test - public void testAuthScrim_notifScrimOpaque_whenShadeFullyExpanded() { + public void testAuthScrim_setClipQSScrimTrue_notifScrimOpaque_whenShadeFullyExpanded() { // GIVEN device has an activity showing ('UNLOCKED' state can occur on the lock screen // with the camera app occluding the keyguard) mScrimController.transitionTo(ScrimState.UNLOCKED); @@ -1176,6 +1176,34 @@ public class ScrimControllerTest extends SysuiTestCase { )); } + + @Test + public void testAuthScrim_setClipQSScrimFalse_notifScrimOpaque_whenShadeFullyExpanded() { + // GIVEN device has an activity showing ('UNLOCKED' state can occur on the lock screen + // with the camera app occluding the keyguard) + mScrimController.transitionTo(ScrimState.UNLOCKED); + mScrimController.setClipsQsScrim(false); + mScrimController.setRawPanelExpansionFraction(1); + // notifications scrim alpha change require calling setQsPosition + mScrimController.setQsPosition(0, 300); + finishAnimationsImmediately(); + + // WHEN the user triggers the auth bouncer + mScrimController.transitionTo(ScrimState.AUTH_SCRIMMED_SHADE); + finishAnimationsImmediately(); + + assertEquals("Behind scrim should be opaque", + mScrimBehind.getViewAlpha(), 1, 0.0); + assertEquals("Notifications scrim should be opaque", + mNotificationsScrim.getViewAlpha(), 1, 0.0); + + assertScrimTinted(Map.of( + mScrimInFront, true, + mScrimBehind, true, + mNotificationsScrim, false + )); + } + @Test public void testAuthScrimKeyguard() { // GIVEN device is on the keyguard @@ -1280,7 +1308,7 @@ public class ScrimControllerTest extends SysuiTestCase { @Test public void qsExpansion_BehindTint_shadeLocked_bouncerActive_usesBouncerProgress() { - when(mStatusBarKeyguardViewManager.isBouncerInTransit()).thenReturn(true); + when(mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit()).thenReturn(true); // clipping doesn't change tested logic but allows to assert scrims more in line with // their expected large screen behaviour mScrimController.setClipsQsScrim(false); @@ -1296,7 +1324,7 @@ public class ScrimControllerTest extends SysuiTestCase { @Test public void expansionNotificationAlpha_shadeLocked_bouncerActive_usesBouncerInterpolator() { - when(mStatusBarKeyguardViewManager.isBouncerInTransit()).thenReturn(true); + when(mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit()).thenReturn(true); mScrimController.transitionTo(SHADE_LOCKED); @@ -1312,7 +1340,7 @@ public class ScrimControllerTest extends SysuiTestCase { @Test public void expansionNotificationAlpha_shadeLocked_bouncerNotActive_usesShadeInterpolator() { - when(mStatusBarKeyguardViewManager.isBouncerInTransit()).thenReturn(false); + when(mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit()).thenReturn(false); mScrimController.transitionTo(SHADE_LOCKED); @@ -1327,7 +1355,7 @@ public class ScrimControllerTest extends SysuiTestCase { @Test public void notificationAlpha_unnocclusionAnimating_bouncerActive_usesKeyguardNotifAlpha() { - when(mStatusBarKeyguardViewManager.isBouncerInTransit()).thenReturn(true); + when(mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit()).thenReturn(true); mScrimController.setClipsQsScrim(true); mScrimController.transitionTo(ScrimState.KEYGUARD); @@ -1349,7 +1377,7 @@ public class ScrimControllerTest extends SysuiTestCase { @Test public void notificationAlpha_unnocclusionAnimating_bouncerNotActive_usesKeyguardNotifAlpha() { - when(mStatusBarKeyguardViewManager.isBouncerInTransit()).thenReturn(false); + when(mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit()).thenReturn(false); mScrimController.transitionTo(ScrimState.KEYGUARD); mScrimController.setUnocclusionAnimationRunning(true); @@ -1370,7 +1398,7 @@ public class ScrimControllerTest extends SysuiTestCase { @Test public void notificationAlpha_inKeyguardState_bouncerActive_usesInvertedBouncerInterpolator() { - when(mStatusBarKeyguardViewManager.isBouncerInTransit()).thenReturn(true); + when(mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit()).thenReturn(true); mScrimController.setClipsQsScrim(true); mScrimController.transitionTo(ScrimState.KEYGUARD); @@ -1390,7 +1418,7 @@ public class ScrimControllerTest extends SysuiTestCase { @Test public void notificationAlpha_inKeyguardState_bouncerNotActive_usesInvertedShadeInterpolator() { - when(mStatusBarKeyguardViewManager.isBouncerInTransit()).thenReturn(false); + when(mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit()).thenReturn(false); mScrimController.setClipsQsScrim(true); mScrimController.transitionTo(ScrimState.KEYGUARD); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java index 9c56c2670c63..6fb68938b00d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java @@ -45,7 +45,7 @@ import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconStat import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState; import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags; import com.android.systemui.statusbar.pipeline.mobile.ui.MobileUiAdapter; -import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.WifiViewModel; +import com.android.systemui.statusbar.pipeline.wifi.ui.WifiUiAdapter; import com.android.systemui.utils.leaks.LeakCheckedTest; import org.junit.Before; @@ -80,7 +80,7 @@ public class StatusBarIconControllerTest extends LeakCheckedTest { layout, StatusBarLocation.HOME, mock(StatusBarPipelineFlags.class), - mock(WifiViewModel.class), + mock(WifiUiAdapter.class), mock(MobileUiAdapter.class), mMobileContextProvider, mock(DarkIconDispatcher.class)); @@ -124,14 +124,14 @@ public class StatusBarIconControllerTest extends LeakCheckedTest { LinearLayout group, StatusBarLocation location, StatusBarPipelineFlags statusBarPipelineFlags, - WifiViewModel wifiViewModel, + WifiUiAdapter wifiUiAdapter, MobileUiAdapter mobileUiAdapter, MobileContextProvider contextProvider, DarkIconDispatcher darkIconDispatcher) { super(group, location, statusBarPipelineFlags, - wifiViewModel, + wifiUiAdapter, mobileUiAdapter, contextProvider, darkIconDispatcher); @@ -172,7 +172,7 @@ public class StatusBarIconControllerTest extends LeakCheckedTest { super(group, StatusBarLocation.HOME, mock(StatusBarPipelineFlags.class), - mock(WifiViewModel.class), + mock(WifiUiAdapter.class), mock(MobileUiAdapter.class), contextProvider); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java index 716666657871..49c3a2128bd7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java @@ -56,8 +56,8 @@ import com.android.systemui.dreams.DreamOverlayStateController; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.keyguard.data.BouncerView; import com.android.systemui.keyguard.data.BouncerViewDelegate; -import com.android.systemui.keyguard.domain.interactor.BouncerCallbackInteractor; -import com.android.systemui.keyguard.domain.interactor.BouncerInteractor; +import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor; +import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor; import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.plugins.ActivityStarter.OnDismissAction; import com.android.systemui.shade.NotificationPanelViewController; @@ -105,8 +105,8 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { @Mock private KeyguardBouncer.Factory mKeyguardBouncerFactory; @Mock private KeyguardMessageAreaController.Factory mKeyguardMessageAreaFactory; @Mock private KeyguardMessageAreaController mKeyguardMessageAreaController; - @Mock private KeyguardBouncer mBouncer; - @Mock private StatusBarKeyguardViewManager.AlternateAuthInterceptor mAlternateAuthInterceptor; + @Mock private KeyguardBouncer mPrimaryBouncer; + @Mock private StatusBarKeyguardViewManager.AlternateBouncer mAlternateBouncer; @Mock private KeyguardMessageArea mKeyguardMessageArea; @Mock private ShadeController mShadeController; @Mock private SysUIUnfoldComponent mSysUiUnfoldComponent; @@ -114,13 +114,13 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { @Mock private LatencyTracker mLatencyTracker; @Mock private FeatureFlags mFeatureFlags; @Mock private KeyguardSecurityModel mKeyguardSecurityModel; - @Mock private BouncerCallbackInteractor mBouncerCallbackInteractor; - @Mock private BouncerInteractor mBouncerInteractor; + @Mock private PrimaryBouncerCallbackInteractor mPrimaryBouncerCallbackInteractor; + @Mock private PrimaryBouncerInteractor mPrimaryBouncerInteractor; @Mock private BouncerView mBouncerView; @Mock private BouncerViewDelegate mBouncerViewDelegate; private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; - private KeyguardBouncer.BouncerExpansionCallback mBouncerExpansionCallback; + private KeyguardBouncer.PrimaryBouncerExpansionCallback mBouncerExpansionCallback; private FakeKeyguardStateController mKeyguardStateController = spy(new FakeKeyguardStateController()); @@ -134,8 +134,9 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { public void setUp() { MockitoAnnotations.initMocks(this); when(mKeyguardBouncerFactory.create( - any(ViewGroup.class), any(KeyguardBouncer.BouncerExpansionCallback.class))) - .thenReturn(mBouncer); + any(ViewGroup.class), + any(KeyguardBouncer.PrimaryBouncerExpansionCallback.class))) + .thenReturn(mPrimaryBouncer); when(mCentralSurfaces.getBouncerContainer()).thenReturn(mContainer); when(mContainer.findViewById(anyInt())).thenReturn(mKeyguardMessageArea); when(mKeyguardMessageAreaFactory.create(any(KeyguardMessageArea.class))) @@ -163,8 +164,8 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { mLatencyTracker, mKeyguardSecurityModel, mFeatureFlags, - mBouncerCallbackInteractor, - mBouncerInteractor, + mPrimaryBouncerCallbackInteractor, + mPrimaryBouncerInteractor, mBouncerView) { @Override public ViewRootImpl getViewRootImpl() { @@ -181,8 +182,8 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { mNotificationContainer, mBypassController); mStatusBarKeyguardViewManager.show(null); - ArgumentCaptor<KeyguardBouncer.BouncerExpansionCallback> callbackArgumentCaptor = - ArgumentCaptor.forClass(KeyguardBouncer.BouncerExpansionCallback.class); + ArgumentCaptor<KeyguardBouncer.PrimaryBouncerExpansionCallback> callbackArgumentCaptor = + ArgumentCaptor.forClass(KeyguardBouncer.PrimaryBouncerExpansionCallback.class); verify(mKeyguardBouncerFactory).create(any(ViewGroup.class), callbackArgumentCaptor.capture()); mBouncerExpansionCallback = callbackArgumentCaptor.getValue(); @@ -194,86 +195,86 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { Runnable cancelAction = () -> {}; mStatusBarKeyguardViewManager.dismissWithAction( action, cancelAction, false /* afterKeyguardGone */); - verify(mBouncer).showWithDismissAction(eq(action), eq(cancelAction)); + verify(mPrimaryBouncer).showWithDismissAction(eq(action), eq(cancelAction)); } @Test public void showBouncer_onlyWhenShowing() { mStatusBarKeyguardViewManager.hide(0 /* startTime */, 0 /* fadeoutDuration */); - mStatusBarKeyguardViewManager.showBouncer(true /* scrimmed */); - verify(mBouncer, never()).show(anyBoolean(), anyBoolean()); - verify(mBouncer, never()).show(anyBoolean()); + mStatusBarKeyguardViewManager.showPrimaryBouncer(true /* scrimmed */); + verify(mPrimaryBouncer, never()).show(anyBoolean(), anyBoolean()); + verify(mPrimaryBouncer, never()).show(anyBoolean()); } @Test public void showBouncer_notWhenBouncerAlreadyShowing() { mStatusBarKeyguardViewManager.hide(0 /* startTime */, 0 /* fadeoutDuration */); - when(mBouncer.isSecure()).thenReturn(true); - mStatusBarKeyguardViewManager.showBouncer(true /* scrimmed */); - verify(mBouncer, never()).show(anyBoolean(), anyBoolean()); - verify(mBouncer, never()).show(anyBoolean()); + when(mPrimaryBouncer.isSecure()).thenReturn(true); + mStatusBarKeyguardViewManager.showPrimaryBouncer(true /* scrimmed */); + verify(mPrimaryBouncer, never()).show(anyBoolean(), anyBoolean()); + verify(mPrimaryBouncer, never()).show(anyBoolean()); } @Test public void showBouncer_showsTheBouncer() { - mStatusBarKeyguardViewManager.showBouncer(true /* scrimmed */); - verify(mBouncer).show(anyBoolean(), eq(true)); + mStatusBarKeyguardViewManager.showPrimaryBouncer(true /* scrimmed */); + verify(mPrimaryBouncer).show(anyBoolean(), eq(true)); } @Test public void onPanelExpansionChanged_neverHidesScrimmedBouncer() { - when(mBouncer.isShowing()).thenReturn(true); - when(mBouncer.isScrimmed()).thenReturn(true); + when(mPrimaryBouncer.isShowing()).thenReturn(true); + when(mPrimaryBouncer.isScrimmed()).thenReturn(true); mStatusBarKeyguardViewManager.onPanelExpansionChanged(EXPANSION_EVENT); - verify(mBouncer).setExpansion(eq(KeyguardBouncer.EXPANSION_VISIBLE)); + verify(mPrimaryBouncer).setExpansion(eq(KeyguardBouncer.EXPANSION_VISIBLE)); } @Test public void onPanelExpansionChanged_neverShowsDuringHintAnimation() { when(mNotificationPanelView.isUnlockHintRunning()).thenReturn(true); mStatusBarKeyguardViewManager.onPanelExpansionChanged(EXPANSION_EVENT); - verify(mBouncer).setExpansion(eq(KeyguardBouncer.EXPANSION_HIDDEN)); + verify(mPrimaryBouncer).setExpansion(eq(KeyguardBouncer.EXPANSION_HIDDEN)); } @Test public void onPanelExpansionChanged_propagatesToBouncer() { mStatusBarKeyguardViewManager.onPanelExpansionChanged(EXPANSION_EVENT); - verify(mBouncer).setExpansion(eq(0.5f)); + verify(mPrimaryBouncer).setExpansion(eq(0.5f)); } @Test public void onPanelExpansionChanged_hideBouncer_afterKeyguardHidden() { mStatusBarKeyguardViewManager.hide(0, 0); - when(mBouncer.inTransit()).thenReturn(true); + when(mPrimaryBouncer.inTransit()).thenReturn(true); mStatusBarKeyguardViewManager.onPanelExpansionChanged(EXPANSION_EVENT); - verify(mBouncer).setExpansion(eq(KeyguardBouncer.EXPANSION_HIDDEN)); + verify(mPrimaryBouncer).setExpansion(eq(KeyguardBouncer.EXPANSION_HIDDEN)); } @Test public void onPanelExpansionChanged_showsBouncerWhenSwiping() { mKeyguardStateController.setCanDismissLockScreen(false); mStatusBarKeyguardViewManager.onPanelExpansionChanged(EXPANSION_EVENT); - verify(mBouncer).show(eq(false), eq(false)); + verify(mPrimaryBouncer).show(eq(false), eq(false)); // But not when it's already visible - reset(mBouncer); - when(mBouncer.isShowing()).thenReturn(true); + reset(mPrimaryBouncer); + when(mPrimaryBouncer.isShowing()).thenReturn(true); mStatusBarKeyguardViewManager.onPanelExpansionChanged(EXPANSION_EVENT); - verify(mBouncer, never()).show(eq(false), eq(false)); + verify(mPrimaryBouncer, never()).show(eq(false), eq(false)); // Or animating away - reset(mBouncer); - when(mBouncer.isAnimatingAway()).thenReturn(true); + reset(mPrimaryBouncer); + when(mPrimaryBouncer.isAnimatingAway()).thenReturn(true); mStatusBarKeyguardViewManager.onPanelExpansionChanged(EXPANSION_EVENT); - verify(mBouncer, never()).show(eq(false), eq(false)); + verify(mPrimaryBouncer, never()).show(eq(false), eq(false)); } @Test public void onPanelExpansionChanged_neverTranslatesBouncerWhenOccluded() { mStatusBarKeyguardViewManager.setOccluded(true /* occluded */, false /* animate */); mStatusBarKeyguardViewManager.onPanelExpansionChanged(EXPANSION_EVENT); - verify(mBouncer, never()).setExpansion(eq(0.5f)); + verify(mPrimaryBouncer, never()).setExpansion(eq(0.5f)); } @Test @@ -285,7 +286,7 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { /* fraction= */ KeyguardBouncer.EXPANSION_VISIBLE, /* expanded= */ true, /* tracking= */ false)); - verify(mBouncer, never()).setExpansion(anyFloat()); + verify(mPrimaryBouncer, never()).setExpansion(anyFloat()); } @Test @@ -302,18 +303,7 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { /* fraction= */ KeyguardBouncer.EXPANSION_VISIBLE, /* expanded= */ true, /* tracking= */ false)); - verify(mBouncer, never()).setExpansion(anyFloat()); - } - - @Test - public void onPanelExpansionChanged_neverTranslatesBouncerWhenLaunchingApp() { - when(mNotificationPanelView.isLaunchTransitionFinished()).thenReturn(true); - mStatusBarKeyguardViewManager.onPanelExpansionChanged( - expansionEvent( - /* fraction= */ KeyguardBouncer.EXPANSION_VISIBLE, - /* expanded= */ true, - /* tracking= */ false)); - verify(mBouncer, never()).setExpansion(anyFloat()); + verify(mPrimaryBouncer, never()).setExpansion(anyFloat()); } @Test @@ -324,7 +314,7 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { /* fraction= */ KeyguardBouncer.EXPANSION_VISIBLE, /* expanded= */ true, /* tracking= */ false)); - verify(mBouncer, never()).setExpansion(anyFloat()); + verify(mPrimaryBouncer, never()).setExpansion(anyFloat()); } @Test @@ -332,7 +322,7 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { mStatusBarKeyguardViewManager.setOccluded(false /* occluded */, true /* animated */); verify(mCentralSurfaces).animateKeyguardUnoccluding(); - when(mBouncer.isShowing()).thenReturn(true); + when(mPrimaryBouncer.isShowing()).thenReturn(true); clearInvocations(mCentralSurfaces); mStatusBarKeyguardViewManager.setOccluded(false /* occluded */, true /* animated */); verify(mCentralSurfaces, never()).animateKeyguardUnoccluding(); @@ -361,7 +351,6 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { @Test public void setOccluded_isInLaunchTransition_onKeyguardOccludedChangedCalled() { - when(mNotificationPanelView.isLaunchTransitionFinished()).thenReturn(true); mStatusBarKeyguardViewManager.show(null); mStatusBarKeyguardViewManager.setOccluded(true /* occluded */, false /* animated */); @@ -384,7 +373,7 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { mStatusBarKeyguardViewManager.dismissWithAction( action, cancelAction, true /* afterKeyguardGone */); - when(mBouncer.isShowing()).thenReturn(false); + when(mPrimaryBouncer.isShowing()).thenReturn(false); mStatusBarKeyguardViewManager.hideBouncer(true); mStatusBarKeyguardViewManager.hide(0, 30); verify(action, never()).onDismiss(); @@ -398,7 +387,7 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { mStatusBarKeyguardViewManager.dismissWithAction( action, cancelAction, true /* afterKeyguardGone */); - when(mBouncer.isShowing()).thenReturn(false); + when(mPrimaryBouncer.isShowing()).thenReturn(false); mStatusBarKeyguardViewManager.hideBouncer(true); verify(action, never()).onDismiss(); @@ -419,9 +408,9 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { @Test public void testShowing_whenAlternateAuthShowing() { - mStatusBarKeyguardViewManager.setAlternateAuthInterceptor(mAlternateAuthInterceptor); - when(mBouncer.isShowing()).thenReturn(false); - when(mAlternateAuthInterceptor.isShowingAlternateAuthBouncer()).thenReturn(true); + mStatusBarKeyguardViewManager.setAlternateBouncer(mAlternateBouncer); + when(mPrimaryBouncer.isShowing()).thenReturn(false); + when(mAlternateBouncer.isShowingAlternateBouncer()).thenReturn(true); assertTrue( "Is showing not accurate when alternative auth showing", mStatusBarKeyguardViewManager.isBouncerShowing()); @@ -429,93 +418,93 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { @Test public void testWillBeShowing_whenAlternateAuthShowing() { - mStatusBarKeyguardViewManager.setAlternateAuthInterceptor(mAlternateAuthInterceptor); - when(mBouncer.isShowing()).thenReturn(false); - when(mAlternateAuthInterceptor.isShowingAlternateAuthBouncer()).thenReturn(true); + mStatusBarKeyguardViewManager.setAlternateBouncer(mAlternateBouncer); + when(mPrimaryBouncer.isShowing()).thenReturn(false); + when(mAlternateBouncer.isShowingAlternateBouncer()).thenReturn(true); assertTrue( "Is or will be showing not accurate when alternative auth showing", - mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing()); + mStatusBarKeyguardViewManager.primaryBouncerIsOrWillBeShowing()); } @Test - public void testHideAltAuth_onShowBouncer() { + public void testHideAlternateBouncer_onShowBouncer() { // GIVEN alt auth is showing - mStatusBarKeyguardViewManager.setAlternateAuthInterceptor(mAlternateAuthInterceptor); - when(mBouncer.isShowing()).thenReturn(false); - when(mAlternateAuthInterceptor.isShowingAlternateAuthBouncer()).thenReturn(true); - reset(mAlternateAuthInterceptor); + mStatusBarKeyguardViewManager.setAlternateBouncer(mAlternateBouncer); + when(mPrimaryBouncer.isShowing()).thenReturn(false); + when(mAlternateBouncer.isShowingAlternateBouncer()).thenReturn(true); + reset(mAlternateBouncer); // WHEN showBouncer is called - mStatusBarKeyguardViewManager.showBouncer(true); + mStatusBarKeyguardViewManager.showPrimaryBouncer(true); // THEN alt bouncer should be hidden - verify(mAlternateAuthInterceptor).hideAlternateAuthBouncer(); + verify(mAlternateBouncer).hideAlternateBouncer(); } @Test public void testBouncerIsOrWillBeShowing_whenBouncerIsInTransit() { - when(mBouncer.isShowing()).thenReturn(false); - when(mBouncer.inTransit()).thenReturn(true); + when(mPrimaryBouncer.isShowing()).thenReturn(false); + when(mPrimaryBouncer.inTransit()).thenReturn(true); assertTrue( "Is or will be showing should be true when bouncer is in transit", - mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing()); + mStatusBarKeyguardViewManager.primaryBouncerIsOrWillBeShowing()); } @Test public void testShowAltAuth_unlockingWithBiometricNotAllowed() { // GIVEN alt auth exists, unlocking with biometric isn't allowed - mStatusBarKeyguardViewManager.setAlternateAuthInterceptor(mAlternateAuthInterceptor); - when(mBouncer.isShowing()).thenReturn(false); + mStatusBarKeyguardViewManager.setAlternateBouncer(mAlternateBouncer); + when(mPrimaryBouncer.isShowing()).thenReturn(false); when(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())) .thenReturn(false); // WHEN showGenericBouncer is called final boolean scrimmed = true; - mStatusBarKeyguardViewManager.showGenericBouncer(scrimmed); + mStatusBarKeyguardViewManager.showBouncer(scrimmed); // THEN regular bouncer is shown - verify(mBouncer).show(anyBoolean(), eq(scrimmed)); - verify(mAlternateAuthInterceptor, never()).showAlternateAuthBouncer(); + verify(mPrimaryBouncer).show(anyBoolean(), eq(scrimmed)); + verify(mAlternateBouncer, never()).showAlternateBouncer(); } @Test - public void testShowAltAuth_unlockingWithBiometricAllowed() { + public void testShowAlternateBouncer_unlockingWithBiometricAllowed() { // GIVEN alt auth exists, unlocking with biometric is allowed - mStatusBarKeyguardViewManager.setAlternateAuthInterceptor(mAlternateAuthInterceptor); - when(mBouncer.isShowing()).thenReturn(false); + mStatusBarKeyguardViewManager.setAlternateBouncer(mAlternateBouncer); + when(mPrimaryBouncer.isShowing()).thenReturn(false); when(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true); // WHEN showGenericBouncer is called - mStatusBarKeyguardViewManager.showGenericBouncer(true); + mStatusBarKeyguardViewManager.showBouncer(true); // THEN alt auth bouncer is shown - verify(mAlternateAuthInterceptor).showAlternateAuthBouncer(); - verify(mBouncer, never()).show(anyBoolean(), anyBoolean()); + verify(mAlternateBouncer).showAlternateBouncer(); + verify(mPrimaryBouncer, never()).show(anyBoolean(), anyBoolean()); } @Test public void testUpdateResources_delegatesToBouncer() { mStatusBarKeyguardViewManager.updateResources(); - verify(mBouncer).updateResources(); + verify(mPrimaryBouncer).updateResources(); } @Test public void updateKeyguardPosition_delegatesToBouncer() { mStatusBarKeyguardViewManager.updateKeyguardPosition(1.0f); - verify(mBouncer).updateKeyguardPosition(1.0f); + verify(mPrimaryBouncer).updateKeyguardPosition(1.0f); } @Test public void testIsBouncerInTransit() { - when(mBouncer.inTransit()).thenReturn(true); - Truth.assertThat(mStatusBarKeyguardViewManager.isBouncerInTransit()).isTrue(); - when(mBouncer.inTransit()).thenReturn(false); - Truth.assertThat(mStatusBarKeyguardViewManager.isBouncerInTransit()).isFalse(); - mBouncer = null; - Truth.assertThat(mStatusBarKeyguardViewManager.isBouncerInTransit()).isFalse(); + when(mPrimaryBouncer.inTransit()).thenReturn(true); + Truth.assertThat(mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit()).isTrue(); + when(mPrimaryBouncer.inTransit()).thenReturn(false); + Truth.assertThat(mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit()).isFalse(); + mPrimaryBouncer = null; + Truth.assertThat(mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit()).isFalse(); } private static ShadeExpansionChangeEvent expansionEvent( @@ -546,7 +535,7 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { eq(OnBackInvokedDispatcher.PRIORITY_OVERLAY), mOnBackInvokedCallback.capture()); - when(mBouncer.isShowing()).thenReturn(true); + when(mPrimaryBouncer.isShowing()).thenReturn(true); when(mCentralSurfaces.shouldKeyguardHideImmediately()).thenReturn(true); /* invoke the back callback directly */ mOnBackInvokedCallback.getValue().onBackInvoked(); @@ -579,6 +568,6 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { public void flag_off_DoesNotCallBouncerInteractor() { when(mFeatureFlags.isEnabled(MODERN_BOUNCER)).thenReturn(false); mStatusBarKeyguardViewManager.hideBouncer(false); - verify(mBouncerInteractor, never()).hide(); + verify(mPrimaryBouncerInteractor, never()).hide(); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java index c4098578197b..ce54d784520c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java @@ -67,8 +67,8 @@ import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorControllerProvider; -import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.collection.provider.LaunchFullScreenIntentProvider; import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; @@ -123,8 +123,6 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { @Mock private ShadeControllerImpl mShadeController; @Mock - private NotifPipeline mNotifPipeline; - @Mock private NotificationVisibilityProvider mVisibilityProvider; @Mock private ActivityIntentHelper mActivityIntentHelper; @@ -197,7 +195,6 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { getContext(), mHandler, mUiBgExecutor, - mNotifPipeline, mVisibilityProvider, headsUpManager, mActivityStarter, @@ -222,7 +219,8 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { mock(NotificationPresenter.class), mock(NotificationPanelViewController.class), mActivityLaunchAnimator, - notificationAnimationProvider + notificationAnimationProvider, + mock(LaunchFullScreenIntentProvider.class) ); // set up dismissKeyguardThenExecute to synchronously invoke the OnDismissAction arg @@ -384,11 +382,9 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { NotificationEntry entry = mock(NotificationEntry.class); when(entry.getImportance()).thenReturn(NotificationManager.IMPORTANCE_HIGH); when(entry.getSbn()).thenReturn(sbn); - when(mNotificationInterruptStateProvider.shouldLaunchFullScreenIntentWhenAdded(eq(entry))) - .thenReturn(true); // WHEN - mNotificationActivityStarter.handleFullScreenIntent(entry); + mNotificationActivityStarter.launchFullScreenIntent(entry); // THEN display should try wake up for the full screen intent verify(mCentralSurfaces).wakeUpForFullScreenIntent(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java index c3a7e65f4697..613238f7752e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java @@ -99,6 +99,6 @@ public class StatusBarRemoteInputCallbackTest extends SysuiTestCase { mRemoteInputCallback.onLockedRemoteInput( mock(ExpandableNotificationRow.class), mock(View.class)); - verify(mStatusBarKeyguardViewManager).showGenericBouncer(true); + verify(mStatusBarKeyguardViewManager).showBouncer(true); } }
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt index c5841098010a..37457b308597 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt @@ -28,7 +28,6 @@ import com.android.systemui.lifecycle.InstantTaskExecutorRule 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.phone.StatusBarLocation 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 @@ -40,6 +39,7 @@ import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractor import com.android.systemui.statusbar.pipeline.wifi.shared.WifiConstants +import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.LocationBasedWifiViewModel import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.WifiViewModel import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.CoroutineScope @@ -70,7 +70,7 @@ class ModernStatusBarWifiViewTest : SysuiTestCase() { private lateinit var connectivityRepository: FakeConnectivityRepository private lateinit var wifiRepository: FakeWifiRepository private lateinit var interactor: WifiInteractor - private lateinit var viewModel: WifiViewModel + private lateinit var viewModel: LocationBasedWifiViewModel private lateinit var scope: CoroutineScope private lateinit var airplaneModeViewModel: AirplaneModeViewModel @@ -105,23 +105,19 @@ class ModernStatusBarWifiViewTest : SysuiTestCase() { scope, statusBarPipelineFlags, wifiConstants, - ) + ).home } @Test fun constructAndBind_hasCorrectSlot() { - val view = ModernStatusBarWifiView.constructAndBind( - context, "slotName", viewModel, StatusBarLocation.HOME - ) + val view = ModernStatusBarWifiView.constructAndBind(context, "slotName", viewModel) assertThat(view.slot).isEqualTo("slotName") } @Test fun getVisibleState_icon_returnsIcon() { - val view = ModernStatusBarWifiView.constructAndBind( - context, SLOT_NAME, viewModel, StatusBarLocation.HOME - ) + val view = ModernStatusBarWifiView.constructAndBind(context, SLOT_NAME, viewModel) view.setVisibleState(STATE_ICON, /* animate= */ false) @@ -130,9 +126,7 @@ class ModernStatusBarWifiViewTest : SysuiTestCase() { @Test fun getVisibleState_dot_returnsDot() { - val view = ModernStatusBarWifiView.constructAndBind( - context, SLOT_NAME, viewModel, StatusBarLocation.HOME - ) + val view = ModernStatusBarWifiView.constructAndBind(context, SLOT_NAME, viewModel) view.setVisibleState(STATE_DOT, /* animate= */ false) @@ -141,9 +135,7 @@ class ModernStatusBarWifiViewTest : SysuiTestCase() { @Test fun getVisibleState_hidden_returnsHidden() { - val view = ModernStatusBarWifiView.constructAndBind( - context, SLOT_NAME, viewModel, StatusBarLocation.HOME - ) + val view = ModernStatusBarWifiView.constructAndBind(context, SLOT_NAME, viewModel) view.setVisibleState(STATE_HIDDEN, /* animate= */ false) @@ -155,9 +147,7 @@ class ModernStatusBarWifiViewTest : SysuiTestCase() { @Test fun setVisibleState_icon_iconShownDotHidden() { - val view = ModernStatusBarWifiView.constructAndBind( - context, SLOT_NAME, viewModel, StatusBarLocation.HOME - ) + val view = ModernStatusBarWifiView.constructAndBind(context, SLOT_NAME, viewModel) view.setVisibleState(STATE_ICON, /* animate= */ false) @@ -172,9 +162,7 @@ class ModernStatusBarWifiViewTest : SysuiTestCase() { @Test fun setVisibleState_dot_iconHiddenDotShown() { - val view = ModernStatusBarWifiView.constructAndBind( - context, SLOT_NAME, viewModel, StatusBarLocation.HOME - ) + val view = ModernStatusBarWifiView.constructAndBind(context, SLOT_NAME, viewModel) view.setVisibleState(STATE_DOT, /* animate= */ false) @@ -189,9 +177,7 @@ class ModernStatusBarWifiViewTest : SysuiTestCase() { @Test fun setVisibleState_hidden_iconAndDotHidden() { - val view = ModernStatusBarWifiView.constructAndBind( - context, SLOT_NAME, viewModel, StatusBarLocation.HOME - ) + val view = ModernStatusBarWifiView.constructAndBind(context, SLOT_NAME, viewModel) view.setVisibleState(STATE_HIDDEN, /* animate= */ false) @@ -211,9 +197,7 @@ class ModernStatusBarWifiViewTest : SysuiTestCase() { WifiNetworkModel.Active(NETWORK_ID, isValidated = true, level = 2) ) - val view = ModernStatusBarWifiView.constructAndBind( - context, SLOT_NAME, viewModel, StatusBarLocation.HOME - ) + val view = ModernStatusBarWifiView.constructAndBind(context, SLOT_NAME, viewModel) ViewUtils.attachView(view) testableLooper.processAllMessages() @@ -230,9 +214,7 @@ class ModernStatusBarWifiViewTest : SysuiTestCase() { WifiNetworkModel.Active(NETWORK_ID, isValidated = true, level = 2) ) - val view = ModernStatusBarWifiView.constructAndBind( - context, SLOT_NAME, viewModel, StatusBarLocation.HOME - ) + val view = ModernStatusBarWifiView.constructAndBind(context, SLOT_NAME, viewModel) ViewUtils.attachView(view) testableLooper.processAllMessages() diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java index 4f1fb02ecdcd..26df03f31b9a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.policy; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; @@ -25,6 +26,7 @@ import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import android.net.TetheringManager; @@ -36,6 +38,7 @@ import android.testing.TestableLooper; import androidx.test.filters.SmallTest; +import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.dump.DumpManager; @@ -96,6 +99,9 @@ public class HotspotControllerImplTest extends SysuiTestCase { }).when(mWifiManager).registerSoftApCallback(any(Executor.class), any(WifiManager.SoftApCallback.class)); + mContext.getOrCreateTestableResources() + .addOverride(R.bool.config_show_wifi_tethering, true); + Handler handler = new Handler(mLooper.getLooper()); mController = new HotspotControllerImpl(mContext, handler, handler, mDumpManager); @@ -176,4 +182,18 @@ public class HotspotControllerImplTest extends SysuiTestCase { verify(mCallback1).onHotspotAvailabilityChanged(false); } + + @Test + public void testHotspotSupported_resource_false() { + mContext.getOrCreateTestableResources() + .addOverride(R.bool.config_show_wifi_tethering, false); + + Handler handler = new Handler(mLooper.getLooper()); + + HotspotController controller = + new HotspotControllerImpl(mContext, handler, handler, mDumpManager); + + verifyNoMoreInteractions(mTetheringManager); + assertFalse(controller.isHotspotSupported()); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt index 91b5c35d9661..9dea48e3b47c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt @@ -35,6 +35,8 @@ import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.argumentCaptor import com.android.systemui.util.mockito.capture import com.android.systemui.util.time.FakeSystemClock +import com.android.systemui.util.wakelock.WakeLock +import com.android.systemui.util.wakelock.WakeLockFake import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Test @@ -53,6 +55,9 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() { private lateinit var fakeClock: FakeSystemClock private lateinit var fakeExecutor: FakeExecutor + private lateinit var fakeWakeLockBuilder: WakeLockFake.Builder + private lateinit var fakeWakeLock: WakeLockFake + @Mock private lateinit var logger: TemporaryViewLogger @Mock @@ -74,6 +79,10 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() { fakeClock = FakeSystemClock() fakeExecutor = FakeExecutor(fakeClock) + fakeWakeLock = WakeLockFake() + fakeWakeLockBuilder = WakeLockFake.Builder(context) + fakeWakeLockBuilder.setWakeLock(fakeWakeLock) + underTest = TestController( context, logger, @@ -82,7 +91,9 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() { accessibilityManager, configurationController, powerManager, + fakeWakeLockBuilder, ) + underTest.start() } @Test @@ -112,25 +123,33 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() { } @Test - fun displayView_screenOff_screenWakes() { - whenever(powerManager.isScreenOn).thenReturn(false) - + fun displayView_screenOff_wakeLockAcquired() { underTest.displayView(getState()) - verify(powerManager).wakeUp(any(), any(), any()) + assertThat(fakeWakeLock.isHeld).isTrue() } @Test - fun displayView_screenAlreadyOn_screenNotWoken() { + fun displayView_screenAlreadyOn_wakeLockNotAcquired() { whenever(powerManager.isScreenOn).thenReturn(true) underTest.displayView(getState()) - verify(powerManager, never()).wakeUp(any(), any(), any()) + assertThat(fakeWakeLock.isHeld).isFalse() + } + + @Test + fun displayView_screenOff_wakeLockCanBeReleasedAfterTimeOut() { + underTest.displayView(getState()) + assertThat(fakeWakeLock.isHeld).isTrue() + + fakeClock.advanceTime(TIMEOUT_MS + 1) + + assertThat(fakeWakeLock.isHeld).isFalse() } @Test - fun displayView_twiceWithSameWindowTitle_viewNotAddedTwice() { + fun displayView_twice_viewNotAddedTwice() { underTest.displayView(getState()) reset(windowManager) @@ -269,6 +288,7 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() { accessibilityManager: AccessibilityManager, configurationController: ConfigurationController, powerManager: PowerManager, + wakeLockBuilder: WakeLock.Builder, ) : TemporaryViewDisplayController<ViewInfo, TemporaryViewLogger>( context, logger, @@ -278,13 +298,12 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() { configurationController, powerManager, R.layout.chipbar, + wakeLockBuilder, ) { var mostRecentViewInfo: ViewInfo? = null override val windowLayoutParams = commonWindowLayoutParams - override fun start() {} - override fun updateView(newInfo: ViewInfo, currentView: ViewGroup) { mostRecentViewInfo = newInfo } @@ -292,6 +311,8 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() { override fun getTouchableRegion(view: View, outRect: Rect) { outRect.setEmpty() } + + override fun start() {} } inner class ViewInfo( diff --git a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt index f64397325867..8e37aa292240 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt @@ -43,6 +43,7 @@ import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.eq import com.android.systemui.util.time.FakeSystemClock import com.android.systemui.util.view.ViewUtil +import com.android.systemui.util.wakelock.WakeLockFake import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Test @@ -69,6 +70,8 @@ class ChipbarCoordinatorTest : SysuiTestCase() { @Mock private lateinit var falsingCollector: FalsingCollector @Mock private lateinit var viewUtil: ViewUtil @Mock private lateinit var vibratorHelper: VibratorHelper + private lateinit var fakeWakeLockBuilder: WakeLockFake.Builder + private lateinit var fakeWakeLock: WakeLockFake private lateinit var fakeClock: FakeSystemClock private lateinit var fakeExecutor: FakeExecutor private lateinit var uiEventLoggerFake: UiEventLoggerFake @@ -81,6 +84,10 @@ class ChipbarCoordinatorTest : SysuiTestCase() { fakeClock = FakeSystemClock() fakeExecutor = FakeExecutor(fakeClock) + fakeWakeLock = WakeLockFake() + fakeWakeLockBuilder = WakeLockFake.Builder(context) + fakeWakeLockBuilder.setWakeLock(fakeWakeLock) + uiEventLoggerFake = UiEventLoggerFake() underTest = @@ -96,6 +103,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() { falsingCollector, viewUtil, vibratorHelper, + fakeWakeLockBuilder, ) underTest.start() } diff --git a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/FakeChipbarCoordinator.kt b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/FakeChipbarCoordinator.kt index 574f70e7fddc..beedf9f337bc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/FakeChipbarCoordinator.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/FakeChipbarCoordinator.kt @@ -27,6 +27,7 @@ import com.android.systemui.statusbar.VibratorHelper import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.util.concurrency.DelayableExecutor import com.android.systemui.util.view.ViewUtil +import com.android.systemui.util.wakelock.WakeLock /** A fake implementation of [ChipbarCoordinator] for testing. */ class FakeChipbarCoordinator( @@ -41,6 +42,7 @@ class FakeChipbarCoordinator( falsingCollector: FalsingCollector, viewUtil: ViewUtil, vibratorHelper: VibratorHelper, + wakeLockBuilder: WakeLock.Builder, ) : ChipbarCoordinator( context, @@ -54,6 +56,7 @@ class FakeChipbarCoordinator( falsingCollector, viewUtil, vibratorHelper, + wakeLockBuilder, ) { override fun animateViewOut(view: ViewGroup, onAnimationEnd: Runnable) { // Just bypass the animation in tests diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/CreateUserActivityTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/CreateUserActivityTest.kt new file mode 100644 index 000000000000..51afbcb37442 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/user/CreateUserActivityTest.kt @@ -0,0 +1,55 @@ +package com.android.systemui.user + +import android.app.Dialog +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper +import androidx.test.ext.junit.rules.ActivityScenarioRule +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.util.mockito.mock +import com.android.systemui.util.mockito.nullable +import com.android.systemui.util.mockito.whenever +import com.google.common.truth.Truth.assertThat +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidTestingRunner::class) +@SmallTest +@TestableLooper.RunWithLooper +class CreateUserActivityTest : SysuiTestCase() { + open class CreateUserActivityTestable : + CreateUserActivity( + /* userCreator = */ mock(), + /* editUserInfoController = */ mock { + val dialog: Dialog = mock() + whenever( + createDialog( + /* activity = */ nullable(), + /* activityStarter = */ nullable(), + /* oldUserIcon = */ nullable(), + /* defaultUserName = */ nullable(), + /* title = */ nullable(), + /* successCallback = */ nullable(), + /* cancelCallback = */ nullable() + ) + ) + .thenReturn(dialog) + }, + /* activityManager = */ mock(), + /* activityStarter = */ mock(), + ) + + @get:Rule val activityRule = ActivityScenarioRule(CreateUserActivityTestable::class.java) + + @Test + fun onBackPressed_finishActivity() { + activityRule.scenario.onActivity { activity -> + assertThat(activity.isFinishing).isFalse() + + activity.onBackPressed() + + assertThat(activity.isFinishing).isTrue() + } + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplRefactoredTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplRefactoredTest.kt index 525d8371c9ff..7c7f0e1e0e12 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplRefactoredTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplRefactoredTest.kt @@ -145,6 +145,25 @@ class UserRepositoryImplRefactoredTest : UserRepositoryImplTest() { assertThat(userInfos).isEqualTo(expectedUsers) } + @Test + fun `userTrackerCallback - updates selectedUserInfo`() = runSelfCancelingTest { + underTest = create(this) + var selectedUserInfo: UserInfo? = null + underTest.selectedUserInfo.onEach { selectedUserInfo = it }.launchIn(this) + setUpUsers( + count = 2, + selectedIndex = 0, + ) + tracker.onProfileChanged() + assertThat(selectedUserInfo?.id == 0) + setUpUsers( + count = 2, + selectedIndex = 1, + ) + tracker.onProfileChanged() + assertThat(selectedUserInfo?.id == 1) + } + private fun setUpUsers( count: Int, isLastGuestUser: Boolean = false, diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/WakeLockTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/WakeLockTest.java index fe01f841aa16..6e109eafd748 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/WakeLockTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/WakeLockTest.java @@ -42,7 +42,9 @@ public class WakeLockTest extends SysuiTestCase { @Before public void setUp() { - mInner = WakeLock.createPartialInner(mContext, WakeLockTest.class.getName()); + mInner = WakeLock.createWakeLockInner(mContext, + WakeLockTest.class.getName(), + PowerManager.PARTIAL_WAKE_LOCK); mWakeLock = WakeLock.wrap(mInner, 20000); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java index fa7ebf6a2449..bee882d43849 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java @@ -86,6 +86,7 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.biometrics.AuthController; import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.dump.DumpManager; +import com.android.systemui.flags.FeatureFlags; import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.model.SysUiState; import com.android.systemui.plugins.statusbar.StatusBarStateController; @@ -394,6 +395,7 @@ public class BubblesTest extends SysuiTestCase { mCommonNotifCollection, mNotifPipeline, mSysUiState, + mock(FeatureFlags.class), syncExecutor); mBubblesManager.addNotifCallback(mNotifCallback); diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FalsingManagerFake.java b/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FalsingManagerFake.java index 34c83bd41a02..d47e88fc9385 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FalsingManagerFake.java +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FalsingManagerFake.java @@ -39,6 +39,7 @@ public class FalsingManagerFake implements FalsingManager { private boolean mShouldEnforceBouncer; private boolean mIsReportingEnabled; private boolean mIsFalseRobustTap; + private boolean mIsFalseLongTap; private boolean mDestroyed; private boolean mIsProximityNear; @@ -87,6 +88,10 @@ public class FalsingManagerFake implements FalsingManager { mIsProximityNear = proxNear; } + public void setFalseLongTap(boolean falseLongTap) { + mIsFalseLongTap = falseLongTap; + } + @Override public boolean isSimpleTap() { checkDestroyed(); @@ -100,6 +105,12 @@ public class FalsingManagerFake implements FalsingManager { } @Override + public boolean isFalseLongTap(int penalty) { + checkDestroyed(); + return mIsFalseLongTap; + } + + @Override public boolean isFalseDoubleTap() { checkDestroyed(); return mIsFalseDoubleTap; diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt index a60b7735fbd4..6c82cef22ddb 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt @@ -21,14 +21,14 @@ import java.io.PrintWriter class FakeFeatureFlags : FeatureFlags { private val booleanFlags = mutableMapOf<Int, Boolean>() private val stringFlags = mutableMapOf<Int, String>() + private val intFlags = mutableMapOf<Int, Int>() private val knownFlagNames = mutableMapOf<Int, String>() private val flagListeners = mutableMapOf<Int, MutableSet<FlagListenable.Listener>>() private val listenerFlagIds = mutableMapOf<FlagListenable.Listener, MutableSet<Int>>() init { - Flags.flagFields.forEach { field -> - val flag: Flag<*> = field.get(null) as Flag<*> - knownFlagNames[flag.id] = field.name + FlagsFactory.knownFlags.forEach { entry: Map.Entry<String, Flag<*>> -> + knownFlagNames[entry.value.id] = entry.key } } @@ -87,14 +87,16 @@ class FakeFeatureFlags : FeatureFlags { override fun isEnabled(flag: ResourceBooleanFlag): Boolean = requireBooleanValue(flag.id) - override fun isEnabled(flag: DeviceConfigBooleanFlag): Boolean = requireBooleanValue(flag.id) - override fun isEnabled(flag: SysPropBooleanFlag): Boolean = requireBooleanValue(flag.id) override fun getString(flag: StringFlag): String = requireStringValue(flag.id) override fun getString(flag: ResourceStringFlag): String = requireStringValue(flag.id) + override fun getInt(flag: IntFlag): Int = requireIntValue(flag.id) + + override fun getInt(flag: ResourceIntFlag): Int = requireIntValue(flag.id) + override fun addListener(flag: Flag<*>, listener: FlagListenable.Listener) { flagListeners.getOrPut(flag.id) { mutableSetOf() }.add(listener) listenerFlagIds.getOrPut(listener) { mutableSetOf() }.add(flag.id) @@ -118,11 +120,16 @@ class FakeFeatureFlags : FeatureFlags { private fun requireBooleanValue(flagId: Int): Boolean { return booleanFlags[flagId] - ?: error("Flag ${flagName(flagId)} was accessed but not specified.") + ?: error("Flag ${flagName(flagId)} was accessed as boolean but not specified.") } private fun requireStringValue(flagId: Int): String { return stringFlags[flagId] - ?: error("Flag ${flagName(flagId)} was accessed but not specified.") + ?: error("Flag ${flagName(flagId)} was accessed as string but not specified.") + } + + private fun requireIntValue(flagId: Int): Int { + return intFlags[flagId] + ?: error("Flag ${flagName(flagId)} was accessed as int but not specified.") } } 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 627bd096143e..6f70f0ee0f2b 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 @@ -53,6 +53,8 @@ class FakeKeyguardRepository : KeyguardRepository { private val _wakefulnessState = MutableStateFlow(WakefulnessModel.ASLEEP) override val wakefulnessState: Flow<WakefulnessModel> = _wakefulnessState + private val _isUdfpsSupported = MutableStateFlow(false) + private val _isBouncerShowing = MutableStateFlow(false) override val isBouncerShowing: Flow<Boolean> = _isBouncerShowing @@ -86,4 +88,8 @@ class FakeKeyguardRepository : KeyguardRepository { fun setDozeAmount(dozeAmount: Float) { _dozeAmount.value = dozeAmount } + + override fun isUdfpsSupported(): Boolean { + return _isUdfpsSupported.value + } } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeUserTracker.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeUserTracker.kt index 9726bf83b263..a7eadba60ddc 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeUserTracker.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeUserTracker.kt @@ -68,4 +68,8 @@ class FakeUserTracker( callbacks.forEach { it.onUserChanged(_userId, userContext) } } + + fun onProfileChanged() { + callbacks.forEach { it.onProfilesChanged(_userProfiles) } + } } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java index 23c7a6139de8..2d6d29a50a74 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java @@ -62,7 +62,11 @@ public class FakeStatusBarIconController extends BaseLeakChecker<IconManager> } @Override - public void setSignalIcon(String slot, WifiIconState state) { + public void setWifiIcon(String slot, WifiIconState state) { + } + + @Override + public void setNewWifiIcon() { } @Override diff --git a/packages/VpnDialogs/res/values-de/strings.xml b/packages/VpnDialogs/res/values-de/strings.xml index f38e3953855a..1de780562966 100644 --- a/packages/VpnDialogs/res/values-de/strings.xml +++ b/packages/VpnDialogs/res/values-de/strings.xml @@ -17,7 +17,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="prompt" msgid="3183836924226407828">"Verbindungsanfrage"</string> - <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> möchte eine VPN-Verbindung herstellen, über die der Netzwerkverkehr überwacht werden kann. Lass die Verbindung nur zu, wenn die App vertrauenswürdig ist. Wenn VPN aktiv ist, wird oben im Display <br /> <br /> <img src=vpn_icon /> angezeigt."</string> + <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> möchte eine VPN-Verbindung herstellen, über die der Netzwerkverkehr überwacht werden kann. Lass die Verbindung nur zu, wenn die App vertrauenswürdig ist. <br /> <br /> Wenn das VPN aktiv ist, wird oben im Display <img src=vpn_icon /> angezeigt."</string> <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> möchte eine VPN-Verbindung herstellen, über die der Netzwerkverkehr überwacht werden kann. Lass die Verbindung nur zu, wenn die App vertrauenswürdig ist. <br /> <br /> <img src=vpn_icon /> wird auf dem Display angezeigt, wenn VPN aktiv ist."</string> <string name="legacy_title" msgid="192936250066580964">"VPN ist verbunden"</string> <string name="session" msgid="6470628549473641030">"Sitzung:"</string> diff --git a/packages/VpnDialogs/res/values-it/strings.xml b/packages/VpnDialogs/res/values-it/strings.xml index c443c510198e..118fb6a69005 100644 --- a/packages/VpnDialogs/res/values-it/strings.xml +++ b/packages/VpnDialogs/res/values-it/strings.xml @@ -17,7 +17,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="prompt" msgid="3183836924226407828">"Richiesta di connessione"</string> - <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> vuole impostare una connessione VPN che le consenta di monitorare il traffico di rete. Accetta soltanto se ritieni la fonte attendibile. Quando la connessione VPN è attiva, nella parte superiore dello schermo viene visualizzata l\'icona <br /> <br /> <img src=vpn_icon />."</string> + <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> vuole impostare una connessione VPN per monitorare il traffico di rete. Accetta soltanto se ritieni la fonte attendibile. Quando la connessione VPN è attiva, in alto sullo schermo appare l\'icona <br /> <br /> <img src=vpn_icon />."</string> <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> vuole configurare una connessione VPN che le consenta di monitorare il traffico di rete. Accetta soltanto se ritieni la fonte attendibile. Quando la connessione VPN è attiva, sullo schermo viene visualizzata l\'icona <br /> <br /> <img src=vpn_icon />."</string> <string name="legacy_title" msgid="192936250066580964">"VPN connessa"</string> <string name="session" msgid="6470628549473641030">"Sessione:"</string> diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 85d6f293852c..fde96b96cb9c 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -3755,22 +3755,27 @@ public class ActivityManagerService extends IActivityManager.Stub finishForceStopPackageLocked(packageName, appInfo.uid); } } - final Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED, - Uri.fromParts("package", packageName, null)); - intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); - intent.putExtra(Intent.EXTRA_UID, (appInfo != null) ? appInfo.uid : -1); - intent.putExtra(Intent.EXTRA_USER_HANDLE, resolvedUserId); - final int[] visibilityAllowList = - mPackageManagerInt.getVisibilityAllowList(packageName, resolvedUserId); - if (isInstantApp) { - intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName); - broadcastIntentInPackage("android", null, SYSTEM_UID, uid, pid, intent, - null, null, 0, null, null, permission.ACCESS_INSTANT_APPS, null, - false, false, resolvedUserId, false, null, visibilityAllowList); - } else { - broadcastIntentInPackage("android", null, SYSTEM_UID, uid, pid, intent, - null, null, 0, null, null, null, null, false, false, resolvedUserId, - false, null, visibilityAllowList); + + if (succeeded) { + final Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED, + Uri.fromParts("package", packageName, null /* fragment */)); + intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); + intent.putExtra(Intent.EXTRA_UID, + (appInfo != null) ? appInfo.uid : INVALID_UID); + intent.putExtra(Intent.EXTRA_USER_HANDLE, resolvedUserId); + if (isInstantApp) { + intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName); + } + final int[] visibilityAllowList = mPackageManagerInt.getVisibilityAllowList( + packageName, resolvedUserId); + + broadcastIntentInPackage("android", null /* featureId */, SYSTEM_UID, + uid, pid, intent, null /* resolvedType */, null /* resultTo */, + 0 /* resultCode */, null /* resultData */, null /* resultExtras */, + isInstantApp ? permission.ACCESS_INSTANT_APPS : null, + null /* bOptions */, false /* serialized */, false /* sticky */, + resolvedUserId, false /* allowBackgroundActivityStarts */, + null /* backgroundActivityStartsToken */, visibilityAllowList); } if (observer != null) { diff --git a/services/core/java/com/android/server/am/ContentProviderHelper.java b/services/core/java/com/android/server/am/ContentProviderHelper.java index 453385938aca..212793a3a7b5 100644 --- a/services/core/java/com/android/server/am/ContentProviderHelper.java +++ b/services/core/java/com/android/server/am/ContentProviderHelper.java @@ -80,6 +80,7 @@ import com.android.internal.util.FrameworkStatsLog; import com.android.server.LocalServices; import com.android.server.RescueParty; import com.android.server.pm.UserManagerInternal; +import com.android.server.pm.UserManagerService; import com.android.server.pm.parsing.pkg.AndroidPackage; import java.io.FileDescriptor; @@ -162,7 +163,7 @@ public class ContentProviderHelper { private ContentProviderHolder getContentProviderImpl(IApplicationThread caller, String name, IBinder token, int callingUid, String callingPackage, String callingTag, boolean stable, int userId) { - ContentProviderRecord cpr; + ContentProviderRecord cpr = null; ContentProviderConnection conn = null; ProviderInfo cpi = null; boolean providerRunning = false; @@ -184,8 +185,21 @@ public class ContentProviderHelper { checkTime(startTime, "getContentProviderImpl: getProviderByName"); - // First check if this content provider has been published... - cpr = mProviderMap.getProviderByName(name, userId); + UserManagerService userManagerService = UserManagerService.getInstance(); + + /* + For clone user profile and allowed authority, skipping finding provider and redirecting + it to owner profile. Ideally clone profile should not have MediaProvider instance + installed and mProviderMap would not have entry for clone user. This is just fallback + check to ensure even if MediaProvider is installed in Clone Profile, it should not be + used and redirect to owner user's MediaProvider. + */ + //todo(b/236121588) MediaProvider should not be installed in clone profile. + if (!isAuthorityRedirectedForCloneProfile(name) + || !userManagerService.isMediaSharedWithParent(userId)) { + // First check if this content provider has been published... + cpr = mProviderMap.getProviderByName(name, userId); + } // If that didn't work, check if it exists for user 0 and then // verify that it's a singleton provider before using it. if (cpr == null && userId != UserHandle.USER_SYSTEM) { @@ -200,11 +214,9 @@ public class ContentProviderHelper { userId = UserHandle.USER_SYSTEM; checkCrossUser = false; } else if (isAuthorityRedirectedForCloneProfile(name)) { - UserManagerInternal umInternal = LocalServices.getService( - UserManagerInternal.class); - UserInfo userInfo = umInternal.getUserInfo(userId); - - if (userInfo != null && userInfo.isCloneProfile()) { + if (userManagerService.isMediaSharedWithParent(userId)) { + UserManagerInternal umInternal = LocalServices.getService( + UserManagerInternal.class); userId = umInternal.getProfileParentId(userId); checkCrossUser = false; } diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java index bda60ff2172b..8624ee031a93 100644 --- a/services/core/java/com/android/server/am/PendingIntentRecord.java +++ b/services/core/java/com/android/server/am/PendingIntentRecord.java @@ -379,11 +379,16 @@ public final class PendingIntentRecord extends IIntentSender.Stub { resolvedType = key.requestResolvedType; } - // Apply any launch flags from the ActivityOptions. This is to ensure that the caller - // can specify a consistent launch mode even if the PendingIntent is immutable + // Apply any launch flags from the ActivityOptions. This is used only by SystemUI + // to ensure that we can launch the pending intent with a consistent launch mode even + // if the provided PendingIntent is immutable (ie. to force an activity to launch into + // a new task, or to launch multiple instances if supported by the app) final ActivityOptions opts = ActivityOptions.fromBundle(options); if (opts != null) { - finalIntent.addFlags(opts.getPendingIntentLaunchFlags()); + // TODO(b/254490217): Move this check into SafeActivityOptions + if (controller.mAtmInternal.isCallerRecents(Binder.getCallingUid())) { + finalIntent.addFlags(opts.getPendingIntentLaunchFlags()); + } } // Extract options before clearing calling identity diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index d2ba9c6dbfe4..53fcf3293525 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -41,6 +41,7 @@ import android.annotation.SuppressLint; import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.ActivityManagerInternal; +import android.app.ActivityThread; import android.app.AlarmManager; import android.app.AppGlobals; import android.app.AppOpsManager; @@ -152,6 +153,7 @@ import android.os.VibrationAttributes; import android.os.VibrationEffect; import android.os.Vibrator; import android.os.VibratorManager; +import android.provider.DeviceConfig; import android.provider.Settings; import android.provider.Settings.System; import android.service.notification.ZenModeConfig; @@ -173,6 +175,7 @@ import android.widget.Toast; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; import com.android.internal.util.DumpUtils; import com.android.internal.util.Preconditions; import com.android.server.EventLogTags; @@ -231,6 +234,7 @@ public class AudioService extends IAudioService.Stub AudioSystemAdapter.OnVolRangeInitRequestListener { private static final String TAG = "AS.AudioService"; + private static final boolean CONFIG_DEFAULT_VAL = false; private final AudioSystemAdapter mAudioSystem; private final SystemServerAdapter mSystemServer; @@ -981,6 +985,7 @@ public class AudioService extends IAudioService.Stub * @param looper Looper to use for the service's message handler. If this is null, an * {@link AudioSystemThread} is created as the messaging thread instead. */ + @RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG) public AudioService(Context context, AudioSystemAdapter audioSystem, SystemServerAdapter systemServer, SettingsAdapter settings, @Nullable Looper looper, AppOpsManager appOps) { @@ -1020,8 +1025,12 @@ public class AudioService extends IAudioService.Stub mUseVolumeGroupAliases = mContext.getResources().getBoolean( com.android.internal.R.bool.config_handleVolumeAliasesUsingVolumeGroups); - mNotifAliasRing = mContext.getResources().getBoolean( - com.android.internal.R.bool.config_alias_ring_notif_stream_types); + mNotifAliasRing = !DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI, + SystemUiDeviceConfigFlags.VOLUME_SEPARATE_NOTIFICATION, false); + + DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI, + ActivityThread.currentApplication().getMainExecutor(), + this::onDeviceConfigChange); // Initialize volume // Priority 1 - Android Property @@ -1240,6 +1249,22 @@ public class AudioService extends IAudioService.Stub } /** + * Separating notification volume from ring is NOT of aliasing the corresponding streams + * @param properties + */ + private void onDeviceConfigChange(DeviceConfig.Properties properties) { + Set<String> changeSet = properties.getKeyset(); + if (changeSet.contains(SystemUiDeviceConfigFlags.VOLUME_SEPARATE_NOTIFICATION)) { + boolean newNotifAliasRing = !properties.getBoolean( + SystemUiDeviceConfigFlags.VOLUME_SEPARATE_NOTIFICATION, CONFIG_DEFAULT_VAL); + if (mNotifAliasRing != newNotifAliasRing) { + mNotifAliasRing = newNotifAliasRing; + updateStreamVolumeAlias(true, TAG); + } + } + } + + /** * Called by handling of MSG_INIT_STREAMS_VOLUMES */ private void onInitStreamsAndVolumes() { diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java index 9aecf783a881..05e83da6a107 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java @@ -92,6 +92,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession> private long mSideFpsLastAcquireStartTime; private Runnable mAuthSuccessRunnable; private final Clock mClock; + private boolean mDidFinishSfps; FingerprintAuthenticationClient( @NonNull Context context, @@ -197,8 +198,9 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession> @Override protected void handleLifecycleAfterAuth(boolean authenticated) { - if (authenticated) { + if (authenticated && !mDidFinishSfps) { mCallback.onClientFinished(this, true /* success */); + mDidFinishSfps = true; } } @@ -490,11 +492,16 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession> if (mSensorProps.isAnySidefpsType()) { Slog.i(TAG, "(sideFPS): onPowerPressed"); mHandler.post(() -> { + if (mDidFinishSfps) { + return; + } Slog.i(TAG, "(sideFPS): finishing auth"); // Ignore auths after a power has been detected mHandler.removeMessages(MESSAGE_AUTH_SUCCESS); // Do not call onError() as that will send an additional callback to coex. + mDidFinishSfps = true; onErrorInternal(BiometricConstants.BIOMETRIC_ERROR_POWER_PRESSED, 0, true); + stopHalOperation(); mSensorOverlays.hide(getSensorId()); }); } diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index b8ff6ed93666..7806ece9e65f 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -2598,7 +2598,7 @@ public final class DisplayManagerService extends SystemService { // initPowerManagement has not yet been called. return; } - if (mBrightnessTracker == null) { + if (mBrightnessTracker == null && display.getDisplayIdLocked() == Display.DEFAULT_DISPLAY) { mBrightnessTracker = new BrightnessTracker(mContext, null); } diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index 95dc23fc3120..69c890d90d03 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -913,7 +913,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call // Initialize all of the brightness tracking state final float brightness = convertToNits(mPowerState.getScreenBrightness()); - if (brightness >= PowerManager.BRIGHTNESS_MIN) { + if (mBrightnessTracker != null && brightness >= PowerManager.BRIGHTNESS_MIN) { mBrightnessTracker.start(brightness); } mBrightnessSettingListener = brightnessValue -> { @@ -1045,7 +1045,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } loadAmbientLightSensor(); - if (mBrightnessTracker != null) { + // BrightnessTracker should only use one light sensor, we want to use the light sensor + // from the default display and not e.g. temporary displays when switching layouts. + if (mBrightnessTracker != null && mDisplayId == Display.DEFAULT_DISPLAY) { mBrightnessTracker.setLightSensor(mLightSensor); } @@ -2453,7 +2455,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call boolean hadUserDataPoint) { final float brightnessInNits = convertToNits(brightness); if (mPowerRequest.useAutoBrightness && brightnessInNits >= 0.0f - && mAutomaticBrightnessController != null) { + && mAutomaticBrightnessController != null && mBrightnessTracker != null) { // We only want to track changes on devices that can actually map the display backlight // values into a physical brightness unit since the value provided by the API is in // nits and not using the arbitrary backlight units. diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java index 70c9e23c6af8..f64006c3b7c4 100644 --- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java +++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java @@ -167,6 +167,12 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { LogicalDisplayMapper(@NonNull Context context, @NonNull DisplayDeviceRepository repo, @NonNull Listener listener, @NonNull DisplayManagerService.SyncRoot syncRoot, @NonNull Handler handler) { + this(context, repo, listener, syncRoot, handler, new DeviceStateToLayoutMap()); + } + + LogicalDisplayMapper(@NonNull Context context, @NonNull DisplayDeviceRepository repo, + @NonNull Listener listener, @NonNull DisplayManagerService.SyncRoot syncRoot, + @NonNull Handler handler, DeviceStateToLayoutMap deviceStateToLayoutMap) { mSyncRoot = syncRoot; mPowerManager = context.getSystemService(PowerManager.class); mInteractive = mPowerManager.isInteractive(); @@ -181,7 +187,7 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { mDeviceStatesOnWhichToSleep = toSparseBooleanArray(context.getResources().getIntArray( com.android.internal.R.array.config_deviceStatesOnWhichToSleep)); mDisplayDeviceRepo.addListener(this); - mDeviceStateToLayoutMap = new DeviceStateToLayoutMap(); + mDeviceStateToLayoutMap = deviceStateToLayoutMap; } @Override @@ -369,9 +375,7 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { // the transition is smooth. Plus, on some devices, only one internal displays can be // on at a time. We use DISPLAY_PHASE_LAYOUT_TRANSITION to mark a display that needs to be // temporarily turned off. - if (mDeviceState != DeviceStateManager.INVALID_DEVICE_STATE) { - resetLayoutLocked(mDeviceState, state, LogicalDisplay.DISPLAY_PHASE_LAYOUT_TRANSITION); - } + resetLayoutLocked(mDeviceState, state, LogicalDisplay.DISPLAY_PHASE_LAYOUT_TRANSITION); mPendingDeviceState = state; final boolean wakeDevice = shouldDeviceBeWoken(mPendingDeviceState, mDeviceState, mInteractive, mBootCompleted); @@ -891,8 +895,8 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { newDisplay.swapDisplaysLocked(oldDisplay); } - if (!displayLayout.isEnabled()) { - setDisplayPhase(newDisplay, LogicalDisplay.DISPLAY_PHASE_DISABLED); + if (displayLayout.isEnabled()) { + setDisplayPhase(newDisplay, LogicalDisplay.DISPLAY_PHASE_ENABLED); } } @@ -912,7 +916,7 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { final LogicalDisplay display = new LogicalDisplay(displayId, layerStack, device); display.updateLocked(mDisplayDeviceRepo); mLogicalDisplays.put(displayId, display); - setDisplayPhase(display, LogicalDisplay.DISPLAY_PHASE_ENABLED); + setDisplayPhase(display, LogicalDisplay.DISPLAY_PHASE_DISABLED); return display; } diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java index e4aa5e574955..b9511c45771b 100644 --- a/services/core/java/com/android/server/dreams/DreamManagerService.java +++ b/services/core/java/com/android/server/dreams/DreamManagerService.java @@ -23,12 +23,14 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static com.android.server.wm.ActivityInterceptorCallback.DREAM_MANAGER_ORDERED_ID; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.TaskInfo; import android.content.BroadcastReceiver; import android.content.ComponentName; +import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; @@ -39,6 +41,8 @@ import android.content.pm.ServiceInfo; import android.database.ContentObserver; import android.hardware.display.AmbientDisplayConfiguration; import android.hardware.input.InputManagerInternal; +import android.net.Uri; +import android.os.BatteryManager; import android.os.Binder; import android.os.Build; import android.os.Handler; @@ -72,6 +76,8 @@ import com.android.server.wm.ActivityTaskManagerInternal; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -88,6 +94,15 @@ public final class DreamManagerService extends SystemService { private static final String DOZE_WAKE_LOCK_TAG = "dream:doze"; private static final String DREAM_WAKE_LOCK_TAG = "dream:dream"; + /** Constants for the when to activate dreams. */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({DREAM_ON_DOCK, DREAM_ON_CHARGE, DREAM_ON_DOCK_OR_CHARGE}) + public @interface WhenToDream {} + private static final int DREAM_DISABLED = 0x0; + private static final int DREAM_ON_DOCK = 0x1; + private static final int DREAM_ON_CHARGE = 0x2; + private static final int DREAM_ON_DOCK_OR_CHARGE = 0x3; + private final Object mLock = new Object(); private final Context mContext; @@ -101,12 +116,20 @@ public final class DreamManagerService extends SystemService { private final DreamUiEventLogger mDreamUiEventLogger; private final ComponentName mAmbientDisplayComponent; private final boolean mDismissDreamOnActivityStart; + private final boolean mDreamsOnlyEnabledForSystemUser; + private final boolean mDreamsEnabledByDefaultConfig; + private final boolean mDreamsActivatedOnChargeByDefault; + private final boolean mDreamsActivatedOnDockByDefault; @GuardedBy("mLock") private DreamRecord mCurrentDream; private boolean mForceAmbientDisplayEnabled; - private final boolean mDreamsOnlyEnabledForSystemUser; + private SettingsObserver mSettingsObserver; + private boolean mDreamsEnabledSetting; + @WhenToDream private int mWhenToDream; + private boolean mIsDocked; + private boolean mIsCharging; // A temporary dream component that, when present, takes precedence over user configured dream // component. @@ -144,6 +167,37 @@ public final class DreamManagerService extends SystemService { } }; + private final BroadcastReceiver mChargingReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + mIsCharging = BatteryManager.ACTION_CHARGING.equals(intent.getAction()); + } + }; + + private final BroadcastReceiver mDockStateReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (Intent.ACTION_DOCK_EVENT.equals(intent.getAction())) { + final int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, + Intent.EXTRA_DOCK_STATE_UNDOCKED); + mIsDocked = dockState != Intent.EXTRA_DOCK_STATE_UNDOCKED; + } + } + }; + + private final class SettingsObserver extends ContentObserver { + SettingsObserver(Handler handler) { + super(handler); + } + + @Override + public void onChange(boolean selfChange, Uri uri) { + synchronized (mLock) { + updateWhenToDreamSettings(); + } + } + } + public DreamManagerService(Context context) { super(context); mContext = context; @@ -164,6 +218,14 @@ public final class DreamManagerService extends SystemService { mContext.getResources().getBoolean(R.bool.config_dreamsOnlyEnabledForSystemUser); mDismissDreamOnActivityStart = mContext.getResources().getBoolean( R.bool.config_dismissDreamOnActivityStart); + + mDreamsEnabledByDefaultConfig = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_dreamsEnabledByDefault); + mDreamsActivatedOnChargeByDefault = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_dreamsActivatedOnSleepByDefault); + mDreamsActivatedOnDockByDefault = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_dreamsActivatedOnDockByDefault); + mSettingsObserver = new SettingsObserver(mHandler); } @Override @@ -197,6 +259,30 @@ public final class DreamManagerService extends SystemService { DREAM_MANAGER_ORDERED_ID, mActivityInterceptorCallback); } + + mContext.registerReceiver( + mDockStateReceiver, new IntentFilter(Intent.ACTION_DOCK_EVENT)); + IntentFilter chargingIntentFilter = new IntentFilter(); + chargingIntentFilter.addAction(BatteryManager.ACTION_CHARGING); + chargingIntentFilter.addAction(BatteryManager.ACTION_DISCHARGING); + mContext.registerReceiver(mChargingReceiver, chargingIntentFilter); + + mSettingsObserver = new SettingsObserver(mHandler); + mContext.getContentResolver().registerContentObserver(Settings.Secure.getUriFor( + Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP), + false, mSettingsObserver, UserHandle.USER_ALL); + mContext.getContentResolver().registerContentObserver(Settings.Secure.getUriFor( + Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK), + false, mSettingsObserver, UserHandle.USER_ALL); + mContext.getContentResolver().registerContentObserver(Settings.Secure.getUriFor( + Settings.Secure.SCREENSAVER_ENABLED), + false, mSettingsObserver, UserHandle.USER_ALL); + + // We don't get an initial broadcast for the batter state, so we have to initialize + // directly from BatteryManager. + mIsCharging = mContext.getSystemService(BatteryManager.class).isCharging(); + + updateWhenToDreamSettings(); } } @@ -207,6 +293,14 @@ public final class DreamManagerService extends SystemService { pw.println("mCurrentDream=" + mCurrentDream); pw.println("mForceAmbientDisplayEnabled=" + mForceAmbientDisplayEnabled); pw.println("mDreamsOnlyEnabledForSystemUser=" + mDreamsOnlyEnabledForSystemUser); + pw.println("mDreamsEnabledSetting=" + mDreamsEnabledSetting); + pw.println("mForceAmbientDisplayEnabled=" + mForceAmbientDisplayEnabled); + pw.println("mDreamsOnlyEnabledForSystemUser=" + mDreamsOnlyEnabledForSystemUser); + pw.println("mDreamsActivatedOnDockByDefault=" + mDreamsActivatedOnDockByDefault); + pw.println("mDreamsActivatedOnChargeByDefault=" + mDreamsActivatedOnChargeByDefault); + pw.println("mIsDocked=" + mIsDocked); + pw.println("mIsCharging=" + mIsCharging); + pw.println("mWhenToDream=" + mWhenToDream); pw.println("getDozeComponent()=" + getDozeComponent()); pw.println(); @@ -214,7 +308,28 @@ public final class DreamManagerService extends SystemService { } } - /** Whether a real dream is occurring. */ + private void updateWhenToDreamSettings() { + synchronized (mLock) { + final ContentResolver resolver = mContext.getContentResolver(); + + final int activateWhenCharging = (Settings.Secure.getIntForUser(resolver, + Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, + mDreamsActivatedOnChargeByDefault ? 1 : 0, + UserHandle.USER_CURRENT) != 0) ? DREAM_ON_CHARGE : DREAM_DISABLED; + final int activateWhenDocked = (Settings.Secure.getIntForUser(resolver, + Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK, + mDreamsActivatedOnDockByDefault ? 1 : 0, + UserHandle.USER_CURRENT) != 0) ? DREAM_ON_DOCK : DREAM_DISABLED; + mWhenToDream = activateWhenCharging + activateWhenDocked; + + mDreamsEnabledSetting = (Settings.Secure.getIntForUser(resolver, + Settings.Secure.SCREENSAVER_ENABLED, + mDreamsEnabledByDefaultConfig ? 1 : 0, + UserHandle.USER_CURRENT) != 0); + } + } + + /** Whether a real dream is occurring. */ private boolean isDreamingInternal() { synchronized (mLock) { return mCurrentDream != null && !mCurrentDream.isPreview @@ -236,6 +351,30 @@ public final class DreamManagerService extends SystemService { } } + /** Whether dreaming can start given user settings and the current dock/charge state. */ + private boolean canStartDreamingInternal(boolean isScreenOn) { + synchronized (mLock) { + // Can't start dreaming if we are already dreaming. + if (isScreenOn && isDreamingInternal()) { + return false; + } + + if (!mDreamsEnabledSetting) { + return false; + } + + if ((mWhenToDream & DREAM_ON_CHARGE) == DREAM_ON_CHARGE) { + return mIsCharging; + } + + if ((mWhenToDream & DREAM_ON_DOCK) == DREAM_ON_DOCK) { + return mIsDocked; + } + + return false; + } + } + protected void requestStartDreamFromShell() { requestDreamInternal(); } @@ -352,10 +491,6 @@ public final class DreamManagerService extends SystemService { } } - private ComponentName getActiveDreamComponentInternal(boolean doze) { - return chooseDreamForUser(doze, ActivityManager.getCurrentUser()); - } - /** * If doze is true, returns the doze component for the user. * Otherwise, returns the system dream component, if present. @@ -508,7 +643,7 @@ public final class DreamManagerService extends SystemService { .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, DREAM_WAKE_LOCK_TAG); final Binder dreamToken = mCurrentDream.token; mHandler.post(wakeLock.wrap(() -> { - mAtmInternal.notifyDreamStateChanged(true); + mAtmInternal.notifyActiveDreamChanged(name); mController.startDream(dreamToken, name, isPreviewMode, canDoze, userId, wakeLock, mDreamOverlayServiceName, reason); })); @@ -533,7 +668,7 @@ public final class DreamManagerService extends SystemService { @GuardedBy("mLock") private void cleanupDreamLocked() { - mHandler.post(() -> mAtmInternal.notifyDreamStateChanged(false /*dreaming*/)); + mHandler.post(() -> mAtmInternal.notifyActiveDreamChanged(null)); if (mCurrentDream == null) { return; @@ -869,8 +1004,8 @@ public final class DreamManagerService extends SystemService { } @Override - public ComponentName getActiveDreamComponent(boolean doze) { - return getActiveDreamComponentInternal(doze); + public boolean canStartDreaming(boolean isScreenOn) { + return canStartDreamingInternal(isScreenOn); } @Override diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java index 604e8f3949f4..0785fac17984 100644 --- a/services/core/java/com/android/server/media/MediaSessionRecord.java +++ b/services/core/java/com/android/server/media/MediaSessionRecord.java @@ -52,6 +52,8 @@ import android.os.Process; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.SystemClock; +import android.text.TextUtils; +import android.util.EventLog; import android.util.Log; import android.view.KeyEvent; @@ -956,6 +958,14 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR public void setMediaButtonBroadcastReceiver(ComponentName receiver) throws RemoteException { final long token = Binder.clearCallingIdentity(); try { + //mPackageName has been verified in MediaSessionService.enforcePackageName(). + if (receiver != null && !TextUtils.equals( + mPackageName, receiver.getPackageName())) { + EventLog.writeEvent(0x534e4554, "238177121", -1, ""); // SafetyNet logging. + throw new IllegalArgumentException("receiver does not belong to " + + "package name provided to MediaSessionRecord. Pkg = " + mPackageName + + ", Receiver Pkg = " + receiver.getPackageName()); + } if ((mPolicies & MediaSessionPolicyProvider.SESSION_POLICY_IGNORE_BUTTON_RECEIVER) != 0) { return; diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 37f980d699bd..c2df904d07ce 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -4966,16 +4966,7 @@ public class NotificationManagerService extends SystemService { } enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule"); - // If the caller is system, take the package name from the rule's owner rather than - // from the caller's package. - String rulePkg = pkg; - if (isCallingUidSystem()) { - if (automaticZenRule.getOwner() != null) { - rulePkg = automaticZenRule.getOwner().getPackageName(); - } - } - - return mZenModeHelper.addAutomaticZenRule(rulePkg, automaticZenRule, + return mZenModeHelper.addAutomaticZenRule(pkg, automaticZenRule, "addAutomaticZenRule"); } diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index 4c23ab84a14f..d42667951608 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -326,7 +326,7 @@ public class ZenModeHelper { public String addAutomaticZenRule(String pkg, AutomaticZenRule automaticZenRule, String reason) { - if (!ZenModeConfig.SYSTEM_AUTHORITY.equals(pkg)) { + if (!isSystemRule(automaticZenRule)) { PackageItemInfo component = getServiceInfo(automaticZenRule.getOwner()); if (component == null) { component = getActivityInfo(automaticZenRule.getConfigurationActivity()); @@ -582,6 +582,11 @@ public class ZenModeHelper { } } + private boolean isSystemRule(AutomaticZenRule rule) { + return rule.getOwner() != null + && ZenModeConfig.SYSTEM_AUTHORITY.equals(rule.getOwner().getPackageName()); + } + private ServiceInfo getServiceInfo(ComponentName owner) { Intent queryIntent = new Intent(); queryIntent.setComponent(owner); diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 37bfbb11948a..06458d1bf50c 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -366,6 +366,14 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @GuardedBy("mLock") private boolean mStageDirInUse = false; + /** + * True if the installation is already in progress. This is used to prevent the caller + * from {@link #commit(IntentSender, boolean) committing} the session again while the + * installation is still in progress. + */ + @GuardedBy("mLock") + private boolean mInstallationInProgress = false; + /** Permissions have been accepted by the user (see {@link #setPermissionsResult}) */ @GuardedBy("mLock") private boolean mPermissionsManuallyAccepted = false; @@ -1661,6 +1669,14 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } + synchronized (mLock) { + if (mInstallationInProgress) { + throw new IllegalStateException("Installation is already in progress. Don't " + + "commit session=" + sessionId + " again."); + } + mInstallationInProgress = true; + } + dispatchSessionSealed(); } diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 7437b145189f..cfd029346340 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -456,19 +456,24 @@ public final class Settings implements Watchable, Snappable { // The user's preferred activities associated with particular intent // filters. @Watched - private final WatchedSparseArray<PreferredIntentResolver> - mPreferredActivities = new WatchedSparseArray<>(); + private final WatchedSparseArray<PreferredIntentResolver> mPreferredActivities; + private final SnapshotCache<WatchedSparseArray<PreferredIntentResolver>> + mPreferredActivitiesSnapshot; // The persistent preferred activities of the user's profile/device owner // associated with particular intent filters. @Watched private final WatchedSparseArray<PersistentPreferredIntentResolver> - mPersistentPreferredActivities = new WatchedSparseArray<>(); + mPersistentPreferredActivities; + private final SnapshotCache<WatchedSparseArray<PersistentPreferredIntentResolver>> + mPersistentPreferredActivitiesSnapshot; + // For every user, it is used to find to which other users the intent can be forwarded. @Watched - private final WatchedSparseArray<CrossProfileIntentResolver> - mCrossProfileIntentResolvers = new WatchedSparseArray<>(); + private final WatchedSparseArray<CrossProfileIntentResolver> mCrossProfileIntentResolvers; + private final SnapshotCache<WatchedSparseArray<CrossProfileIntentResolver>> + mCrossProfileIntentResolversSnapshot; @Watched final WatchedArrayMap<String, SharedUserSetting> mSharedUsers = new WatchedArrayMap<>(); @@ -477,11 +482,12 @@ public final class Settings implements Watchable, Snappable { // For reading/writing settings file. @Watched - private final WatchedArrayList<Signature> mPastSignatures = - new WatchedArrayList<Signature>(); + private final WatchedArrayList<Signature> mPastSignatures; + private final SnapshotCache<WatchedArrayList<Signature>> mPastSignaturesSnapshot; + @Watched - private final WatchedArrayMap<Long, Integer> mKeySetRefs = - new WatchedArrayMap<Long, Integer>(); + private final WatchedArrayMap<Long, Integer> mKeySetRefs; + private final SnapshotCache<WatchedArrayMap<Long, Integer>> mKeySetRefsSnapshot; // Packages that have been renamed since they were first installed. // Keys are the new names of the packages, values are the original @@ -512,7 +518,8 @@ public final class Settings implements Watchable, Snappable { * scanning to make it less confusing. */ @Watched - private final WatchedArrayList<PackageSetting> mPendingPackages = new WatchedArrayList<>(); + private final WatchedArrayList<PackageSetting> mPendingPackages; + private final SnapshotCache<WatchedArrayList<PackageSetting>> mPendingPackagesSnapshot; private final File mSystemDir; @@ -584,6 +591,26 @@ public final class Settings implements Watchable, Snappable { mInstallerPackagesSnapshot = new SnapshotCache.Auto<>(mInstallerPackages, mInstallerPackages, "Settings.mInstallerPackages"); + mPreferredActivities = new WatchedSparseArray<>(); + mPreferredActivitiesSnapshot = new SnapshotCache.Auto<>(mPreferredActivities, + mPreferredActivities, "Settings.mPreferredActivities"); + mPersistentPreferredActivities = new WatchedSparseArray<>(); + mPersistentPreferredActivitiesSnapshot = new SnapshotCache.Auto<>( + mPersistentPreferredActivities, mPersistentPreferredActivities, + "Settings.mPersistentPreferredActivities"); + mCrossProfileIntentResolvers = new WatchedSparseArray<>(); + mCrossProfileIntentResolversSnapshot = new SnapshotCache.Auto<>( + mCrossProfileIntentResolvers, mCrossProfileIntentResolvers, + "Settings.mCrossProfileIntentResolvers"); + mPastSignatures = new WatchedArrayList<>(); + mPastSignaturesSnapshot = new SnapshotCache.Auto<>(mPastSignatures, mPastSignatures, + "Settings.mPastSignatures"); + mKeySetRefs = new WatchedArrayMap<>(); + mKeySetRefsSnapshot = new SnapshotCache.Auto<>(mKeySetRefs, mKeySetRefs, + "Settings.mKeySetRefs"); + mPendingPackages = new WatchedArrayList<>(); + mPendingPackagesSnapshot = new SnapshotCache.Auto<>(mPendingPackages, mPendingPackages, + "Settings.mPendingPackages"); mKeySetManagerService = new KeySetManagerService(mPackages); // Test-only handler working on background thread. @@ -624,6 +651,26 @@ public final class Settings implements Watchable, Snappable { mInstallerPackagesSnapshot = new SnapshotCache.Auto<>(mInstallerPackages, mInstallerPackages, "Settings.mInstallerPackages"); + mPreferredActivities = new WatchedSparseArray<>(); + mPreferredActivitiesSnapshot = new SnapshotCache.Auto<>(mPreferredActivities, + mPreferredActivities, "Settings.mPreferredActivities"); + mPersistentPreferredActivities = new WatchedSparseArray<>(); + mPersistentPreferredActivitiesSnapshot = new SnapshotCache.Auto<>( + mPersistentPreferredActivities, mPersistentPreferredActivities, + "Settings.mPersistentPreferredActivities"); + mCrossProfileIntentResolvers = new WatchedSparseArray<>(); + mCrossProfileIntentResolversSnapshot = new SnapshotCache.Auto<>( + mCrossProfileIntentResolvers, mCrossProfileIntentResolvers, + "Settings.mCrossProfileIntentResolvers"); + mPastSignatures = new WatchedArrayList<>(); + mPastSignaturesSnapshot = new SnapshotCache.Auto<>(mPastSignatures, mPastSignatures, + "Settings.mPastSignatures"); + mKeySetRefs = new WatchedArrayMap<>(); + mKeySetRefsSnapshot = new SnapshotCache.Auto<>(mKeySetRefs, mKeySetRefs, + "Settings.mKeySetRefs"); + mPendingPackages = new WatchedArrayList<>(); + mPendingPackagesSnapshot = new SnapshotCache.Auto<>(mPendingPackages, mPendingPackages, + "Settings.mPendingPackages"); mKeySetManagerService = new KeySetManagerService(mPackages); mHandler = handler; @@ -700,24 +747,27 @@ public final class Settings implements Watchable, Snappable { mBlockUninstallPackages.snapshot(r.mBlockUninstallPackages); mVersion.putAll(r.mVersion); mVerifierDeviceIdentity = r.mVerifierDeviceIdentity; - WatchedSparseArray.snapshot( - mPreferredActivities, r.mPreferredActivities); - WatchedSparseArray.snapshot( - mPersistentPreferredActivities, r.mPersistentPreferredActivities); - WatchedSparseArray.snapshot( - mCrossProfileIntentResolvers, r.mCrossProfileIntentResolvers); + mPreferredActivities = r.mPreferredActivitiesSnapshot.snapshot(); + mPreferredActivitiesSnapshot = new SnapshotCache.Sealed<>(); + mPersistentPreferredActivities = r.mPersistentPreferredActivitiesSnapshot.snapshot(); + mPersistentPreferredActivitiesSnapshot = new SnapshotCache.Sealed<>(); + mCrossProfileIntentResolvers = r.mCrossProfileIntentResolversSnapshot.snapshot(); + mCrossProfileIntentResolversSnapshot = new SnapshotCache.Sealed<>(); + mSharedUsers.snapshot(r.mSharedUsers); mAppIds = r.mAppIds.snapshot(); - WatchedArrayList.snapshot( - mPastSignatures, r.mPastSignatures); - WatchedArrayMap.snapshot( - mKeySetRefs, r.mKeySetRefs); + + mPastSignatures = r.mPastSignaturesSnapshot.snapshot(); + mPastSignaturesSnapshot = new SnapshotCache.Sealed<>(); + mKeySetRefs = r.mKeySetRefsSnapshot.snapshot(); + mKeySetRefsSnapshot = new SnapshotCache.Sealed<>(); + mRenamedPackages.snapshot(r.mRenamedPackages); mNextAppLinkGeneration.snapshot(r.mNextAppLinkGeneration); mDefaultBrowserApp.snapshot(r.mDefaultBrowserApp); // mReadMessages - WatchedArrayList.snapshot( - mPendingPackages, r.mPendingPackages); + mPendingPackages = r.mPendingPackagesSnapshot.snapshot(); + mPendingPackagesSnapshot = new SnapshotCache.Sealed<>(); mSystemDir = null; // mKeySetManagerService; mPermissions = r.mPermissions; diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index fa0d41c5ac2f..352d4be6c7ce 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -256,6 +256,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { static final int SHORT_PRESS_POWER_GO_HOME = 4; static final int SHORT_PRESS_POWER_CLOSE_IME_OR_GO_HOME = 5; static final int SHORT_PRESS_POWER_LOCK_OR_SLEEP = 6; + static final int SHORT_PRESS_POWER_DREAM_OR_SLEEP = 7; // must match: config_LongPressOnPowerBehavior in config.xml static final int LONG_PRESS_POWER_NOTHING = 0; @@ -971,7 +972,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { powerMultiPressAction(eventTime, interactive, mTriplePressOnPowerBehavior); } else if (count > 3 && count <= getMaxMultiPressPowerCount()) { Slog.d(TAG, "No behavior defined for power press count " + count); - } else if (count == 1 && interactive && !beganFromNonInteractive) { + } else if (count == 1 && interactive) { + if (beganFromNonInteractive) { + // The screen off case, where we might want to start dreaming on power button press. + attemptToDreamFromShortPowerButtonPress(false, () -> {}); + return; + } if (mSideFpsEventHandler.shouldConsumeSinglePress(eventTime)) { Slog.i(TAG, "Suppressing power key because the user is interacting with the " + "fingerprint sensor"); @@ -1020,11 +1026,39 @@ public class PhoneWindowManager implements WindowManagerPolicy { } break; } + case SHORT_PRESS_POWER_DREAM_OR_SLEEP: { + attemptToDreamFromShortPowerButtonPress( + true, + () -> sleepDefaultDisplayFromPowerButton(eventTime, 0)); + break; + } } } } /** + * Attempt to dream from a power button press. + * + * @param isScreenOn Whether the screen is currently on. + * @param noDreamAction The action to perform if dreaming is not possible. + */ + private void attemptToDreamFromShortPowerButtonPress( + boolean isScreenOn, Runnable noDreamAction) { + if (mShortPressOnPowerBehavior != SHORT_PRESS_POWER_DREAM_OR_SLEEP) { + noDreamAction.run(); + return; + } + + final DreamManagerInternal dreamManagerInternal = getDreamManagerInternal(); + if (dreamManagerInternal == null || !dreamManagerInternal.canStartDreaming(isScreenOn)) { + noDreamAction.run(); + return; + } + + dreamManagerInternal.requestDream(); + } + + /** * Sends the default display to sleep as a result of a power button press. * * @return {@code true} if the device was sent to sleep, {@code false} if the device did not @@ -1595,7 +1629,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { // If there's a dream running then use home to escape the dream // but don't actually go home. - if (mDreamManagerInternal != null && mDreamManagerInternal.isDreaming()) { + final DreamManagerInternal dreamManagerInternal = getDreamManagerInternal(); + if (dreamManagerInternal != null && dreamManagerInternal.isDreaming()) { mDreamManagerInternal.stopDream(false /*immediate*/, "short press on home" /*reason*/); return; } @@ -2483,6 +2518,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } + private DreamManagerInternal getDreamManagerInternal() { + if (mDreamManagerInternal == null) { + // If mDreamManagerInternal is null, attempt to re-fetch it. + mDreamManagerInternal = LocalServices.getService(DreamManagerInternal.class); + } + + return mDreamManagerInternal; + } + private void updateWakeGestureListenerLp() { if (shouldEnableWakeGestureLp()) { mWakeGestureListener.requestWakeUpTrigger(); diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index e86f34bb5d84..ccab96888e8f 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -496,7 +496,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A /** The most recently given options. */ private ActivityOptions mPendingOptions; /** Non-null if {@link #mPendingOptions} specifies the remote animation. */ - private RemoteAnimationAdapter mPendingRemoteAnimation; + RemoteAnimationAdapter mPendingRemoteAnimation; private RemoteTransition mPendingRemoteTransition; ActivityOptions returningOptions; // options that are coming back via convertToTranslucent AppTimeTracker appTimeTracker; // set if we are tracking the time in this app/task/activity diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 027d485d15a0..dc69ca6bc0cf 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -2947,10 +2947,14 @@ class ActivityStarter { } } - // Update the target's launch cookie to those specified in the options if set + // Update the target's launch cookie and pending remote animation to those specified in the + // options if set. if (mStartActivity.mLaunchCookie != null) { intentActivity.mLaunchCookie = mStartActivity.mLaunchCookie; } + if (mStartActivity.mPendingRemoteAnimation != null) { + intentActivity.mPendingRemoteAnimation = mStartActivity.mPendingRemoteAnimation; + } // Need to update mTargetRootTask because if task was moved out of it, the original root // task may be destroyed. @@ -3033,7 +3037,12 @@ class ActivityStarter { newParent = candidateTf; } } - newParent.mTransitionController.collect(newParent); + if (newParent.asTask() == null) { + // only collect task-fragments. + // TODO(b/258095975): we probably shouldn't ever collect the parent here since it isn't + // changing. The logic that changes it should collect it. + newParent.mTransitionController.collect(newParent); + } if (mStartActivity.getTaskFragment() == null || mStartActivity.getTaskFragment() == newParent) { newParent.addChild(mStartActivity, POSITION_TOP); diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java index e7b62b0d66d3..2792f4265caa 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java @@ -287,8 +287,10 @@ public abstract class ActivityTaskManagerInternal { /** * Called when the device changes its dreaming state. + * + * @param activeDreamComponent The currently active dream. If null, the device is not dreaming. */ - public abstract void notifyDreamStateChanged(boolean dreaming); + public abstract void notifyActiveDreamChanged(@Nullable ComponentName activeDreamComponent); /** * Set a uid that is allowed to bypass stopped app switches, launching an app diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 0398cc84f9db..1ba7e687a553 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -208,7 +208,6 @@ import android.os.UserManager; import android.os.WorkSource; import android.provider.Settings; import android.service.dreams.DreamActivity; -import android.service.dreams.DreamManagerInternal; import android.service.voice.IVoiceInteractionSession; import android.service.voice.VoiceInteractionManagerInternal; import android.sysprop.DisplayProperties; @@ -669,11 +668,12 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { private volatile boolean mSleeping; /** - * The mDreaming state is set by the {@link DreamManagerService} when it receives a request to - * start/stop the dream. It is set to true shortly before the {@link DreamService} is started. - * It is set to false after the {@link DreamService} is stopped. + * The mActiveDreamComponent state is set by the {@link DreamManagerService} when it receives a + * request to start/stop the dream. It is set to the active dream shortly before the + * {@link DreamService} is started. It is set to null after the {@link DreamService} is stopped. */ - private volatile boolean mDreaming; + @Nullable + private volatile ComponentName mActiveDreamComponent; /** * The process state used for processes that are running the top activities. @@ -1442,31 +1442,21 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } boolean isDreaming() { - return mDreaming; + return mActiveDreamComponent != null; } boolean canLaunchDreamActivity(String packageName) { - if (!mDreaming || packageName == null) { + if (mActiveDreamComponent == null || packageName == null) { ProtoLog.e(WM_DEBUG_DREAM, "Cannot launch dream activity due to invalid state. " - + "dreaming: %b packageName: %s", mDreaming, packageName); + + "dream component: %s packageName: %s", mActiveDreamComponent, packageName); return false; } - final DreamManagerInternal dreamManager = - LocalServices.getService(DreamManagerInternal.class); - // Verify that the package is the current active dream or doze component. The - // getActiveDreamComponent() call path does not acquire the DreamManager lock and thus - // is safe to use. - final ComponentName activeDream = dreamManager.getActiveDreamComponent(false /* doze */); - if (activeDream != null && packageName.equals(activeDream.getPackageName())) { - return true; - } - final ComponentName activeDoze = dreamManager.getActiveDreamComponent(true /* doze */); - if (activeDoze != null && packageName.equals(activeDoze.getPackageName())) { + if (packageName.equals(mActiveDreamComponent.getPackageName())) { return true; } ProtoLog.e(WM_DEBUG_DREAM, - "Dream packageName does not match active dream. Package %s does not match %s or %s", - packageName, String.valueOf(activeDream), String.valueOf(activeDoze)); + "Dream packageName does not match active dream. Package %s does not match %s", + packageName, String.valueOf(mActiveDreamComponent)); return false; } @@ -5676,9 +5666,9 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } @Override - public void notifyDreamStateChanged(boolean dreaming) { + public void notifyActiveDreamChanged(@Nullable ComponentName dreamComponent) { synchronized (mGlobalLock) { - mDreaming = dreaming; + mActiveDreamComponent = dreamComponent; } } diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java index 671524b39bc1..12133bc06df8 100644 --- a/services/core/java/com/android/server/wm/AppTransitionController.java +++ b/services/core/java/com/android/server/wm/AppTransitionController.java @@ -80,7 +80,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import android.annotation.IntDef; -import android.annotation.NonNull; import android.annotation.Nullable; import android.graphics.Rect; import android.os.Trace; @@ -172,16 +171,6 @@ public class AppTransitionController { ? null : wallpaperTarget; } - @NonNull - private static ArraySet<ActivityRecord> getAppsForAnimation( - @NonNull ArraySet<ActivityRecord> apps, boolean excludeLauncherFromAnimation) { - final ArraySet<ActivityRecord> appsForAnimation = new ArraySet<>(apps); - if (excludeLauncherFromAnimation) { - appsForAnimation.removeIf(ConfigurationContainer::isActivityTypeHome); - } - return appsForAnimation; - } - /** * Handle application transition for given display. */ @@ -231,45 +220,32 @@ public class AppTransitionController { mWallpaperControllerLocked.adjustWallpaperWindowsForAppTransitionIfNeeded( mDisplayContent.mOpeningApps); - // Remove launcher from app transition animation while recents is running. Recents animation - // is managed outside of app transition framework, so we just need to commit visibility. - final boolean excludeLauncherFromAnimation = - mDisplayContent.mOpeningApps.stream().anyMatch( - (app) -> app.isAnimating(PARENTS, ANIMATION_TYPE_RECENTS)) - || mDisplayContent.mClosingApps.stream().anyMatch( - (app) -> app.isAnimating(PARENTS, ANIMATION_TYPE_RECENTS)); - final ArraySet<ActivityRecord> openingAppsForAnimation = getAppsForAnimation( - mDisplayContent.mOpeningApps, excludeLauncherFromAnimation); - final ArraySet<ActivityRecord> closingAppsForAnimation = getAppsForAnimation( - mDisplayContent.mClosingApps, excludeLauncherFromAnimation); - @TransitionOldType final int transit = getTransitCompatType( - mDisplayContent.mAppTransition, openingAppsForAnimation, closingAppsForAnimation, - mDisplayContent.mChangingContainers, + mDisplayContent.mAppTransition, mDisplayContent.mOpeningApps, + mDisplayContent.mClosingApps, mDisplayContent.mChangingContainers, mWallpaperControllerLocked.getWallpaperTarget(), getOldWallpaper(), mDisplayContent.mSkipAppTransitionAnimation); mDisplayContent.mSkipAppTransitionAnimation = false; ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "handleAppTransitionReady: displayId=%d appTransition={%s}" - + " excludeLauncherFromAnimation=%b openingApps=[%s] closingApps=[%s] transit=%s", - mDisplayContent.mDisplayId, appTransition.toString(), excludeLauncherFromAnimation, - mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, - AppTransition.appTransitionOldToString(transit)); + + " openingApps=[%s] closingApps=[%s] transit=%s", + mDisplayContent.mDisplayId, appTransition.toString(), mDisplayContent.mOpeningApps, + mDisplayContent.mClosingApps, AppTransition.appTransitionOldToString(transit)); // Find the layout params of the top-most application window in the tokens, which is // what will control the animation theme. If all closing windows are obscured, then there is // no need to do an animation. This is the case, for example, when this transition is being // done behind a dream window. - final ArraySet<Integer> activityTypes = collectActivityTypes(openingAppsForAnimation, - closingAppsForAnimation, mDisplayContent.mChangingContainers); + final ArraySet<Integer> activityTypes = collectActivityTypes(mDisplayContent.mOpeningApps, + mDisplayContent.mClosingApps, mDisplayContent.mChangingContainers); final ActivityRecord animLpActivity = findAnimLayoutParamsToken(transit, activityTypes, - openingAppsForAnimation, closingAppsForAnimation, + mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, mDisplayContent.mChangingContainers); final ActivityRecord topOpeningApp = - getTopApp(openingAppsForAnimation, false /* ignoreHidden */); + getTopApp(mDisplayContent.mOpeningApps, false /* ignoreHidden */); final ActivityRecord topClosingApp = - getTopApp(closingAppsForAnimation, false /* ignoreHidden */); + getTopApp(mDisplayContent.mClosingApps, false /* ignoreHidden */); final ActivityRecord topChangingApp = getTopApp(mDisplayContent.mChangingContainers, false /* ignoreHidden */); final WindowManager.LayoutParams animLp = getAnimLp(animLpActivity); @@ -281,14 +257,14 @@ public class AppTransitionController { overrideWithRemoteAnimationIfSet(animLpActivity, transit, activityTypes); } - final boolean voiceInteraction = containsVoiceInteraction(closingAppsForAnimation) - || containsVoiceInteraction(openingAppsForAnimation); + final boolean voiceInteraction = containsVoiceInteraction(mDisplayContent.mClosingApps) + || containsVoiceInteraction(mDisplayContent.mOpeningApps); final int layoutRedo; mService.mSurfaceAnimationRunner.deferStartingAnimations(); try { - applyAnimations(openingAppsForAnimation, closingAppsForAnimation, transit, animLp, - voiceInteraction); + applyAnimations(mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, transit, + animLp, voiceInteraction); handleClosingApps(); handleOpeningApps(); handleChangingApps(transit); @@ -300,8 +276,8 @@ public class AppTransitionController { layoutRedo = appTransition.goodToGo(transit, topOpeningApp); handleNonAppWindowsInTransition(transit, flags); appTransition.postAnimationCallback(); - appTransition.clear(); } finally { + appTransition.clear(); mService.mSurfaceAnimationRunner.continueStartingAnimations(); } @@ -1226,6 +1202,11 @@ public class AppTransitionController { if (activity == null) { continue; } + if (activity.isAnimating(PARENTS, ANIMATION_TYPE_RECENTS)) { + ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, + "Delaying app transition for recents animation to finish"); + return false; + } ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Check opening app=%s: allDrawn=%b startingDisplayed=%b " + "startingMoved=%b isRelaunching()=%b startingWindow=%s", diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java index 879c7e2d75dc..377c5b41fe35 100644 --- a/services/core/java/com/android/server/wm/TaskFragment.java +++ b/services/core/java/com/android/server/wm/TaskFragment.java @@ -2336,6 +2336,11 @@ class TaskFragment extends WindowContainer<WindowContainer> { if (mTaskFragmentOrganizer != null && (mLastSurfaceSize.x != 0 || mLastSurfaceSize.y != 0)) { t.setWindowCrop(mSurfaceControl, 0, 0); + final SurfaceControl.Transaction syncTransaction = getSyncTransaction(); + if (t != syncTransaction) { + // Avoid restoring to old window crop if the sync transaction is applied later. + syncTransaction.setWindowCrop(mSurfaceControl, 0, 0); + } mLastSurfaceSize.set(0, 0); } } diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index 65c497cded0c..fa1bc5454018 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -3271,9 +3271,10 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< void resetSurfacePositionForAnimationLeash(Transaction t) { t.setPosition(mSurfaceControl, 0, 0); - if (mSyncState != SYNC_STATE_NONE && t != mSyncTransaction) { + final SurfaceControl.Transaction syncTransaction = getSyncTransaction(); + if (t != syncTransaction) { // Avoid restoring to old position if the sync transaction is applied later. - mSyncTransaction.setPosition(mSurfaceControl, 0, 0); + syncTransaction.setPosition(mSurfaceControl, 0, 0); } mLastSurfacePosition.set(0, 0); } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index d4c1abfa8d24..a42cec9c06fb 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -6113,8 +6113,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP if (mRedrawForSyncReported) { return false; } - // TODO(b/233286785): Remove mIsWallpaper once WallpaperService handles syncId of relayout. - if (mInRelayout && !mIsWallpaper) { + if (mInRelayout && mPrepareSyncSeqId > 0) { // The last sync seq id will return to the client, so there is no need to request the // client to redraw. return false; diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java index cd4af0a581f8..666d4010e921 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java @@ -372,6 +372,7 @@ public class FingerprintAuthenticationClientTest { @Test public void fingerprintPowerIgnoresAuthInWindow() throws Exception { when(mSensorProps.isAnySidefpsType()).thenReturn(true); + when(mHal.authenticate(anyLong())).thenReturn(mCancellationSignal); final FingerprintAuthenticationClient client = createClient(1); client.start(mCallback); @@ -382,11 +383,13 @@ public class FingerprintAuthenticationClientTest { mLooper.dispatchAll(); verify(mCallback).onClientFinished(any(), eq(false)); + verify(mCancellationSignal).cancel(); } @Test public void fingerprintAuthIgnoredWaitingForPower() throws Exception { when(mSensorProps.isAnySidefpsType()).thenReturn(true); + when(mHal.authenticate(anyLong())).thenReturn(mCancellationSignal); final FingerprintAuthenticationClient client = createClient(1); client.start(mCallback); @@ -397,11 +400,13 @@ public class FingerprintAuthenticationClientTest { mLooper.dispatchAll(); verify(mCallback).onClientFinished(any(), eq(false)); + verify(mCancellationSignal).cancel(); } @Test - public void fingerprintAuthSucceedsAfterPowerWindow() throws Exception { + public void fingerprintAuthFailsWhenAuthAfterPower() throws Exception { when(mSensorProps.isAnySidefpsType()).thenReturn(true); + when(mHal.authenticate(anyLong())).thenReturn(mCancellationSignal); final FingerprintAuthenticationClient client = createClient(1); client.start(mCallback); @@ -415,7 +420,9 @@ public class FingerprintAuthenticationClientTest { mLooper.moveTimeForward(1000); mLooper.dispatchAll(); - verify(mCallback).onClientFinished(any(), eq(true)); + verify(mCallback, never()).onClientFinished(any(), eq(true)); + verify(mCallback).onClientFinished(any(), eq(false)); + when(mHal.authenticateWithContext(anyLong(), any())).thenReturn(mCancellationSignal); } @Test diff --git a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java index cc68ba88f76e..2094c9345fa2 100644 --- a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java +++ b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java @@ -22,6 +22,8 @@ import static android.view.Display.DEFAULT_DISPLAY_GROUP; import static com.android.server.display.DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED; import static com.android.server.display.DisplayAdapter.DISPLAY_DEVICE_EVENT_CHANGED; import static com.android.server.display.DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED; +import static com.android.server.display.LogicalDisplay.DISPLAY_PHASE_DISABLED; +import static com.android.server.display.LogicalDisplay.DISPLAY_PHASE_ENABLED; import static com.android.server.display.LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_ADDED; import static com.android.server.display.LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_REMOVED; @@ -53,6 +55,8 @@ import android.view.DisplayInfo; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.server.display.layout.Layout; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -85,6 +89,7 @@ public class LogicalDisplayMapperTest { @Mock Resources mResourcesMock; @Mock IPowerManager mIPowerManagerMock; @Mock IThermalService mIThermalServiceMock; + @Mock DeviceStateToLayoutMap mDeviceStateToLayoutMapMock; @Captor ArgumentCaptor<LogicalDisplay> mDisplayCaptor; @@ -130,11 +135,13 @@ public class LogicalDisplayMapperTest { when(mResourcesMock.getIntArray( com.android.internal.R.array.config_deviceStatesOnWhichToSleep)) .thenReturn(new int[]{0}); + when(mDeviceStateToLayoutMapMock.get(-1)).thenReturn(new Layout()); mLooper = new TestLooper(); mHandler = new Handler(mLooper.getLooper()); mLogicalDisplayMapper = new LogicalDisplayMapper(mContextMock, mDisplayDeviceRepo, - mListenerMock, new DisplayManagerService.SyncRoot(), mHandler); + mListenerMock, new DisplayManagerService.SyncRoot(), mHandler, + mDeviceStateToLayoutMapMock); } @@ -413,6 +420,58 @@ public class LogicalDisplayMapperTest { /* isBootCompleted= */true)); } + @Test + public void testDeviceStateLocked() { + DisplayDevice device1 = createDisplayDevice(Display.TYPE_INTERNAL, 600, 800, + DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY); + DisplayDevice device2 = createDisplayDevice(Display.TYPE_INTERNAL, 600, 800, + DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY); + + Layout layout = new Layout(); + layout.createDisplayLocked(device1.getDisplayDeviceInfoLocked().address, true, true); + layout.createDisplayLocked(device2.getDisplayDeviceInfoLocked().address, false, false); + when(mDeviceStateToLayoutMapMock.get(0)).thenReturn(layout); + + layout = new Layout(); + layout.createDisplayLocked(device1.getDisplayDeviceInfoLocked().address, false, false); + layout.createDisplayLocked(device2.getDisplayDeviceInfoLocked().address, true, true); + when(mDeviceStateToLayoutMapMock.get(1)).thenReturn(layout); + when(mDeviceStateToLayoutMapMock.get(2)).thenReturn(layout); + + LogicalDisplay display1 = add(device1); + assertEquals(info(display1).address, info(device1).address); + assertEquals(DEFAULT_DISPLAY, id(display1)); + + LogicalDisplay display2 = add(device2); + assertEquals(info(display2).address, info(device2).address); + // We can only have one default display + assertEquals(DEFAULT_DISPLAY, id(display1)); + + mLogicalDisplayMapper.setDeviceStateLocked(0, false); + mLooper.moveTimeForward(1000); + mLooper.dispatchAll(); + assertEquals(DISPLAY_PHASE_ENABLED, + mLogicalDisplayMapper.getDisplayLocked(device1).getPhase()); + assertEquals(DISPLAY_PHASE_DISABLED, + mLogicalDisplayMapper.getDisplayLocked(device2).getPhase()); + + mLogicalDisplayMapper.setDeviceStateLocked(1, false); + mLooper.moveTimeForward(1000); + mLooper.dispatchAll(); + assertEquals(DISPLAY_PHASE_DISABLED, + mLogicalDisplayMapper.getDisplayLocked(device1).getPhase()); + assertEquals(DISPLAY_PHASE_ENABLED, + mLogicalDisplayMapper.getDisplayLocked(device2).getPhase()); + + mLogicalDisplayMapper.setDeviceStateLocked(2, false); + mLooper.moveTimeForward(1000); + mLooper.dispatchAll(); + assertEquals(DISPLAY_PHASE_DISABLED, + mLogicalDisplayMapper.getDisplayLocked(device1).getPhase()); + assertEquals(DISPLAY_PHASE_ENABLED, + mLogicalDisplayMapper.getDisplayLocked(device2).getPhase()); + } + ///////////////// // Helper Methods ///////////////// diff --git a/services/tests/servicestests/src/com/android/server/job/WorkTypeConfigTest.java b/services/tests/servicestests/src/com/android/server/job/WorkTypeConfigTest.java index a5fedef23e00..21d27848bc57 100644 --- a/services/tests/servicestests/src/com/android/server/job/WorkTypeConfigTest.java +++ b/services/tests/servicestests/src/com/android/server/job/WorkTypeConfigTest.java @@ -36,7 +36,6 @@ import androidx.test.runner.AndroidJUnit4; import com.android.server.job.JobConcurrencyManager.WorkTypeConfig; -import org.junit.After; import org.junit.Test; import org.junit.runner.RunWith; @@ -59,30 +58,6 @@ public class WorkTypeConfigTest { private static final String KEY_MIN_BGUSER_IMPORTANT = "concurrency_min_bguser_important_test"; private static final String KEY_MIN_BGUSER = "concurrency_min_bguser_test"; - @After - public void tearDown() throws Exception { - resetConfig(); - } - - private void resetConfig() { - // DeviceConfig.resetToDefaults() doesn't work here. Need to reset constants manually. - DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_TOTAL, null, false); - DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_TOP, null, false); - DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_FGS, null, false); - DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_EJ, null, false); - DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_BG, null, false); - DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, - KEY_MAX_BGUSER_IMPORTANT, null, false); - DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_BGUSER, null, false); - DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MIN_TOP, null, false); - DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MIN_FGS, null, false); - DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MIN_EJ, null, false); - DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MIN_BG, null, false); - DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, - KEY_MIN_BGUSER_IMPORTANT, null, false); - DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MIN_BGUSER, null, false); - } - private void check(@Nullable DeviceConfig.Properties config, int defaultTotal, @NonNull List<Pair<Integer, Integer>> defaultMin, @@ -90,10 +65,6 @@ public class WorkTypeConfigTest { boolean expectedValid, int expectedTotal, @NonNull List<Pair<Integer, Integer>> expectedMinLimits, @NonNull List<Pair<Integer, Integer>> expectedMaxLimits) throws Exception { - resetConfig(); - if (config != null) { - DeviceConfig.setProperties(config); - } final WorkTypeConfig counts; try { @@ -112,7 +83,9 @@ public class WorkTypeConfigTest { } } - counts.update(DeviceConfig.getProperties(DeviceConfig.NAMESPACE_JOB_SCHEDULER)); + if (config != null) { + counts.update(config); + } assertEquals(expectedTotal, counts.getMaxTotal()); for (Pair<Integer, Integer> min : expectedMinLimits) { diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index beaa6e066d7d..7df4b57b6cf8 100755 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -7549,43 +7549,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test - public void testAddAutomaticZenRule_systemCallTakesPackageFromOwner() throws Exception { - mService.isSystemUid = true; - ZenModeHelper mockZenModeHelper = mock(ZenModeHelper.class); - when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) - .thenReturn(true); - mService.setZenHelper(mockZenModeHelper); - ComponentName owner = new ComponentName("android", "ProviderName"); - ZenPolicy zenPolicy = new ZenPolicy.Builder().allowAlarms(true).build(); - boolean isEnabled = true; - AutomaticZenRule rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class), - zenPolicy, NotificationManager.INTERRUPTION_FILTER_PRIORITY, isEnabled); - mBinderService.addAutomaticZenRule(rule, "com.android.settings"); - - // verify that zen mode helper gets passed in a package name of "android" - verify(mockZenModeHelper).addAutomaticZenRule(eq("android"), eq(rule), anyString()); - } - - @Test - public void testAddAutomaticZenRule_nonSystemCallTakesPackageFromArg() throws Exception { - mService.isSystemUid = false; - ZenModeHelper mockZenModeHelper = mock(ZenModeHelper.class); - when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) - .thenReturn(true); - mService.setZenHelper(mockZenModeHelper); - ComponentName owner = new ComponentName("android", "ProviderName"); - ZenPolicy zenPolicy = new ZenPolicy.Builder().allowAlarms(true).build(); - boolean isEnabled = true; - AutomaticZenRule rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class), - zenPolicy, NotificationManager.INTERRUPTION_FILTER_PRIORITY, isEnabled); - mBinderService.addAutomaticZenRule(rule, "another.package"); - - // verify that zen mode helper gets passed in the package name from the arg, not the owner - verify(mockZenModeHelper).addAutomaticZenRule( - eq("another.package"), eq(rule), anyString()); - } - - @Test public void testAreNotificationsEnabledForPackage() throws Exception { mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(), mUid); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java index 2ccdcaace8bf..4550b56f6fd0 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java @@ -1672,36 +1672,6 @@ public class ZenModeHelperTest extends UiServiceTestCase { } @Test - public void testAddAutomaticZenRule_claimedSystemOwner() { - // Make sure anything that claims to have a "system" owner but not actually part of the - // system package still gets limited on number of rules - for (int i = 0; i < RULE_LIMIT_PER_PACKAGE; i++) { - ScheduleInfo si = new ScheduleInfo(); - si.startHour = i; - AutomaticZenRule zenRule = new AutomaticZenRule("name" + i, - new ComponentName("android", "ScheduleConditionProvider" + i), - null, // configuration activity - ZenModeConfig.toScheduleConditionId(si), - new ZenPolicy.Builder().build(), - NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); - String id = mZenModeHelperSpy.addAutomaticZenRule("pkgname", zenRule, "test"); - assertNotNull(id); - } - try { - AutomaticZenRule zenRule = new AutomaticZenRule("name", - new ComponentName("android", "ScheduleConditionProviderFinal"), - null, // configuration activity - ZenModeConfig.toScheduleConditionId(new ScheduleInfo()), - new ZenPolicy.Builder().build(), - NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); - String id = mZenModeHelperSpy.addAutomaticZenRule("pkgname", zenRule, "test"); - fail("allowed too many rules to be created"); - } catch (IllegalArgumentException e) { - // yay - } - } - - @Test public void testAddAutomaticZenRule_CA() { AutomaticZenRule zenRule = new AutomaticZenRule("name", null, diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java index 00be7ed5bc6c..496f6817bb08 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java @@ -98,6 +98,7 @@ import android.service.voice.IVoiceInteractionSession; import android.util.Pair; import android.util.Size; import android.view.Gravity; +import android.view.RemoteAnimationAdapter; import android.window.TaskFragmentOrganizerToken; import androidx.test.filters.SmallTest; @@ -1315,6 +1316,32 @@ public class ActivityStarterTests extends WindowTestsBase { } @Test + public void testRemoteAnimation_appliesToExistingTask() { + final ActivityStarter starter = prepareStarter(0, false); + + // Put an activity on default display as the top focused activity. + ActivityRecord r = new ActivityBuilder(mAtm).setCreateTask(true).build(); + final Intent intent = new Intent(); + intent.setComponent(ActivityBuilder.getDefaultComponent()); + starter.setReason("testRemoteAnimation_newTask") + .setIntent(intent) + .execute(); + + assertNull(mRootWindowContainer.topRunningActivity().mPendingRemoteAnimation); + + // Relaunch the activity with remote animation indicated in options. + final RemoteAnimationAdapter adaptor = mock(RemoteAnimationAdapter.class); + final ActivityOptions options = ActivityOptions.makeRemoteAnimation(adaptor); + starter.setReason("testRemoteAnimation_existingTask") + .setIntent(intent) + .setActivityOptions(options.toBundle()) + .execute(); + + // Verify the remote animation is updated. + assertEquals(adaptor, mRootWindowContainer.topRunningActivity().mPendingRemoteAnimation); + } + + @Test public void testStartLaunchIntoPipActivity() { final ActivityStarter starter = prepareStarter(0, false); diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java index d55e53cca8a6..32c95fa7b6c7 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java @@ -16,8 +16,6 @@ package com.android.server.wm; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; -import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import static android.view.WindowManager.TRANSIT_CHANGE; @@ -27,7 +25,6 @@ import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY; import static android.view.WindowManager.TRANSIT_KEYGUARD_OCCLUDE; import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE; import static android.view.WindowManager.TRANSIT_NONE; -import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN; import static android.view.WindowManager.TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE; import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY; import static android.view.WindowManager.TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE; @@ -411,50 +408,38 @@ public class AppTransitionTests extends WindowTestsBase { } @Test - public void testExcludeLauncher() { + public void testDelayWhileRecents() { final DisplayContent dc = createNewDisplay(Display.STATE_ON); doReturn(false).when(dc).onDescendantOrientationChanged(any()); final Task task = createTask(dc); - // Simulate activity1 launches activity2 + // Simulate activity1 launches activity2. final ActivityRecord activity1 = createActivityRecord(task); activity1.setVisible(true); activity1.mVisibleRequested = false; activity1.allDrawn = true; - dc.mClosingApps.add(activity1); final ActivityRecord activity2 = createActivityRecord(task); activity2.setVisible(false); activity2.mVisibleRequested = true; activity2.allDrawn = true; + + dc.mClosingApps.add(activity1); dc.mOpeningApps.add(activity2); dc.prepareAppTransition(TRANSIT_OPEN); - - // Simulate start recents - final ActivityRecord homeActivity = createActivityRecord(dc, WINDOWING_MODE_FULLSCREEN, - ACTIVITY_TYPE_HOME); - homeActivity.setVisible(false); - homeActivity.mVisibleRequested = true; - homeActivity.allDrawn = true; - dc.mOpeningApps.add(homeActivity); - dc.prepareAppTransition(TRANSIT_NONE); - doReturn(true).when(task) - .isSelfAnimating(anyInt(), eq(ANIMATION_TYPE_RECENTS)); + assertTrue(dc.mAppTransition.containsTransitRequest(TRANSIT_OPEN)); // Wait until everything in animation handler get executed to prevent the exiting window // from being removed during WindowSurfacePlacer Traversal. waitUntilHandlersIdle(); + // Start recents + doReturn(true).when(task) + .isSelfAnimating(anyInt(), eq(ANIMATION_TYPE_RECENTS)); + dc.mAppTransitionController.handleAppTransitionReady(); - verify(activity1).commitVisibility(eq(false), anyBoolean(), anyBoolean()); - verify(activity1).applyAnimation(any(), eq(TRANSIT_OLD_ACTIVITY_OPEN), eq(false), - anyBoolean(), any()); - verify(activity2).commitVisibility(eq(true), anyBoolean(), anyBoolean()); - verify(activity2).applyAnimation(any(), eq(TRANSIT_OLD_ACTIVITY_OPEN), eq(true), - anyBoolean(), any()); - verify(homeActivity).commitVisibility(eq(true), anyBoolean(), anyBoolean()); - verify(homeActivity, never()).applyAnimation(any(), anyInt(), anyBoolean(), anyBoolean(), - any()); + verify(activity1, never()).commitVisibility(anyBoolean(), anyBoolean(), anyBoolean()); + verify(activity2, never()).commitVisibility(anyBoolean(), anyBoolean(), anyBoolean()); } @Test |