diff options
449 files changed, 9339 insertions, 4166 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index c7d92b0cd74e..e015169cf69a 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -99,7 +99,7 @@ package android { field public static final String INTERACT_ACROSS_PROFILES = "android.permission.INTERACT_ACROSS_PROFILES"; field public static final String INTERNET = "android.permission.INTERNET"; field public static final String KILL_BACKGROUND_PROCESSES = "android.permission.KILL_BACKGROUND_PROCESSES"; - field public static final String LAUNCH_TWO_PANE_SETTINGS_DEEP_LINK = "android.permission.LAUNCH_TWO_PANE_SETTINGS_DEEP_LINK"; + field public static final String LAUNCH_MULTI_PANE_SETTINGS_DEEP_LINK = "android.permission.LAUNCH_MULTI_PANE_SETTINGS_DEEP_LINK"; field public static final String LOADER_USAGE_STATS = "android.permission.LOADER_USAGE_STATS"; field public static final String LOCATION_HARDWARE = "android.permission.LOCATION_HARDWARE"; field public static final String MANAGE_DOCUMENTS = "android.permission.MANAGE_DOCUMENTS"; @@ -6712,6 +6712,7 @@ package android.app { } public class TaskInfo { + method public boolean isVisible(); field @Nullable public android.content.ComponentName baseActivity; field @NonNull public android.content.Intent baseIntent; field public boolean isRunning; @@ -22581,6 +22582,7 @@ package android.media { field public static final String KEY_MAX_FPS_TO_ENCODER = "max-fps-to-encoder"; field public static final String KEY_MAX_HEIGHT = "max-height"; field public static final String KEY_MAX_INPUT_SIZE = "max-input-size"; + field public static final String KEY_MAX_OUTPUT_CHANNEL_COUNT = "max-output-channel_count"; field public static final String KEY_MAX_PTS_GAP_TO_ENCODER = "max-pts-gap-to-encoder"; field public static final String KEY_MAX_WIDTH = "max-width"; field public static final String KEY_MIME = "mime"; @@ -35240,7 +35242,7 @@ package android.provider { field public static final String ACTION_SEARCH_SETTINGS = "android.search.action.SEARCH_SETTINGS"; field public static final String ACTION_SECURITY_SETTINGS = "android.settings.SECURITY_SETTINGS"; field public static final String ACTION_SETTINGS = "android.settings.SETTINGS"; - field public static final String ACTION_SETTINGS_LARGE_SCREEN_DEEP_LINK = "android.settings.SETTINGS_LARGE_SCREEN_DEEP_LINK"; + field public static final String ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY = "android.settings.SETTINGS_EMBED_DEEP_LINK_ACTIVITY"; field public static final String ACTION_SHOW_REGULATORY_INFO = "android.settings.SHOW_REGULATORY_INFO"; field public static final String ACTION_SHOW_WORK_POLICY_INFO = "android.settings.SHOW_WORK_POLICY_INFO"; field public static final String ACTION_SOUND_SETTINGS = "android.settings.SOUND_SETTINGS"; @@ -35281,8 +35283,8 @@ package android.provider { field public static final String EXTRA_EASY_CONNECT_ERROR_CODE = "android.provider.extra.EASY_CONNECT_ERROR_CODE"; field public static final String EXTRA_INPUT_METHOD_ID = "input_method_id"; field public static final String EXTRA_NOTIFICATION_LISTENER_COMPONENT_NAME = "android.provider.extra.NOTIFICATION_LISTENER_COMPONENT_NAME"; - field public static final String EXTRA_SETTINGS_LARGE_SCREEN_DEEP_LINK_INTENT_URI = "android.provider.extra.SETTINGS_LARGE_SCREEN_DEEP_LINK_INTENT_URI"; - field public static final String EXTRA_SETTINGS_LARGE_SCREEN_HIGHLIGHT_MENU_KEY = "android.provider.extra.SETTINGS_LARGE_SCREEN_HIGHLIGHT_MENU_KEY"; + field public static final String EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_HIGHLIGHT_MENU_KEY = "android.provider.extra.SETTINGS_EMBEDDED_DEEP_LINK_HIGHLIGHT_MENU_KEY"; + field public static final String EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_INTENT_URI = "android.provider.extra.SETTINGS_EMBEDDED_DEEP_LINK_INTENT_URI"; field public static final String EXTRA_SUB_ID = "android.provider.extra.SUB_ID"; field public static final String EXTRA_WIFI_NETWORK_LIST = "android.provider.extra.WIFI_NETWORK_LIST"; field public static final String EXTRA_WIFI_NETWORK_RESULT_LIST = "android.provider.extra.WIFI_NETWORK_RESULT_LIST"; diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 5b27019f300e..3aa17f0865b4 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -26,7 +26,7 @@ package android { field public static final String ADJUST_RUNTIME_PERMISSIONS_POLICY = "android.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY"; field public static final String ALLOCATE_AGGRESSIVE = "android.permission.ALLOCATE_AGGRESSIVE"; field public static final String ALLOW_ANY_CODEC_FOR_PLAYBACK = "android.permission.ALLOW_ANY_CODEC_FOR_PLAYBACK"; - field public static final String ALLOW_PLACE_IN_TWO_PANE_SETTINGS = "android.permission.ALLOW_PLACE_IN_TWO_PANE_SETTINGS"; + field public static final String ALLOW_PLACE_IN_MULTI_PANE_SETTINGS = "android.permission.ALLOW_PLACE_IN_MULTI_PANE_SETTINGS"; field public static final String AMBIENT_WALLPAPER = "android.permission.AMBIENT_WALLPAPER"; field public static final String APPROVE_INCIDENT_REPORTS = "android.permission.APPROVE_INCIDENT_REPORTS"; field public static final String ASSOCIATE_COMPANION_DEVICES = "android.permission.ASSOCIATE_COMPANION_DEVICES"; @@ -437,6 +437,11 @@ package android.app { method public void onUidImportance(int, int); } + public class ActivityOptions { + method public int getLaunchTaskId(); + method @RequiresPermission("android.permission.START_TASKS_FROM_RECENTS") public void setLaunchTaskId(int); + } + public class AlarmManager { method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void set(int, long, long, long, android.app.PendingIntent, android.os.WorkSource); method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void set(int, long, long, long, android.app.AlarmManager.OnAlarmListener, android.os.Handler, android.os.WorkSource); diff --git a/core/api/test-current.txt b/core/api/test-current.txt index ceab0560e0d3..488f8b145e52 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -144,7 +144,6 @@ package android.app { method @NonNull @RequiresPermission(android.Manifest.permission.START_TASKS_FROM_RECENTS) public static android.app.ActivityOptions makeCustomTaskAnimation(@NonNull android.content.Context, int, int, @Nullable android.os.Handler, @Nullable android.app.ActivityOptions.OnAnimationStartedListener, @Nullable android.app.ActivityOptions.OnAnimationFinishedListener); method public static void setExitTransitionTimeout(long); method public void setLaunchActivityType(int); - method public void setLaunchTaskId(int); method public void setLaunchWindowingMode(int); method public void setLaunchedFromBubble(boolean); method public void setTaskAlwaysOnTop(boolean); diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java index d1def7e62626..edcab29dec94 100644 --- a/core/java/android/app/ActivityOptions.java +++ b/core/java/android/app/ActivityOptions.java @@ -26,6 +26,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; +import android.annotation.SystemApi; import android.annotation.TestApi; import android.app.ExitTransitionCoordinator.ActivityExitTransitionCallbacks; import android.app.ExitTransitionCoordinator.ExitTransitionCallbacks; @@ -1521,7 +1522,8 @@ public class ActivityOptions { * Sets the task the activity will be launched in. * @hide */ - @TestApi + @RequiresPermission(START_TASKS_FROM_RECENTS) + @SystemApi public void setLaunchTaskId(int taskId) { mLaunchTaskId = taskId; } @@ -1529,6 +1531,7 @@ public class ActivityOptions { /** * @hide */ + @SystemApi public int getLaunchTaskId() { return mLaunchTaskId; } diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java index a2c9795204ad..74208c3a4aff 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -2134,4 +2134,38 @@ public final class LoadedApk { final IBinder mService; } } + + /** + * Check if the Apk paths in the cache are correct, and update them if they are not. + * @hide + */ + public static void checkAndUpdateApkPaths(ApplicationInfo expectedAppInfo) { + // Get the LoadedApk from the cache + ActivityThread activityThread = ActivityThread.currentActivityThread(); + if (activityThread == null) { + Log.e(TAG, "Cannot find activity thread"); + return; + } + checkAndUpdateApkPaths(activityThread, expectedAppInfo, /* cacheWithCode */ true); + checkAndUpdateApkPaths(activityThread, expectedAppInfo, /* cacheWithCode */ false); + } + + private static void checkAndUpdateApkPaths(ActivityThread activityThread, + ApplicationInfo expectedAppInfo, boolean cacheWithCode) { + String expectedCodePath = expectedAppInfo.getCodePath(); + LoadedApk loadedApk = activityThread.peekPackageInfo( + expectedAppInfo.packageName, /* includeCode= */ cacheWithCode); + // If there is load apk cached, or if the cache is valid, don't do anything. + if (loadedApk == null || loadedApk.getApplicationInfo() == null + || loadedApk.getApplicationInfo().getCodePath().equals(expectedCodePath)) { + return; + } + // Duplicate framework logic + List<String> oldPaths = new ArrayList<>(); + LoadedApk.makePaths(activityThread, expectedAppInfo, oldPaths); + + // Force update the LoadedApk instance, which should update the reference in the cache + loadedApk.updateApplicationInfo(expectedAppInfo, oldPaths); + } + } diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java index cac763988d5e..bd9b6e952118 100644 --- a/core/java/android/app/TaskInfo.java +++ b/core/java/android/app/TaskInfo.java @@ -265,6 +265,13 @@ public class TaskInfo { } /** + * Whether this task is visible. + */ + public boolean isVisible() { + return isVisible; + } + + /** * @param isLowResolution * @return * @hide diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java index dd147cc26e59..eb10f097f37f 100644 --- a/core/java/android/appwidget/AppWidgetHostView.java +++ b/core/java/android/appwidget/AppWidgetHostView.java @@ -20,6 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.app.Activity; import android.app.ActivityOptions; +import android.app.LoadedApk; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; @@ -554,7 +555,7 @@ public class AppWidgetHostView extends FrameLayout { } // Prepare a local reference to the remote Context so we're ready to // inflate any requested LayoutParams. - mRemoteContext = getRemoteContext(); + mRemoteContext = getRemoteContextEnsuringCorrectCachedApkPath(); int layoutId = rvToApply.getLayoutId(); if (rvToApply.canRecycleView(mView)) { @@ -616,7 +617,7 @@ public class AppWidgetHostView extends FrameLayout { private void inflateAsync(@NonNull RemoteViews remoteViews) { // Prepare a local reference to the remote Context so we're ready to // inflate any requested LayoutParams. - mRemoteContext = getRemoteContext(); + mRemoteContext = getRemoteContextEnsuringCorrectCachedApkPath(); int layoutId = remoteViews.getLayoutId(); if (mLastExecutionSignal != null) { @@ -718,8 +719,10 @@ public class AppWidgetHostView extends FrameLayout { * purposes of reading remote resources. * @hide */ - protected Context getRemoteContext() { + protected Context getRemoteContextEnsuringCorrectCachedApkPath() { try { + ApplicationInfo expectedAppInfo = mInfo.providerInfo.applicationInfo; + LoadedApk.checkAndUpdateApkPaths(expectedAppInfo); // Return if cloned successfully, otherwise default Context newContext = mContext.createApplicationContext( mInfo.providerInfo.applicationInfo, @@ -765,7 +768,7 @@ public class AppWidgetHostView extends FrameLayout { try { if (mInfo != null) { - Context theirContext = getRemoteContext(); + Context theirContext = getRemoteContextEnsuringCorrectCachedApkPath(); mRemoteContext = theirContext; LayoutInflater inflater = (LayoutInflater) theirContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index c3ec09466de6..7f2a740d3228 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -3246,7 +3246,11 @@ public abstract class Context { * Service will call {@link android.app.Service#startForeground(int, android.app.Notification) * startForeground(int, android.app.Notification)} once it begins running. The service is given * an amount of time comparable to the ANR interval to do this, otherwise the system - * will automatically stop the service and declare the app ANR. + * will automatically crash the process, in which case an internal exception + * {@code ForegroundServiceDidNotStartInTimeException} is logged on logcat on devices + * running SDK Version {@link android.os.Build.VERSION_CODES#S} or later. On older Android + * versions, an internal exception {@code RemoteServiceException} is logged instead, with + * a corresponding message. * * <p>Unlike the ordinary {@link #startService(Intent)}, this method can be used * at any time, regardless of whether the app hosting the service is in a foreground diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java index 95c5612aeee4..e28e4ad9ae9f 100644 --- a/core/java/android/content/pm/ActivityInfo.java +++ b/core/java/android/content/pm/ActivityInfo.java @@ -994,9 +994,10 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { * OVERRIDE_MIN_ASPECT_RATIO_MEDIUM * OVERRIDE_MIN_ASPECT_RATIO_LARGE * - * If OVERRIDE_MIN_ASPECT_RATIO is applied, the min aspect ratio given in the app's - * manifest will be overridden to the largest enabled aspect ratio treatment unless the app's - * manifest value is higher. + * If OVERRIDE_MIN_ASPECT_RATIO is applied, and the activity's orientation is fixed to + * portrait, the min aspect ratio given in the app's manifest will be overridden to the + * largest enabled aspect ratio treatment unless the app's manifest value is higher. + * TODO(b/203647190): add OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY instead of portrait by default * @hide */ @ChangeId @@ -1232,8 +1233,8 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { * Returns true if the activity has maximum or minimum aspect ratio. * @hide */ - public boolean hasFixedAspectRatio() { - return getMaxAspectRatio() != 0 || getMinAspectRatio() != 0; + public boolean hasFixedAspectRatio(@ScreenOrientation int orientation) { + return getMaxAspectRatio() != 0 || getMinAspectRatio(orientation) != 0; } /** @@ -1392,10 +1393,14 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { * {@code getManifestMinAspectRatio}. * @hide */ - public float getMinAspectRatio() { + public float getMinAspectRatio(@ScreenOrientation int orientation) { + // TODO(b/203647190): check orientation only if OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY + // In case the activity's orientation isn't fixed to portrait, OVERRIDE_MIN_ASPECT_RATIO + // shouldn't be applied. if (applicationInfo == null || !CompatChanges.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO, applicationInfo.packageName, - UserHandle.getUserHandleForUid(applicationInfo.uid))) { + UserHandle.getUserHandleForUid(applicationInfo.uid)) + || !isFixedOrientationPortrait(orientation)) { return mMinAspectRatio; } @@ -1521,9 +1526,10 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { if (getMaxAspectRatio() != 0) { pw.println(prefix + "maxAspectRatio=" + getMaxAspectRatio()); } - if (getMinAspectRatio() != 0) { - pw.println(prefix + "minAspectRatio=" + getMinAspectRatio()); - if (getManifestMinAspectRatio() != getMinAspectRatio()) { + final float minAspectRatio = getMinAspectRatio(screenOrientation); + if (minAspectRatio != 0) { + pw.println(prefix + "minAspectRatio=" + minAspectRatio); + if (getManifestMinAspectRatio() != minAspectRatio) { pw.println(prefix + "getManifestMinAspectRatio=" + getManifestMinAspectRatio()); } } diff --git a/core/java/android/hardware/display/AmbientDisplayConfiguration.java b/core/java/android/hardware/display/AmbientDisplayConfiguration.java index f5b2ac586bd1..2b52e967ce54 100644 --- a/core/java/android/hardware/display/AmbientDisplayConfiguration.java +++ b/core/java/android/hardware/display/AmbientDisplayConfiguration.java @@ -22,11 +22,9 @@ import android.os.Build; import android.os.SystemProperties; import android.provider.Settings; import android.text.TextUtils; -import android.util.Log; - -import java.util.Arrays; import com.android.internal.R; +import com.android.internal.util.ArrayUtils; /** * AmbientDisplayConfiguration encapsulates reading access to the configuration of ambient display. @@ -90,7 +88,12 @@ public class AmbientDisplayConfiguration { /** {@hide} */ public boolean tapSensorAvailable() { - return !TextUtils.isEmpty(tapSensorType()); + for (String tapType : tapSensorTypeMapping()) { + if (!TextUtils.isEmpty(tapType)) { + return true; + } + } + return false; } /** {@hide} */ @@ -143,18 +146,18 @@ public class AmbientDisplayConfiguration { return mContext.getResources().getString(R.string.config_dozeDoubleTapSensorType); } - /** {@hide} */ - private String tapSensorType() { - return mContext.getResources().getString(R.string.config_dozeTapSensorType); - } - - /** {@hide} */ - public String tapSensorType(int posture) { - return getSensorFromPostureMapping( - mContext.getResources().getStringArray(R.array.config_dozeTapSensorPostureMapping), - tapSensorType(), - posture - ); + /** {@hide} + * May support multiple postures. + */ + public String[] tapSensorTypeMapping() { + String[] postureMapping = + mContext.getResources().getStringArray(R.array.config_dozeTapSensorPostureMapping); + if (ArrayUtils.isEmpty(postureMapping)) { + return new String[] { + mContext.getResources().getString(R.string.config_dozeTapSensorType) + }; + } + return postureMapping; } /** {@hide} */ @@ -253,20 +256,4 @@ public class AmbientDisplayConfiguration { private boolean boolSetting(String name, int user, int def) { return Settings.Secure.getIntForUser(mContext.getContentResolver(), name, def, user) != 0; } - - /** {@hide} */ - public static String getSensorFromPostureMapping( - String[] postureMapping, - String defaultValue, - int posture) { - String sensorType = defaultValue; - if (postureMapping != null && posture < postureMapping.length) { - sensorType = postureMapping[posture]; - } else { - Log.e(TAG, "Unsupported doze posture " + posture - + " postureMapping=" + Arrays.toString(postureMapping)); - } - - return TextUtils.isEmpty(sensorType) ? defaultValue : sensorType; - } } diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 249154aa9129..fee2e2b27457 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -47,7 +47,6 @@ import android.text.TextUtils; import android.util.BackupUtils; import android.util.Log; -import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.net.module.util.NetworkIdentityUtils; @@ -151,24 +150,6 @@ public class NetworkTemplate implements Parcelable { } } - private static boolean sForceAllNetworkTypes = false; - - /** - * Results in matching against all mobile network types. - * - * <p>See {@link #matchesMobile} and {@link matchesMobileWildcard}. - */ - @VisibleForTesting - public static void forceAllNetworkTypes() { - sForceAllNetworkTypes = true; - } - - /** Resets the affect of {@link #forceAllNetworkTypes}. */ - @VisibleForTesting - public static void resetForceAllNetworkTypes() { - sForceAllNetworkTypes = false; - } - /** * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with * the given IMSI. @@ -179,19 +160,19 @@ public class NetworkTemplate implements Parcelable { } /** - * Template to match cellular networks with the given IMSI and {@code ratType}. - * Use {@link #NETWORK_TYPE_ALL} to include all network types when filtering. - * See {@code TelephonyManager.NETWORK_TYPE_*}. + * Template to match cellular networks with the given IMSI, {@code ratType} and + * {@code metered}. Use {@link #NETWORK_TYPE_ALL} to include all network types when + * filtering. See {@code TelephonyManager.NETWORK_TYPE_*}. */ public static NetworkTemplate buildTemplateMobileWithRatType(@Nullable String subscriberId, - @NetworkType int ratType) { + @NetworkType int ratType, int metered) { if (TextUtils.isEmpty(subscriberId)) { return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null, null, - METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, + metered, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT); } return new NetworkTemplate(MATCH_MOBILE, subscriberId, new String[]{subscriberId}, null, - METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, + metered, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT); } @@ -324,6 +305,7 @@ public class NetworkTemplate implements Parcelable { } } + // TODO: Deprecate this constructor, mark it @UnsupportedAppUsage(maxTargetSdk = S) @UnsupportedAppUsage public NetworkTemplate(int matchRule, String subscriberId, String networkId) { this(matchRule, subscriberId, new String[] { subscriberId }, networkId); @@ -331,9 +313,14 @@ public class NetworkTemplate implements Parcelable { public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, String networkId) { - this(matchRule, subscriberId, matchSubscriberIds, networkId, METERED_ALL, ROAMING_ALL, - DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL, - SUBSCRIBER_ID_MATCH_RULE_EXACT); + // Older versions used to only match MATCH_MOBILE and MATCH_MOBILE_WILDCARD templates + // to metered networks. It is now possible to match mobile with any meteredness, but + // in order to preserve backward compatibility of @UnsupportedAppUsage methods, this + //constructor passes METERED_YES for these types. + this(matchRule, subscriberId, matchSubscriberIds, networkId, + (matchRule == MATCH_MOBILE || matchRule == MATCH_MOBILE_WILDCARD) ? METERED_YES + : METERED_ALL , ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, + OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT); } // TODO: Remove it after updating all of the caller. @@ -608,11 +595,7 @@ public class NetworkTemplate implements Parcelable { // TODO: consider matching against WiMAX subscriber identity return true; } else { - // Only metered mobile network would be matched regardless of metered filter. - // This is used to exclude non-metered APNs, e.g. IMS. See ag/908650. - // TODO: Respect metered filter and remove mMetered condition. - return (sForceAllNetworkTypes || (ident.mType == TYPE_MOBILE && ident.mMetered)) - && !ArrayUtils.isEmpty(mMatchSubscriberIds) + return ident.mType == TYPE_MOBILE && !ArrayUtils.isEmpty(mMatchSubscriberIds) && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId) && matchesCollapsedRatType(ident); } @@ -726,8 +709,7 @@ public class NetworkTemplate implements Parcelable { if (ident.mType == TYPE_WIMAX) { return true; } else { - return (sForceAllNetworkTypes || (ident.mType == TYPE_MOBILE && ident.mMetered)) - && matchesCollapsedRatType(ident); + return ident.mType == TYPE_MOBILE && matchesCollapsedRatType(ident); } } diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index fb9911811da9..79ec55482c50 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -2303,6 +2303,38 @@ public abstract class BatteryStats implements Parcelable { public abstract Timer getScreenBrightnessTimer(int brightnessBin); /** + * Returns the number of physical displays on the device. + * + * {@hide} + */ + public abstract int getDisplayCount(); + + /** + * Returns the time in microseconds that the screen has been on for a display while the + * device was running on battery. + * + * {@hide} + */ + public abstract long getDisplayScreenOnTime(int display, long elapsedRealtimeUs); + + /** + * Returns the time in microseconds that a display has been dozing while the device was + * running on battery. + * + * {@hide} + */ + public abstract long getDisplayScreenDozeTime(int display, long elapsedRealtimeUs); + + /** + * Returns the time in microseconds that a display has been on with the given brightness + * level while the device was running on battery. + * + * {@hide} + */ + public abstract long getDisplayScreenBrightnessTime(int display, int brightnessBin, + long elapsedRealtimeUs); + + /** * Returns the time in microseconds that power save mode has been enabled while the device was * running on battery. * @@ -5038,6 +5070,71 @@ public abstract class BatteryStats implements Parcelable { pw.println(sb.toString()); } + final int numDisplays = getDisplayCount(); + if (numDisplays > 1) { + pw.println(""); + pw.print(prefix); + sb.setLength(0); + sb.append(prefix); + sb.append(" MULTI-DISPLAY POWER SUMMARY START"); + pw.println(sb.toString()); + + for (int display = 0; display < numDisplays; display++) { + sb.setLength(0); + sb.append(prefix); + sb.append(" Display "); + sb.append(display); + sb.append(" Statistics:"); + pw.println(sb.toString()); + + final long displayScreenOnTime = getDisplayScreenOnTime(display, rawRealtime); + sb.setLength(0); + sb.append(prefix); + sb.append(" Screen on: "); + formatTimeMs(sb, displayScreenOnTime / 1000); + sb.append("("); + sb.append(formatRatioLocked(displayScreenOnTime, whichBatteryRealtime)); + sb.append(") "); + pw.println(sb.toString()); + + sb.setLength(0); + sb.append(" Screen brightness levels:"); + didOne = false; + for (int bin = 0; bin < NUM_SCREEN_BRIGHTNESS_BINS; bin++) { + final long timeUs = getDisplayScreenBrightnessTime(display, bin, rawRealtime); + if (timeUs == 0) { + continue; + } + didOne = true; + sb.append("\n "); + sb.append(prefix); + sb.append(SCREEN_BRIGHTNESS_NAMES[bin]); + sb.append(" "); + formatTimeMs(sb, timeUs / 1000); + sb.append("("); + sb.append(formatRatioLocked(timeUs, displayScreenOnTime)); + sb.append(")"); + } + if (!didOne) sb.append(" (no activity)"); + pw.println(sb.toString()); + + final long displayScreenDozeTimeUs = getDisplayScreenDozeTime(display, rawRealtime); + sb.setLength(0); + sb.append(prefix); + sb.append(" Screen Doze: "); + formatTimeMs(sb, displayScreenDozeTimeUs / 1000); + sb.append("("); + sb.append(formatRatioLocked(displayScreenDozeTimeUs, whichBatteryRealtime)); + sb.append(") "); + pw.println(sb.toString()); + } + pw.print(prefix); + sb.setLength(0); + sb.append(prefix); + sb.append(" MULTI-DISPLAY POWER SUMMARY END"); + pw.println(sb.toString()); + } + pw.println(""); pw.print(prefix); sb.setLength(0); diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 7472cca7fbd6..1b6a03c7a736 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -16966,40 +16966,42 @@ public final class Settings { "android.settings.MANAGE_APP_ALL_FILES_ACCESS_PERMISSION"; /** - * Activity Action: For system or preinstalled apps to show their {@link Activity} in 2-pane - * mode in Settings app on large screen devices. + * Activity Action: For system or preinstalled apps to show their {@link Activity} embedded + * in Settings app on large screen devices. * <p> - * Input: {@link #EXTRA_SETTINGS_LARGE_SCREEN_DEEP_LINK_INTENT_URI} must be included to - * specify the intent for the activity which will be displayed in 2-pane mode in Settings app. + * Input: {@link #EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_INTENT_URI} must be included to + * specify the intent for the activity which will be embedded in Settings app. * It's an intent URI string from {@code intent.toUri(Intent.URI_INTENT_SCHEME)}. * - * Input: {@link #EXTRA_SETTINGS_LARGE_SCREEN_HIGHLIGHT_MENU_KEY} must be included to + * Input: {@link #EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_HIGHLIGHT_MENU_KEY} must be included to * specify a key that indicates the menu item which will be highlighted on settings home menu. * <p> * Output: Nothing. */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) - public static final String ACTION_SETTINGS_LARGE_SCREEN_DEEP_LINK = - "android.settings.SETTINGS_LARGE_SCREEN_DEEP_LINK"; + public static final String ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY = + "android.settings.SETTINGS_EMBED_DEEP_LINK_ACTIVITY"; /** - * Activity Extra: Specify the intent for the {@link Activity} which will be displayed in 2-pane - * mode in Settings app. It's an intent URI string from + * Activity Extra: Specify the intent for the {@link Activity} which will be embedded in + * Settings app. It's an intent URI string from * {@code intent.toUri(Intent.URI_INTENT_SCHEME)}. * <p> - * This must be passed as an extra field to {@link #ACTION_SETTINGS_LARGE_SCREEN_DEEP_LINK}. + * This must be passed as an extra field to + * {@link #ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY}. */ - public static final String EXTRA_SETTINGS_LARGE_SCREEN_DEEP_LINK_INTENT_URI = - "android.provider.extra.SETTINGS_LARGE_SCREEN_DEEP_LINK_INTENT_URI"; + public static final String EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_INTENT_URI = + "android.provider.extra.SETTINGS_EMBEDDED_DEEP_LINK_INTENT_URI"; /** * Activity Extra: Specify a key that indicates the menu item which should be highlighted on * settings home menu. * <p> - * This must be passed as an extra field to {@link #ACTION_SETTINGS_LARGE_SCREEN_DEEP_LINK}. + * This must be passed as an extra field to + * {@link #ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY}. */ - public static final String EXTRA_SETTINGS_LARGE_SCREEN_HIGHLIGHT_MENU_KEY = - "android.provider.extra.SETTINGS_LARGE_SCREEN_HIGHLIGHT_MENU_KEY"; + public static final String EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_HIGHLIGHT_MENU_KEY = + "android.provider.extra.SETTINGS_EMBEDDED_DEEP_LINK_HIGHLIGHT_MENU_KEY"; /** * Performs a strict and comprehensive check of whether a calling package is allowed to diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java index 3d18a8933153..c94595468aec 100644 --- a/core/java/android/service/notification/NotificationListenerService.java +++ b/core/java/android/service/notification/NotificationListenerService.java @@ -1699,7 +1699,7 @@ public abstract class NotificationListenerService extends Service { private ArrayList<Notification.Action> mSmartActions; private ArrayList<CharSequence> mSmartReplies; private boolean mCanBubble; - private boolean mVisuallyInterruptive; + private boolean mIsTextChanged; private boolean mIsConversation; private ShortcutInfo mShortcutInfo; private @RankingAdjustment int mRankingAdjustment; @@ -1736,7 +1736,7 @@ public abstract class NotificationListenerService extends Service { out.writeTypedList(mSmartActions, flags); out.writeCharSequenceList(mSmartReplies); out.writeBoolean(mCanBubble); - out.writeBoolean(mVisuallyInterruptive); + out.writeBoolean(mIsTextChanged); out.writeBoolean(mIsConversation); out.writeParcelable(mShortcutInfo, flags); out.writeInt(mRankingAdjustment); @@ -1774,7 +1774,7 @@ public abstract class NotificationListenerService extends Service { mSmartActions = in.createTypedArrayList(Notification.Action.CREATOR); mSmartReplies = in.readCharSequenceList(); mCanBubble = in.readBoolean(); - mVisuallyInterruptive = in.readBoolean(); + mIsTextChanged = in.readBoolean(); mIsConversation = in.readBoolean(); mShortcutInfo = in.readParcelable(cl); mRankingAdjustment = in.readInt(); @@ -1977,8 +1977,8 @@ public abstract class NotificationListenerService extends Service { } /** @hide */ - public boolean visuallyInterruptive() { - return mVisuallyInterruptive; + public boolean isTextChanged() { + return mIsTextChanged; } /** @hide */ @@ -2033,7 +2033,7 @@ public abstract class NotificationListenerService extends Service { int userSentiment, boolean hidden, long lastAudiblyAlertedMs, boolean noisy, ArrayList<Notification.Action> smartActions, ArrayList<CharSequence> smartReplies, boolean canBubble, - boolean visuallyInterruptive, boolean isConversation, ShortcutInfo shortcutInfo, + boolean isTextChanged, boolean isConversation, ShortcutInfo shortcutInfo, int rankingAdjustment, boolean isBubble) { mKey = key; mRank = rank; @@ -2055,7 +2055,7 @@ public abstract class NotificationListenerService extends Service { mSmartActions = smartActions; mSmartReplies = smartReplies; mCanBubble = canBubble; - mVisuallyInterruptive = visuallyInterruptive; + mIsTextChanged = isTextChanged; mIsConversation = isConversation; mShortcutInfo = shortcutInfo; mRankingAdjustment = rankingAdjustment; @@ -2096,7 +2096,7 @@ public abstract class NotificationListenerService extends Service { other.mSmartActions, other.mSmartReplies, other.mCanBubble, - other.mVisuallyInterruptive, + other.mIsTextChanged, other.mIsConversation, other.mShortcutInfo, other.mRankingAdjustment, @@ -2153,7 +2153,7 @@ public abstract class NotificationListenerService extends Service { == (other.mSmartActions == null ? 0 : other.mSmartActions.size())) && Objects.equals(mSmartReplies, other.mSmartReplies) && Objects.equals(mCanBubble, other.mCanBubble) - && Objects.equals(mVisuallyInterruptive, other.mVisuallyInterruptive) + && Objects.equals(mIsTextChanged, other.mIsTextChanged) && Objects.equals(mIsConversation, other.mIsConversation) // Shortcutinfo doesn't have equals either; use id && Objects.equals((mShortcutInfo == null ? 0 : mShortcutInfo.getId()), diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java index 9db856a8762a..4d0fc1642874 100644 --- a/core/java/android/service/voice/VoiceInteractionSession.java +++ b/core/java/android/service/voice/VoiceInteractionSession.java @@ -2045,7 +2045,11 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall /** * Registers a callback that will be notified when visible activities have been changed. * - * @param executor The handler to receive the callback. + * Note: The {@link VisibleActivityCallback#onVisible(VisibleActivityInfo)} will be called + * immediately with current visible activities when the callback is registered for the first + * time. If the callback is already registered, this method does nothing. + * + * @param executor The executor which will be used to invoke the callback. * @param callback The callback to receive the response. * * @throws IllegalStateException if calling this method before onCreate(). diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 8e149a98af0e..1791d3a731f7 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -347,6 +347,14 @@ interface IWindowManager Bitmap screenshotWallpaper(); /** + * Mirrors the wallpaper for the given display. + * + * @param displayId ID of the display for the wallpaper. + * @return A SurfaceControl for the parent of the mirrored wallpaper. + */ + SurfaceControl mirrorWallpaperSurface(int displayId); + + /** * Registers a wallpaper visibility listener. * @return Current visibility. */ diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java index 11b161ad3cb2..a6c5042db275 100644 --- a/core/java/android/view/SurfaceControlViewHost.java +++ b/core/java/android/view/SurfaceControlViewHost.java @@ -292,11 +292,18 @@ public class SurfaceControlViewHost { */ @TestApi public void relayout(WindowManager.LayoutParams attrs) { + relayout(attrs, SurfaceControl.Transaction::apply); + } + + /** + * Forces relayout and draw and allows to set a custom callback when it is finished + * @hide + */ + public void relayout(WindowManager.LayoutParams attrs, + WindowlessWindowManager.ResizeCompleteCallback callback) { mViewRoot.setLayoutParams(attrs, false); mViewRoot.setReportNextDraw(); - mWm.setCompletionCallback(mViewRoot.mWindow.asBinder(), (SurfaceControl.Transaction t) -> { - t.apply(); - }); + mWm.setCompletionCallback(mViewRoot.mWindow.asBinder(), callback); } /** diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index b729c9fb01b1..572a7cdabdc9 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -27060,7 +27060,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, switch (event.mAction) { case DragEvent.ACTION_DRAG_STARTED: { - if (result && li.mOnDragListener != null) { + if (result && li != null && li.mOnDragListener != null) { sendWindowContentChangedAccessibilityEvent( AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); } @@ -27074,7 +27074,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, refreshDrawableState(); } break; case DragEvent.ACTION_DROP: { - if (result && (li.mOnDragListener != null | li.mOnReceiveContentListener != null)) { + if (result && li != null && (li.mOnDragListener != null + || li.mOnReceiveContentListener != null)) { sendWindowContentChangedAccessibilityEvent( AccessibilityEvent.CONTENT_CHANGE_TYPE_DRAG_DROPPED); } diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java index 18013e815d13..c92a3a086a8b 100644 --- a/core/java/android/view/WindowManagerGlobal.java +++ b/core/java/android/view/WindowManagerGlobal.java @@ -18,6 +18,7 @@ package android.view; import android.animation.ValueAnimator; import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.ActivityManager; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentCallbacks2; @@ -709,6 +710,16 @@ public final class WindowManagerGlobal { } } } + + /** @hide */ + @Nullable + public SurfaceControl mirrorWallpaperSurface(int displayId) { + try { + return getWindowManagerService().mirrorWallpaperSurface(displayId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } } final class WindowLeaked extends AndroidRuntimeException { diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java index 52d3612b6f77..3b65ffd35730 100644 --- a/core/java/android/view/accessibility/AccessibilityEvent.java +++ b/core/java/android/view/accessibility/AccessibilityEvent.java @@ -740,7 +740,10 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par CONTENT_CHANGE_TYPE_STATE_DESCRIPTION, CONTENT_CHANGE_TYPE_PANE_TITLE, CONTENT_CHANGE_TYPE_PANE_APPEARED, - CONTENT_CHANGE_TYPE_PANE_DISAPPEARED + CONTENT_CHANGE_TYPE_PANE_DISAPPEARED, + CONTENT_CHANGE_TYPE_DRAG_STARTED, + CONTENT_CHANGE_TYPE_DRAG_DROPPED, + CONTENT_CHANGE_TYPE_DRAG_CANCELLED }) public @interface ContentChangeTypes {} @@ -989,6 +992,9 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par case CONTENT_CHANGE_TYPE_PANE_APPEARED: return "CONTENT_CHANGE_TYPE_PANE_APPEARED"; case CONTENT_CHANGE_TYPE_PANE_DISAPPEARED: return "CONTENT_CHANGE_TYPE_PANE_DISAPPEARED"; + case CONTENT_CHANGE_TYPE_DRAG_STARTED: return "CONTENT_CHANGE_TYPE_DRAG_STARTED"; + case CONTENT_CHANGE_TYPE_DRAG_DROPPED: return "CONTENT_CHANGE_TYPE_DRAG_DROPPED"; + case CONTENT_CHANGE_TYPE_DRAG_CANCELLED: return "CONTENT_CHANGE_TYPE_DRAG_CANCELLED"; default: return Integer.toHexString(type); } } @@ -1047,6 +1053,7 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par /** * Sets the event type. * + * <b>Note: An event must represent a single event type.</b> * @param eventType The event type. * * @throws IllegalStateException If called from an AccessibilityService. diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index fe5eb085dc5c..0f309f10c2b7 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -34,6 +34,7 @@ import android.app.Activity; import android.app.ActivityOptions; import android.app.ActivityThread; import android.app.Application; +import android.app.LoadedApk; import android.app.PendingIntent; import android.app.RemoteInput; import android.appwidget.AppWidgetHostView; @@ -5475,7 +5476,8 @@ public class RemoteViews implements Parcelable, Filter { // user. So build a context that loads resources from that user but // still returns the current users userId so settings like data / time formats // are loaded without requiring cross user persmissions. - final Context contextForResources = getContextForResources(context); + final Context contextForResources = + getContextForResourcesEnsuringCorrectCachedApkPaths(context); if (colorResources != null) { colorResources.apply(contextForResources); } @@ -5853,13 +5855,14 @@ public class RemoteViews implements Parcelable, Filter { } } - private Context getContextForResources(Context context) { + private Context getContextForResourcesEnsuringCorrectCachedApkPaths(Context context) { if (mApplication != null) { if (context.getUserId() == UserHandle.getUserId(mApplication.uid) && context.getPackageName().equals(mApplication.packageName)) { return context; } try { + LoadedApk.checkAndUpdateApkPaths(mApplication); return context.createApplicationContext(mApplication, Context.CONTEXT_RESTRICTED); } catch (NameNotFoundException e) { diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java index 6b33428d7fe4..8e293f4b356d 100644 --- a/core/java/android/widget/RemoteViewsAdapter.java +++ b/core/java/android/widget/RemoteViewsAdapter.java @@ -408,7 +408,7 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback } @Override - protected Context getRemoteContext() { + protected Context getRemoteContextEnsuringCorrectCachedApkPath() { return null; } diff --git a/core/java/android/window/ITransitionMetricsReporter.aidl b/core/java/android/window/ITransitionMetricsReporter.aidl new file mode 100644 index 000000000000..00f71dc7bb90 --- /dev/null +++ b/core/java/android/window/ITransitionMetricsReporter.aidl @@ -0,0 +1,33 @@ +/* + * 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 android.window; + +import android.os.IBinder; + +/** + * Implemented by WM Core to know the metrics of transition that runs on a different process. + * @hide + */ +oneway interface ITransitionMetricsReporter { + + /** + * Called when the transition animation starts. + * + * @param startTime The time when the animation started. + */ + void reportAnimationStart(IBinder transitionToken, long startTime); +} diff --git a/core/java/android/window/IWindowOrganizerController.aidl b/core/java/android/window/IWindowOrganizerController.aidl index e65fcdd7b13b..3c7cd0254e78 100644 --- a/core/java/android/window/IWindowOrganizerController.aidl +++ b/core/java/android/window/IWindowOrganizerController.aidl @@ -23,6 +23,7 @@ import android.view.RemoteAnimationAdapter; import android.window.IDisplayAreaOrganizerController; import android.window.ITaskFragmentOrganizerController; import android.window.ITaskOrganizerController; +import android.window.ITransitionMetricsReporter; import android.window.ITransitionPlayer; import android.window.IWindowContainerTransactionCallback; import android.window.WindowContainerToken; @@ -98,4 +99,7 @@ interface IWindowOrganizerController { * this will replace the existing one if set. */ void registerTransitionPlayer(in ITransitionPlayer player); + + /** @return An interface enabling the transition players to report its metrics. */ + ITransitionMetricsReporter getTransitionMetricsReporter(); } diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java index c2ffc03b6119..7208930c0b20 100644 --- a/core/java/android/window/TransitionInfo.java +++ b/core/java/android/window/TransitionInfo.java @@ -140,7 +140,7 @@ public final class TransitionInfo implements Parcelable { private TransitionInfo(Parcel in) { mType = in.readInt(); mFlags = in.readInt(); - in.readList(mChanges, null /* classLoader */); + in.readTypedList(mChanges, Change.CREATOR); mRootLeash = new SurfaceControl(); mRootLeash.readFromParcel(in); mRootOffset.readFromParcel(in); @@ -152,7 +152,7 @@ public final class TransitionInfo implements Parcelable { public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeInt(mType); dest.writeInt(mFlags); - dest.writeList(mChanges); + dest.writeTypedList(mChanges); mRootLeash.writeToParcel(dest, flags); mRootOffset.writeToParcel(dest, flags); dest.writeTypedObject(mOptions, flags); diff --git a/core/java/android/window/TransitionMetrics.java b/core/java/android/window/TransitionMetrics.java new file mode 100644 index 000000000000..9a93c1a1ffd6 --- /dev/null +++ b/core/java/android/window/TransitionMetrics.java @@ -0,0 +1,57 @@ +/* + * 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 android.window; + +import android.os.IBinder; +import android.os.RemoteException; +import android.os.SystemClock; +import android.util.Singleton; + +/** + * A helper class for who plays transition animation can report its metrics easily. + * @hide + */ +public class TransitionMetrics { + + private final ITransitionMetricsReporter mTransitionMetricsReporter; + + private TransitionMetrics(ITransitionMetricsReporter reporter) { + mTransitionMetricsReporter = reporter; + } + + /** Reports the current timestamp as when the transition animation starts. */ + public void reportAnimationStart(IBinder transitionToken) { + try { + mTransitionMetricsReporter.reportAnimationStart(transitionToken, + SystemClock.elapsedRealtime()); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + + /** Gets the singleton instance of TransitionMetrics. */ + public static TransitionMetrics getInstance() { + return sTransitionMetrics.get(); + } + + private static final Singleton<TransitionMetrics> sTransitionMetrics = new Singleton<>() { + @Override + protected TransitionMetrics create() { + return new TransitionMetrics(WindowOrganizer.getTransitionMetricsReporter()); + } + }; +} diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java index 9d6488d7aa14..bbf813891387 100644 --- a/core/java/android/window/WindowContainerTransaction.java +++ b/core/java/android/window/WindowContainerTransaction.java @@ -295,7 +295,7 @@ public final class WindowContainerTransaction implements Parcelable { } /** - * Reparent's all children tasks of {@param currentParent} in the specified + * Reparent's all children tasks or the top task of {@param currentParent} in the specified * {@param windowingMode} and {@param activityType} to {@param newParent} in their current * z-order. * @@ -306,21 +306,46 @@ public final class WindowContainerTransaction implements Parcelable { * @param activityTypes of the tasks to reparent. * @param onTop When {@code true}, the child goes to the top of parent; otherwise it goes to * the bottom. + * @param reparentTopOnly When {@code true}, only reparent the top task which fit windowingModes + * and activityTypes. + * @hide */ @NonNull public WindowContainerTransaction reparentTasks(@Nullable WindowContainerToken currentParent, @Nullable WindowContainerToken newParent, @Nullable int[] windowingModes, - @Nullable int[] activityTypes, boolean onTop) { + @Nullable int[] activityTypes, boolean onTop, boolean reparentTopOnly) { mHierarchyOps.add(HierarchyOp.createForChildrenTasksReparent( currentParent != null ? currentParent.asBinder() : null, newParent != null ? newParent.asBinder() : null, windowingModes, activityTypes, - onTop)); + onTop, + reparentTopOnly)); return this; } /** + * Reparent's all children tasks of {@param currentParent} in the specified + * {@param windowingMode} and {@param activityType} to {@param newParent} in their current + * z-order. + * + * @param currentParent of the tasks to perform the operation no. + * {@code null} will perform the operation on the display. + * @param newParent for the tasks. {@code null} will perform the operation on the display. + * @param windowingModes of the tasks to reparent. + * @param activityTypes of the tasks to reparent. + * @param onTop When {@code true}, the child goes to the top of parent; otherwise it goes to + * the bottom. + */ + @NonNull + public WindowContainerTransaction reparentTasks(@Nullable WindowContainerToken currentParent, + @Nullable WindowContainerToken newParent, @Nullable int[] windowingModes, + @Nullable int[] activityTypes, boolean onTop) { + return reparentTasks(currentParent, newParent, windowingModes, activityTypes, onTop, + false /* reparentTopOnly */); + } + + /** * Sets whether a container should be the launch root for the specified windowing mode and * activity type. This currently only applies to Task containers created by organizer. */ @@ -948,6 +973,8 @@ public final class WindowContainerTransaction implements Parcelable { // Moves/reparents to top of parent when {@code true}, otherwise moves/reparents to bottom. private boolean mToTop; + private boolean mReparentTopOnly; + @Nullable private int[] mWindowingModes; @@ -985,13 +1012,15 @@ public final class WindowContainerTransaction implements Parcelable { } public static HierarchyOp createForChildrenTasksReparent(IBinder currentParent, - IBinder newParent, int[] windowingModes, int[] activityTypes, boolean onTop) { + IBinder newParent, int[] windowingModes, int[] activityTypes, boolean onTop, + boolean reparentTopOnly) { return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT) .setContainer(currentParent) .setReparentContainer(newParent) .setWindowingModes(windowingModes) .setActivityTypes(activityTypes) .setToTop(onTop) + .setReparentTopOnly(reparentTopOnly) .build(); } @@ -1040,6 +1069,7 @@ public final class WindowContainerTransaction implements Parcelable { mContainer = copy.mContainer; mReparent = copy.mReparent; mToTop = copy.mToTop; + mReparentTopOnly = copy.mReparentTopOnly; mWindowingModes = copy.mWindowingModes; mActivityTypes = copy.mActivityTypes; mLaunchOptions = copy.mLaunchOptions; @@ -1053,6 +1083,7 @@ public final class WindowContainerTransaction implements Parcelable { mContainer = in.readStrongBinder(); mReparent = in.readStrongBinder(); mToTop = in.readBoolean(); + mReparentTopOnly = in.readBoolean(); mWindowingModes = in.createIntArray(); mActivityTypes = in.createIntArray(); mLaunchOptions = in.readBundle(); @@ -1093,6 +1124,10 @@ public final class WindowContainerTransaction implements Parcelable { return mToTop; } + public boolean getReparentTopOnly() { + return mReparentTopOnly; + } + public int[] getWindowingModes() { return mWindowingModes; } @@ -1126,12 +1161,13 @@ public final class WindowContainerTransaction implements Parcelable { switch (mType) { case HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT: return "{ChildrenTasksReparent: from=" + mContainer + " to=" + mReparent - + " mToTop=" + mToTop + " mWindowingMode=" + mWindowingModes - + " mActivityType=" + mActivityTypes + "}"; + + " mToTop=" + mToTop + " mReparentTopOnly=" + mReparentTopOnly + + " mWindowingMode=" + Arrays.toString(mWindowingModes) + + " mActivityType=" + Arrays.toString(mActivityTypes) + "}"; case HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT: return "{SetLaunchRoot: container=" + mContainer - + " mWindowingMode=" + mWindowingModes - + " mActivityType=" + mActivityTypes + "}"; + + " mWindowingMode=" + Arrays.toString(mWindowingModes) + + " mActivityType=" + Arrays.toString(mActivityTypes) + "}"; case HIERARCHY_OP_TYPE_REPARENT: return "{reparent: " + mContainer + " to " + (mToTop ? "top of " : "bottom of ") + mReparent + "}"; @@ -1163,8 +1199,9 @@ public final class WindowContainerTransaction implements Parcelable { + " adjacentContainer=" + mReparent + "}"; default: return "{mType=" + mType + " container=" + mContainer + " reparent=" + mReparent - + " mToTop=" + mToTop + " mWindowingMode=" + mWindowingModes - + " mActivityType=" + mActivityTypes + "}"; + + " mToTop=" + mToTop + + " mWindowingMode=" + Arrays.toString(mWindowingModes) + + " mActivityType=" + Arrays.toString(mActivityTypes) + "}"; } } @@ -1174,6 +1211,7 @@ public final class WindowContainerTransaction implements Parcelable { dest.writeStrongBinder(mContainer); dest.writeStrongBinder(mReparent); dest.writeBoolean(mToTop); + dest.writeBoolean(mReparentTopOnly); dest.writeIntArray(mWindowingModes); dest.writeIntArray(mActivityTypes); dest.writeBundle(mLaunchOptions); @@ -1211,6 +1249,8 @@ public final class WindowContainerTransaction implements Parcelable { private boolean mToTop; + private boolean mReparentTopOnly; + @Nullable private int[] mWindowingModes; @@ -1248,6 +1288,11 @@ public final class WindowContainerTransaction implements Parcelable { return this; } + Builder setReparentTopOnly(boolean reparentTopOnly) { + mReparentTopOnly = reparentTopOnly; + return this; + } + Builder setWindowingModes(@Nullable int[] windowingModes) { mWindowingModes = windowingModes; return this; @@ -1290,6 +1335,7 @@ public final class WindowContainerTransaction implements Parcelable { ? Arrays.copyOf(mActivityTypes, mActivityTypes.length) : null; hierarchyOp.mToTop = mToTop; + hierarchyOp.mReparentTopOnly = mReparentTopOnly; hierarchyOp.mLaunchOptions = mLaunchOptions; hierarchyOp.mActivityIntent = mActivityIntent; hierarchyOp.mPendingIntent = mPendingIntent; diff --git a/core/java/android/window/WindowOrganizer.java b/core/java/android/window/WindowOrganizer.java index e9b8174567a8..4ea5ea5694fa 100644 --- a/core/java/android/window/WindowOrganizer.java +++ b/core/java/android/window/WindowOrganizer.java @@ -159,7 +159,19 @@ public class WindowOrganizer { } } - IWindowOrganizerController getWindowOrganizerController() { + /** + * @see TransitionMetrics + * @hide + */ + public static ITransitionMetricsReporter getTransitionMetricsReporter() { + try { + return getWindowOrganizerController().getTransitionMetricsReporter(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + static IWindowOrganizerController getWindowOrganizerController() { return IWindowOrganizerControllerSingleton.get(); } diff --git a/core/java/com/android/internal/inputmethod/InputMethodDebug.java b/core/java/com/android/internal/inputmethod/InputMethodDebug.java index a00b993749a5..bf094dbd8f1e 100644 --- a/core/java/com/android/internal/inputmethod/InputMethodDebug.java +++ b/core/java/com/android/internal/inputmethod/InputMethodDebug.java @@ -236,6 +236,8 @@ public final class InputMethodDebug { return "HIDE_TOGGLE_SOFT_INPUT"; case SoftInputShowHideReason.SHOW_SOFT_INPUT_BY_INSETS_API: return "SHOW_SOFT_INPUT_BY_INSETS_API"; + case SoftInputShowHideReason.HIDE_DISPLAY_IME_POLICY_HIDE: + return "HIDE_DISPLAY_IME_POLICY_HIDE"; default: return "Unknown=" + reason; } diff --git a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java index e3713a3b8971..9e5776292031 100644 --- a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java +++ b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java @@ -19,6 +19,7 @@ package com.android.internal.inputmethod; import static java.lang.annotation.RetentionPolicy.SOURCE; import android.annotation.IntDef; +import android.view.WindowManager; import android.view.WindowManager.LayoutParams; import java.lang.annotation.Retention; @@ -53,7 +54,8 @@ import java.lang.annotation.Retention; SoftInputShowHideReason.SHOW_RESTORE_IME_VISIBILITY, SoftInputShowHideReason.SHOW_TOGGLE_SOFT_INPUT, SoftInputShowHideReason.HIDE_TOGGLE_SOFT_INPUT, - SoftInputShowHideReason.SHOW_SOFT_INPUT_BY_INSETS_API}) + SoftInputShowHideReason.SHOW_SOFT_INPUT_BY_INSETS_API, + SoftInputShowHideReason.HIDE_DISPLAY_IME_POLICY_HIDE}) public @interface SoftInputShowHideReason { /** Show soft input by {@link android.view.inputmethod.InputMethodManager#showSoftInput}. */ int SHOW_SOFT_INPUT = 0; @@ -195,4 +197,10 @@ public @interface SoftInputShowHideReason { * {@link android.view.InsetsController#show(int)}; */ int SHOW_SOFT_INPUT_BY_INSETS_API = 25; + + /** + * Hide soft input if Ime policy has been set to {@link WindowManager#DISPLAY_IME_POLICY_HIDE}. + * See also {@code InputMethodManagerService#mImeHiddenByDisplayPolicy}. + */ + int HIDE_DISPLAY_IME_POLICY_HIDE = 26; } diff --git a/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java b/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java index 93baa193570d..94430704468f 100644 --- a/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java +++ b/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java @@ -31,12 +31,15 @@ import java.util.List; * Estimates power consumed by the ambient display */ public class AmbientDisplayPowerCalculator extends PowerCalculator { - private final UsageBasedPowerEstimator mPowerEstimator; + private final UsageBasedPowerEstimator[] mPowerEstimators; public AmbientDisplayPowerCalculator(PowerProfile powerProfile) { - // TODO(b/200239964): update to support multidisplay. - mPowerEstimator = new UsageBasedPowerEstimator( - powerProfile.getAveragePowerForOrdinal(POWER_GROUP_DISPLAY_AMBIENT, 0)); + final int numDisplays = powerProfile.getNumDisplays(); + mPowerEstimators = new UsageBasedPowerEstimator[numDisplays]; + for (int display = 0; display < numDisplays; display++) { + mPowerEstimators[display] = new UsageBasedPowerEstimator( + powerProfile.getAveragePowerForOrdinal(POWER_GROUP_DISPLAY_AMBIENT, display)); + } } /** @@ -50,8 +53,8 @@ public class AmbientDisplayPowerCalculator extends PowerCalculator { final int powerModel = getPowerModel(measuredEnergyUC, query); final long durationMs = calculateDuration(batteryStats, rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED); - final double powerMah = getMeasuredOrEstimatedPower(powerModel, - measuredEnergyUC, mPowerEstimator, durationMs); + final double powerMah = calculateTotalPower(powerModel, batteryStats, rawRealtimeUs, + measuredEnergyUC); builder.getAggregateBatteryConsumerBuilder( BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE) .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_AMBIENT_DISPLAY, durationMs) @@ -71,9 +74,8 @@ public class AmbientDisplayPowerCalculator extends PowerCalculator { final long measuredEnergyUC = batteryStats.getScreenDozeMeasuredBatteryConsumptionUC(); final long durationMs = calculateDuration(batteryStats, rawRealtimeUs, statsType); final int powerModel = getPowerModel(measuredEnergyUC); - final double powerMah = getMeasuredOrEstimatedPower(powerModel, - batteryStats.getScreenDozeMeasuredBatteryConsumptionUC(), - mPowerEstimator, durationMs); + final double powerMah = calculateTotalPower(powerModel, batteryStats, rawRealtimeUs, + measuredEnergyUC); if (powerMah > 0) { BatterySipper bs = new BatterySipper(BatterySipper.DrainType.AMBIENT_DISPLAY, null, 0); bs.usagePowerMah = powerMah; @@ -86,4 +88,26 @@ public class AmbientDisplayPowerCalculator extends PowerCalculator { private long calculateDuration(BatteryStats batteryStats, long rawRealtimeUs, int statsType) { return batteryStats.getScreenDozeTime(rawRealtimeUs, statsType) / 1000; } + + private double calculateTotalPower(@BatteryConsumer.PowerModel int powerModel, + BatteryStats batteryStats, long rawRealtimeUs, long consumptionUC) { + switch (powerModel) { + case BatteryConsumer.POWER_MODEL_MEASURED_ENERGY: + return uCtoMah(consumptionUC); + case BatteryConsumer.POWER_MODEL_POWER_PROFILE: + default: + return calculateEstimatedPower(batteryStats, rawRealtimeUs); + } + } + + private double calculateEstimatedPower(BatteryStats batteryStats, long rawRealtimeUs) { + final int numDisplays = mPowerEstimators.length; + double power = 0; + for (int display = 0; display < numDisplays; display++) { + final long dozeTime = batteryStats.getDisplayScreenDozeTime(display, rawRealtimeUs) + / 1000; + power += mPowerEstimators[display].calculatePower(dozeTime); + } + return power; + } } diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index a817119a735f..169eff009bff 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -690,7 +690,7 @@ public class BatteryStatsImpl extends BatteryStats { * Schedule a sync because of a screen state change. */ Future<?> scheduleSyncDueToScreenStateChange(int flags, boolean onBattery, - boolean onBatteryScreenOff, int screenState); + boolean onBatteryScreenOff, int screenState, int[] perDisplayScreenStates); Future<?> scheduleCpuSyncDueToWakelockChange(long delayMillis); void cancelCpuSyncDueToWakelockChange(); Future<?> scheduleSyncDueToBatteryLevelChange(long delayMillis); @@ -851,17 +851,91 @@ public class BatteryStatsImpl extends BatteryStats { public boolean mRecordAllHistory; boolean mNoAutoReset; + /** + * Overall screen state. For multidisplay devices, this represents the current highest screen + * state of the displays. + */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) protected int mScreenState = Display.STATE_UNKNOWN; + /** + * Overall screen on timer. For multidisplay devices, this represents the time spent with at + * least one display in the screen on state. + */ StopwatchTimer mScreenOnTimer; + /** + * Overall screen doze timer. For multidisplay devices, this represents the time spent with + * screen doze being the highest screen state. + */ StopwatchTimer mScreenDozeTimer; - + /** + * Overall screen brightness bin. For multidisplay devices, this represents the current + * brightest screen. + */ int mScreenBrightnessBin = -1; + /** + * Overall screen brightness timers. For multidisplay devices, the {@link mScreenBrightnessBin} + * timer will be active at any given time + */ final StopwatchTimer[] mScreenBrightnessTimer = new StopwatchTimer[NUM_SCREEN_BRIGHTNESS_BINS]; boolean mPretendScreenOff; + private static class DisplayBatteryStats { + /** + * Per display screen state. + */ + public int screenState = Display.STATE_UNKNOWN; + /** + * Per display screen on timers. + */ + public StopwatchTimer screenOnTimer; + /** + * Per display screen doze timers. + */ + public StopwatchTimer screenDozeTimer; + /** + * Per display screen brightness bins. + */ + public int screenBrightnessBin = -1; + /** + * Per display screen brightness timers. + */ + public StopwatchTimer[] screenBrightnessTimers = + new StopwatchTimer[NUM_SCREEN_BRIGHTNESS_BINS]; + /** + * Per display screen state the last time {@link #updateDisplayMeasuredEnergyStatsLocked} + * was called. + */ + public int screenStateAtLastEnergyMeasurement = Display.STATE_UNKNOWN; + + DisplayBatteryStats(Clocks clocks, TimeBase timeBase) { + screenOnTimer = new StopwatchTimer(clocks, null, -1, null, + timeBase); + screenDozeTimer = new StopwatchTimer(clocks, null, -1, null, + timeBase); + for (int i = 0; i < NUM_SCREEN_BRIGHTNESS_BINS; i++) { + screenBrightnessTimers[i] = new StopwatchTimer(clocks, null, -100 - i, null, + timeBase); + } + } + + /** + * Reset display timers. + */ + public void reset(long elapsedRealtimeUs) { + screenOnTimer.reset(false, elapsedRealtimeUs); + screenDozeTimer.reset(false, elapsedRealtimeUs); + for (int i = 0; i < NUM_SCREEN_BRIGHTNESS_BINS; i++) { + screenBrightnessTimers[i].reset(false, elapsedRealtimeUs); + } + } + } + + DisplayBatteryStats[] mPerDisplayBatteryStats; + + private int mDisplayMismatchWtfCount = 0; + boolean mInteractive; StopwatchTimer mInteractiveTimer; @@ -1006,8 +1080,6 @@ public class BatteryStatsImpl extends BatteryStats { @GuardedBy("this") @VisibleForTesting protected @Nullable MeasuredEnergyStats mGlobalMeasuredEnergyStats; - /** Last known screen state. Needed for apportioning display energy. */ - int mScreenStateAtLastEnergyMeasurement = Display.STATE_UNKNOWN; /** Bluetooth Power calculator for attributing measured bluetooth charge consumption to uids */ @Nullable BluetoothPowerCalculator mBluetoothPowerCalculator = null; /** Cpu Power calculator for attributing measured cpu charge consumption to uids */ @@ -4308,8 +4380,10 @@ public class BatteryStatsImpl extends BatteryStats { public void setPretendScreenOff(boolean pretendScreenOff) { if (mPretendScreenOff != pretendScreenOff) { mPretendScreenOff = pretendScreenOff; - noteScreenStateLocked(pretendScreenOff ? Display.STATE_OFF : Display.STATE_ON, - mClocks.elapsedRealtime(), mClocks.uptimeMillis(), mClocks.currentTimeMillis()); + final int primaryScreenState = mPerDisplayBatteryStats[0].screenState; + noteScreenStateLocked(0, primaryScreenState, + mClocks.elapsedRealtime(), mClocks.uptimeMillis(), + mClocks.currentTimeMillis()); } } @@ -4907,29 +4981,158 @@ public class BatteryStatsImpl extends BatteryStats { } @GuardedBy("this") - public void noteScreenStateLocked(int state) { - noteScreenStateLocked(state, mClocks.elapsedRealtime(), mClocks.uptimeMillis(), + public void noteScreenStateLocked(int display, int state) { + noteScreenStateLocked(display, state, mClocks.elapsedRealtime(), mClocks.uptimeMillis(), mClocks.currentTimeMillis()); } @GuardedBy("this") - public void noteScreenStateLocked(int state, + public void noteScreenStateLocked(int display, int displayState, long elapsedRealtimeMs, long uptimeMs, long currentTimeMs) { - state = mPretendScreenOff ? Display.STATE_OFF : state; - // Battery stats relies on there being 4 states. To accommodate this, new states beyond the // original 4 are mapped to one of the originals. - if (state > MAX_TRACKED_SCREEN_STATE) { - switch (state) { - case Display.STATE_VR: - state = Display.STATE_ON; + if (displayState > MAX_TRACKED_SCREEN_STATE) { + if (Display.isOnState(displayState)) { + displayState = Display.STATE_ON; + } else if (Display.isDozeState(displayState)) { + if (Display.isSuspendedState(displayState)) { + displayState = Display.STATE_DOZE_SUSPEND; + } else { + displayState = Display.STATE_DOZE; + } + } else if (Display.isOffState(displayState)) { + displayState = Display.STATE_OFF; + } else { + Slog.wtf(TAG, "Unknown screen state (not mapped): " + displayState); + displayState = Display.STATE_UNKNOWN; + } + } + // As of this point, displayState should be mapped to one of: + // - Display.STATE_ON, + // - Display.STATE_DOZE + // - Display.STATE_DOZE_SUSPEND + // - Display.STATE_OFF + // - Display.STATE_UNKNOWN + + int state; + int overallBin = mScreenBrightnessBin; + int externalUpdateFlag = 0; + boolean shouldScheduleSync = false; + final int numDisplay = mPerDisplayBatteryStats.length; + if (display < 0 || display >= numDisplay) { + Slog.wtf(TAG, "Unexpected note screen state for display " + display + " (only " + + mPerDisplayBatteryStats.length + " displays exist...)"); + return; + } + final DisplayBatteryStats displayStats = mPerDisplayBatteryStats[display]; + final int oldDisplayState = displayStats.screenState; + + if (oldDisplayState == displayState) { + // Nothing changed + state = mScreenState; + } else { + displayStats.screenState = displayState; + + // Stop timer for previous display state. + switch (oldDisplayState) { + case Display.STATE_ON: + displayStats.screenOnTimer.stopRunningLocked(elapsedRealtimeMs); + final int bin = displayStats.screenBrightnessBin; + if (bin >= 0) { + displayStats.screenBrightnessTimers[bin].stopRunningLocked( + elapsedRealtimeMs); + } + overallBin = evaluateOverallScreenBrightnessBinLocked(); + shouldScheduleSync = true; + break; + case Display.STATE_DOZE: + // Transition from doze to doze suspend can be ignored. + if (displayState == Display.STATE_DOZE_SUSPEND) break; + displayStats.screenDozeTimer.stopRunningLocked(elapsedRealtimeMs); + shouldScheduleSync = true; + break; + case Display.STATE_DOZE_SUSPEND: + // Transition from doze suspend to doze can be ignored. + if (displayState == Display.STATE_DOZE) break; + displayStats.screenDozeTimer.stopRunningLocked(elapsedRealtimeMs); + shouldScheduleSync = true; + break; + case Display.STATE_OFF: // fallthrough + case Display.STATE_UNKNOWN: + // Not tracked by timers. break; default: - Slog.wtf(TAG, "Unknown screen state (not mapped): " + state); + Slog.wtf(TAG, + "Attempted to stop timer for unexpected display state " + display); + } + + // Start timer for new display state. + switch (displayState) { + case Display.STATE_ON: + displayStats.screenOnTimer.startRunningLocked(elapsedRealtimeMs); + final int bin = displayStats.screenBrightnessBin; + if (bin >= 0) { + displayStats.screenBrightnessTimers[bin].startRunningLocked( + elapsedRealtimeMs); + } + overallBin = evaluateOverallScreenBrightnessBinLocked(); + shouldScheduleSync = true; + break; + case Display.STATE_DOZE: + // Transition from doze suspend to doze can be ignored. + if (oldDisplayState == Display.STATE_DOZE_SUSPEND) break; + displayStats.screenDozeTimer.startRunningLocked(elapsedRealtimeMs); + shouldScheduleSync = true; break; + case Display.STATE_DOZE_SUSPEND: + // Transition from doze to doze suspend can be ignored. + if (oldDisplayState == Display.STATE_DOZE) break; + displayStats.screenDozeTimer.startRunningLocked(elapsedRealtimeMs); + shouldScheduleSync = true; + break; + case Display.STATE_OFF: // fallthrough + case Display.STATE_UNKNOWN: + // Not tracked by timers. + break; + default: + Slog.wtf(TAG, + "Attempted to start timer for unexpected display state " + displayState + + " for display " + display); + } + + if (shouldScheduleSync + && mGlobalMeasuredEnergyStats != null + && mGlobalMeasuredEnergyStats.isStandardBucketSupported( + MeasuredEnergyStats.POWER_BUCKET_SCREEN_ON)) { + // Display measured energy stats is available. Prepare to schedule an + // external sync. + externalUpdateFlag |= ExternalStatsSync.UPDATE_DISPLAY; + } + + // Reevaluate most important display screen state. + state = Display.STATE_UNKNOWN; + for (int i = 0; i < numDisplay; i++) { + final int tempState = mPerDisplayBatteryStats[i].screenState; + if (tempState == Display.STATE_ON + || state == Display.STATE_ON) { + state = Display.STATE_ON; + } else if (tempState == Display.STATE_DOZE + || state == Display.STATE_DOZE) { + state = Display.STATE_DOZE; + } else if (tempState == Display.STATE_DOZE_SUSPEND + || state == Display.STATE_DOZE_SUSPEND) { + state = Display.STATE_DOZE_SUSPEND; + } else if (tempState == Display.STATE_OFF + || state == Display.STATE_OFF) { + state = Display.STATE_OFF; + } } } + final boolean batteryRunning = mOnBatteryTimeBase.isRunning(); + final boolean batteryScreenOffRunning = mOnBatteryScreenOffTimeBase.isRunning(); + + state = mPretendScreenOff ? Display.STATE_OFF : state; if (mScreenState != state) { recordDailyStatsIfNeededLocked(true, currentTimeMs); final int oldState = mScreenState; @@ -4983,11 +5186,11 @@ public class BatteryStatsImpl extends BatteryStats { + Display.stateToString(state)); addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); } - // TODO: (Probably overkill) Have mGlobalMeasuredEnergyStats store supported flags and - // only update DISPLAY if it is. Currently overkill since CPU is scheduled anyway. - final int updateFlag = ExternalStatsSync.UPDATE_CPU | ExternalStatsSync.UPDATE_DISPLAY; - mExternalSync.scheduleSyncDueToScreenStateChange(updateFlag, - mOnBatteryTimeBase.isRunning(), mOnBatteryScreenOffTimeBase.isRunning(), state); + + // Per screen state Cpu stats needed. Prepare to schedule an external sync. + externalUpdateFlag |= ExternalStatsSync.UPDATE_CPU; + shouldScheduleSync = true; + if (Display.isOnState(state)) { updateTimeBasesLocked(mOnBatteryTimeBase.isRunning(), state, uptimeMs * 1000, elapsedRealtimeMs * 1000); @@ -5005,33 +5208,116 @@ public class BatteryStatsImpl extends BatteryStats { updateDischargeScreenLevelsLocked(oldState, state); } } + + // Changing display states might have changed the screen used to determine the overall + // brightness. + maybeUpdateOverallScreenBrightness(overallBin, elapsedRealtimeMs, uptimeMs); + + if (shouldScheduleSync) { + final int numDisplays = mPerDisplayBatteryStats.length; + final int[] displayStates = new int[numDisplays]; + for (int i = 0; i < numDisplays; i++) { + displayStates[i] = mPerDisplayBatteryStats[i].screenState; + } + mExternalSync.scheduleSyncDueToScreenStateChange(externalUpdateFlag, + batteryRunning, batteryScreenOffRunning, state, displayStates); + } } @UnsupportedAppUsage public void noteScreenBrightnessLocked(int brightness) { - noteScreenBrightnessLocked(brightness, mClocks.elapsedRealtime(), mClocks.uptimeMillis()); + noteScreenBrightnessLocked(0, brightness); + } + + /** + * Note screen brightness change for a display. + */ + public void noteScreenBrightnessLocked(int display, int brightness) { + noteScreenBrightnessLocked(display, brightness, mClocks.elapsedRealtime(), + mClocks.uptimeMillis()); } - public void noteScreenBrightnessLocked(int brightness, long elapsedRealtimeMs, long uptimeMs) { + + /** + * Note screen brightness change for a display. + */ + public void noteScreenBrightnessLocked(int display, int brightness, long elapsedRealtimeMs, + long uptimeMs) { // Bin the brightness. int bin = brightness / (256/NUM_SCREEN_BRIGHTNESS_BINS); if (bin < 0) bin = 0; else if (bin >= NUM_SCREEN_BRIGHTNESS_BINS) bin = NUM_SCREEN_BRIGHTNESS_BINS-1; - if (mScreenBrightnessBin != bin) { - mHistoryCur.states = (mHistoryCur.states&~HistoryItem.STATE_BRIGHTNESS_MASK) - | (bin << HistoryItem.STATE_BRIGHTNESS_SHIFT); - if (DEBUG_HISTORY) Slog.v(TAG, "Screen brightness " + bin + " to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + + final int overallBin; + + final int numDisplays = mPerDisplayBatteryStats.length; + if (display < 0 || display >= numDisplays) { + Slog.wtf(TAG, "Unexpected note screen brightness for display " + display + " (only " + + mPerDisplayBatteryStats.length + " displays exist...)"); + return; + } + + final DisplayBatteryStats displayStats = mPerDisplayBatteryStats[display]; + final int oldBin = displayStats.screenBrightnessBin; + if (oldBin == bin) { + // Nothing changed + overallBin = mScreenBrightnessBin; + } else { + displayStats.screenBrightnessBin = bin; + if (displayStats.screenState == Display.STATE_ON) { + if (oldBin >= 0) { + displayStats.screenBrightnessTimers[oldBin].stopRunningLocked( + elapsedRealtimeMs); + } + displayStats.screenBrightnessTimers[bin].startRunningLocked( + elapsedRealtimeMs); + } + overallBin = evaluateOverallScreenBrightnessBinLocked(); + } + + maybeUpdateOverallScreenBrightness(overallBin, elapsedRealtimeMs, uptimeMs); + } + + private int evaluateOverallScreenBrightnessBinLocked() { + int overallBin = -1; + final int numDisplays = getDisplayCount(); + for (int display = 0; display < numDisplays; display++) { + final int displayBrightnessBin; + if (mPerDisplayBatteryStats[display].screenState == Display.STATE_ON) { + displayBrightnessBin = mPerDisplayBatteryStats[display].screenBrightnessBin; + } else { + displayBrightnessBin = -1; + } + if (displayBrightnessBin > overallBin) { + overallBin = displayBrightnessBin; + } + } + return overallBin; + } + + private void maybeUpdateOverallScreenBrightness(int overallBin, long elapsedRealtimeMs, + long uptimeMs) { + if (mScreenBrightnessBin != overallBin) { + if (overallBin >= 0) { + mHistoryCur.states = (mHistoryCur.states & ~HistoryItem.STATE_BRIGHTNESS_MASK) + | (overallBin << HistoryItem.STATE_BRIGHTNESS_SHIFT); + if (DEBUG_HISTORY) { + Slog.v(TAG, "Screen brightness " + overallBin + " to: " + + Integer.toHexString(mHistoryCur.states)); + } + addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + } if (mScreenState == Display.STATE_ON) { if (mScreenBrightnessBin >= 0) { mScreenBrightnessTimer[mScreenBrightnessBin] .stopRunningLocked(elapsedRealtimeMs); } - mScreenBrightnessTimer[bin] - .startRunningLocked(elapsedRealtimeMs); + if (overallBin >= 0) { + mScreenBrightnessTimer[overallBin] + .startRunningLocked(elapsedRealtimeMs); + } } - mScreenBrightnessBin = bin; + mScreenBrightnessBin = overallBin; } } @@ -6693,6 +6979,31 @@ public class BatteryStatsImpl extends BatteryStats { return mScreenBrightnessTimer[brightnessBin]; } + @Override + public int getDisplayCount() { + return mPerDisplayBatteryStats.length; + } + + @Override + public long getDisplayScreenOnTime(int display, long elapsedRealtimeUs) { + return mPerDisplayBatteryStats[display].screenOnTimer.getTotalTimeLocked(elapsedRealtimeUs, + STATS_SINCE_CHARGED); + } + + @Override + public long getDisplayScreenDozeTime(int display, long elapsedRealtimeUs) { + return mPerDisplayBatteryStats[display].screenDozeTimer.getTotalTimeLocked( + elapsedRealtimeUs, STATS_SINCE_CHARGED); + } + + @Override + public long getDisplayScreenBrightnessTime(int display, int brightnessBin, + long elapsedRealtimeUs) { + final DisplayBatteryStats displayStats = mPerDisplayBatteryStats[display]; + return displayStats.screenBrightnessTimers[brightnessBin].getTotalTimeLocked( + elapsedRealtimeUs, STATS_SINCE_CHARGED); + } + @Override public long getInteractiveTime(long elapsedRealtimeUs, int which) { return mInteractiveTimer.getTotalTimeLocked(elapsedRealtimeUs, which); } @@ -10694,6 +11005,10 @@ public class BatteryStatsImpl extends BatteryStats { mScreenBrightnessTimer[i] = new StopwatchTimer(mClocks, null, -100-i, null, mOnBatteryTimeBase); } + + mPerDisplayBatteryStats = new DisplayBatteryStats[1]; + mPerDisplayBatteryStats[0] = new DisplayBatteryStats(mClocks, mOnBatteryTimeBase); + mInteractiveTimer = new StopwatchTimer(mClocks, null, -10, null, mOnBatteryTimeBase); mPowerSaveModeEnabledTimer = new StopwatchTimer(mClocks, null, -2, null, mOnBatteryTimeBase); @@ -10806,6 +11121,8 @@ public class BatteryStatsImpl extends BatteryStats { // Initialize the estimated battery capacity to a known preset one. mEstimatedBatteryCapacityMah = (int) mPowerProfile.getBatteryCapacity(); } + + setDisplayCountLocked(mPowerProfile.getNumDisplays()); } PowerProfile getPowerProfile() { @@ -10838,6 +11155,16 @@ public class BatteryStatsImpl extends BatteryStats { mExternalSync = sync; } + /** + * Initialize and set multi display timers and states. + */ + public void setDisplayCountLocked(int numDisplays) { + mPerDisplayBatteryStats = new DisplayBatteryStats[numDisplays]; + for (int i = 0; i < numDisplays; i++) { + mPerDisplayBatteryStats[i] = new DisplayBatteryStats(mClocks, mOnBatteryTimeBase); + } + } + public void updateDailyDeadlineLocked() { // Get the current time. long currentTimeMs = mDailyStartTimeMs = mClocks.currentTimeMillis(); @@ -11314,6 +11641,11 @@ public class BatteryStatsImpl extends BatteryStats { mScreenBrightnessTimer[i].reset(false, elapsedRealtimeUs); } + final int numDisplays = mPerDisplayBatteryStats.length; + for (int i = 0; i < numDisplays; i++) { + mPerDisplayBatteryStats[i].reset(elapsedRealtimeUs); + } + if (mPowerProfile != null) { mEstimatedBatteryCapacityMah = (int) mPowerProfile.getBatteryCapacity(); } else { @@ -12597,22 +12929,43 @@ public class BatteryStatsImpl extends BatteryStats { * is always 0 when the screen is not "ON" and whenever the rail energy is 0 (if supported). * To the extent that those assumptions are violated, the algorithm will err. * - * @param chargeUC amount of charge (microcoulombs) used by Display since this was last called. - * @param screenState screen state at the time this data collection was scheduled + * @param chargesUC amount of charge (microcoulombs) used by each Display since this was last + * called. + * @param screenStates each screen state at the time this data collection was scheduled */ @GuardedBy("this") - public void updateDisplayMeasuredEnergyStatsLocked(long chargeUC, int screenState, + public void updateDisplayMeasuredEnergyStatsLocked(long[] chargesUC, int[] screenStates, long elapsedRealtimeMs) { - if (DEBUG_ENERGY) Slog.d(TAG, "Updating display stats: " + chargeUC); + if (DEBUG_ENERGY) Slog.d(TAG, "Updating display stats: " + Arrays.toString(chargesUC)); if (mGlobalMeasuredEnergyStats == null) { return; } - final @StandardPowerBucket int powerBucket = - MeasuredEnergyStats.getDisplayPowerBucket(mScreenStateAtLastEnergyMeasurement); - mScreenStateAtLastEnergyMeasurement = screenState; + final int numDisplays; + if (mPerDisplayBatteryStats.length == screenStates.length) { + numDisplays = screenStates.length; + } else { + // if this point is reached, it will be reached every display state change. + // Rate limit the wtf logging to once every 100 display updates. + if (mDisplayMismatchWtfCount++ % 100 == 0) { + Slog.wtf(TAG, "Mismatch between PowerProfile reported display count (" + + mPerDisplayBatteryStats.length + + ") and PowerStatsHal reported display count (" + screenStates.length + + ")"); + } + // Keep the show going, use the shorter of the two. + numDisplays = mPerDisplayBatteryStats.length < screenStates.length + ? mPerDisplayBatteryStats.length : screenStates.length; + } - if (!mOnBatteryInternal || chargeUC <= 0) { + final int[] oldScreenStates = new int[numDisplays]; + for (int i = 0; i < numDisplays; i++) { + final int screenState = screenStates[i]; + oldScreenStates[i] = mPerDisplayBatteryStats[i].screenStateAtLastEnergyMeasurement; + mPerDisplayBatteryStats[i].screenStateAtLastEnergyMeasurement = screenState; + } + + if (!mOnBatteryInternal) { // There's nothing further to update. return; } @@ -12627,17 +12980,31 @@ public class BatteryStatsImpl extends BatteryStats { return; } - mGlobalMeasuredEnergyStats.updateStandardBucket(powerBucket, chargeUC); + long totalScreenOnChargeUC = 0; + for (int i = 0; i < numDisplays; i++) { + final long chargeUC = chargesUC[i]; + if (chargeUC <= 0) { + // There's nothing further to update. + continue; + } + + final @StandardPowerBucket int powerBucket = + MeasuredEnergyStats.getDisplayPowerBucket(oldScreenStates[i]); + mGlobalMeasuredEnergyStats.updateStandardBucket(powerBucket, chargeUC); + if (powerBucket == MeasuredEnergyStats.POWER_BUCKET_SCREEN_ON) { + totalScreenOnChargeUC += chargeUC; + } + } // Now we blame individual apps, but only if the display was ON. - if (powerBucket != MeasuredEnergyStats.POWER_BUCKET_SCREEN_ON) { + if (totalScreenOnChargeUC <= 0) { return; } // TODO(b/175726779): Consider unifying the code with the non-rail display power blaming. // NOTE: fg time is NOT pooled. If two uids are both somehow in fg, then that time is // 'double counted' and will simply exceed the realtime that elapsed. - // If multidisplay becomes a reality, this is probably more reasonable than pooling. + // TODO(b/175726779): collect per display uid visibility for display power attribution. // Collect total time since mark so that we can normalize power. final SparseDoubleArray fgTimeUsArray = new SparseDoubleArray(); @@ -12650,7 +13017,8 @@ public class BatteryStatsImpl extends BatteryStats { if (fgTimeUs == 0) continue; fgTimeUsArray.put(uid.getUid(), (double) fgTimeUs); } - distributeEnergyToUidsLocked(powerBucket, chargeUC, fgTimeUsArray, 0); + distributeEnergyToUidsLocked(MeasuredEnergyStats.POWER_BUCKET_SCREEN_ON, + totalScreenOnChargeUC, fgTimeUsArray, 0); } /** @@ -14556,7 +14924,12 @@ public class BatteryStatsImpl extends BatteryStats { public void initMeasuredEnergyStatsLocked(@Nullable boolean[] supportedStandardBuckets, String[] customBucketNames) { boolean supportedBucketMismatch = false; - mScreenStateAtLastEnergyMeasurement = mScreenState; + + final int numDisplays = mPerDisplayBatteryStats.length; + for (int i = 0; i < numDisplays; i++) { + final int screenState = mPerDisplayBatteryStats[i].screenState; + mPerDisplayBatteryStats[i].screenStateAtLastEnergyMeasurement = screenState; + } if (supportedStandardBuckets == null) { if (mGlobalMeasuredEnergyStats != null) { diff --git a/core/java/com/android/internal/os/PowerCalculator.java b/core/java/com/android/internal/os/PowerCalculator.java index 4979ecbae8cb..93d562c571f8 100644 --- a/core/java/com/android/internal/os/PowerCalculator.java +++ b/core/java/com/android/internal/os/PowerCalculator.java @@ -133,32 +133,6 @@ public abstract class PowerCalculator { } /** - * Returns either the measured energy converted to mAh or a usage-based estimate. - */ - protected static double getMeasuredOrEstimatedPower(@BatteryConsumer.PowerModel int powerModel, - long measuredEnergyUC, UsageBasedPowerEstimator powerEstimator, long durationMs) { - switch (powerModel) { - case BatteryConsumer.POWER_MODEL_MEASURED_ENERGY: - return uCtoMah(measuredEnergyUC); - case BatteryConsumer.POWER_MODEL_POWER_PROFILE: - default: - return powerEstimator.calculatePower(durationMs); - } - } - - /** - * Returns either the measured energy converted to mAh or a usage-based estimate. - */ - protected static double getMeasuredOrEstimatedPower( - long measuredEnergyUC, UsageBasedPowerEstimator powerEstimator, long durationMs) { - if (measuredEnergyUC != BatteryStats.POWER_DATA_UNAVAILABLE) { - return uCtoMah(measuredEnergyUC); - } else { - return powerEstimator.calculatePower(durationMs); - } - } - - /** * Prints formatted amount of power in milli-amp-hours. */ public static void printPowerMah(PrintWriter pw, double powerMah) { diff --git a/core/java/com/android/internal/os/ScreenPowerCalculator.java b/core/java/com/android/internal/os/ScreenPowerCalculator.java index 72ad4e72707a..2b634598bbbc 100644 --- a/core/java/com/android/internal/os/ScreenPowerCalculator.java +++ b/core/java/com/android/internal/os/ScreenPowerCalculator.java @@ -44,8 +44,8 @@ public class ScreenPowerCalculator extends PowerCalculator { // Minimum amount of time the screen should be on to start smearing drain to apps public static final long MIN_ACTIVE_TIME_FOR_SMEARING = 10 * DateUtils.MINUTE_IN_MILLIS; - private final UsageBasedPowerEstimator mScreenOnPowerEstimator; - private final UsageBasedPowerEstimator mScreenFullPowerEstimator; + private final UsageBasedPowerEstimator[] mScreenOnPowerEstimators; + private final UsageBasedPowerEstimator[] mScreenFullPowerEstimators; private static class PowerAndDuration { public long durationMs; @@ -53,11 +53,16 @@ public class ScreenPowerCalculator extends PowerCalculator { } public ScreenPowerCalculator(PowerProfile powerProfile) { - // TODO(b/200239964): update to support multidisplay. - mScreenOnPowerEstimator = new UsageBasedPowerEstimator( - powerProfile.getAveragePowerForOrdinal(POWER_GROUP_DISPLAY_SCREEN_ON, 0)); - mScreenFullPowerEstimator = new UsageBasedPowerEstimator( - powerProfile.getAveragePowerForOrdinal(POWER_GROUP_DISPLAY_SCREEN_FULL, 0)); + final int numDisplays = powerProfile.getNumDisplays(); + mScreenOnPowerEstimators = new UsageBasedPowerEstimator[numDisplays]; + mScreenFullPowerEstimators = new UsageBasedPowerEstimator[numDisplays]; + for (int display = 0; display < numDisplays; display++) { + mScreenOnPowerEstimators[display] = new UsageBasedPowerEstimator( + powerProfile.getAveragePowerForOrdinal(POWER_GROUP_DISPLAY_SCREEN_ON, display)); + mScreenFullPowerEstimators[display] = new UsageBasedPowerEstimator( + powerProfile.getAveragePowerForOrdinal(POWER_GROUP_DISPLAY_SCREEN_FULL, + display)); + } } @Override @@ -172,7 +177,7 @@ public class ScreenPowerCalculator extends PowerCalculator { case BatteryConsumer.POWER_MODEL_POWER_PROFILE: default: totalPowerAndDuration.powerMah = calculateTotalPowerFromBrightness(batteryStats, - rawRealtimeUs, statsType, totalPowerAndDuration.durationMs); + rawRealtimeUs); } } @@ -194,19 +199,25 @@ public class ScreenPowerCalculator extends PowerCalculator { return batteryStats.getScreenOnTime(rawRealtimeUs, statsType) / 1000; } - private double calculateTotalPowerFromBrightness(BatteryStats batteryStats, long rawRealtimeUs, - int statsType, long durationMs) { - double power = mScreenOnPowerEstimator.calculatePower(durationMs); - for (int i = 0; i < BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS; i++) { - final long brightnessTime = - batteryStats.getScreenBrightnessTime(i, rawRealtimeUs, statsType) / 1000; - final double binPowerMah = mScreenFullPowerEstimator.calculatePower(brightnessTime) - * (i + 0.5f) / BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS; - if (DEBUG && binPowerMah != 0) { - Slog.d(TAG, "Screen bin #" + i + ": time=" + brightnessTime - + " power=" + formatCharge(binPowerMah)); + private double calculateTotalPowerFromBrightness(BatteryStats batteryStats, + long rawRealtimeUs) { + final int numDisplays = mScreenOnPowerEstimators.length; + double power = 0; + for (int display = 0; display < numDisplays; display++) { + final long displayTime = batteryStats.getDisplayScreenOnTime(display, rawRealtimeUs) + / 1000; + power += mScreenOnPowerEstimators[display].calculatePower(displayTime); + for (int bin = 0; bin < BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS; bin++) { + final long brightnessTime = batteryStats.getDisplayScreenBrightnessTime(display, + bin, rawRealtimeUs) / 1000; + final double binPowerMah = mScreenFullPowerEstimators[display].calculatePower( + brightnessTime) * (bin + 0.5f) / BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS; + if (DEBUG && binPowerMah != 0) { + Slog.d(TAG, "Screen bin #" + bin + ": time=" + brightnessTime + + " power=" + formatCharge(binPowerMah)); + } + power += binPowerMah; } - power += binPowerMah; } return power; } diff --git a/core/java/com/android/internal/policy/SystemBarUtils.java b/core/java/com/android/internal/policy/SystemBarUtils.java new file mode 100644 index 000000000000..6bf1333097f7 --- /dev/null +++ b/core/java/com/android/internal/policy/SystemBarUtils.java @@ -0,0 +1,94 @@ +/* + * 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.internal.policy; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Insets; +import android.util.RotationUtils; +import android.view.DisplayCutout; +import android.view.Surface; + +import com.android.internal.R; + +/** + * Utility functions for system bars used by both window manager and System UI. + * + * @hide + */ +public final class SystemBarUtils { + + /** + * Gets the status bar height. + */ + public static int getStatusBarHeight(Context context) { + return getStatusBarHeight(context.getResources(), context.getDisplay().getCutout()); + } + + /** + * Gets the status bar height with a specific display cutout. + */ + public static int getStatusBarHeight(Resources res, DisplayCutout cutout) { + final int defaultSize = res.getDimensionPixelSize(R.dimen.status_bar_height); + final int safeInsetTop = cutout == null ? 0 : cutout.getSafeInsetTop(); + final int waterfallInsetTop = cutout == null ? 0 : cutout.getWaterfallInsets().top; + // The status bar height should be: + // Max(top cutout size, (status bar default height + waterfall top size)) + return Math.max(safeInsetTop, defaultSize + waterfallInsetTop); + } + + /** + * Gets the status bar height for a specific rotation. + */ + public static int getStatusBarHeightForRotation( + Context context, @Surface.Rotation int targetRot) { + final int rotation = context.getDisplay().getRotation(); + final DisplayCutout cutout = context.getDisplay().getCutout(); + + Insets insets = cutout == null ? Insets.NONE : Insets.of(cutout.getSafeInsets()); + Insets waterfallInsets = cutout == null ? Insets.NONE : cutout.getWaterfallInsets(); + // rotate insets to target rotation if needed. + if (rotation != targetRot) { + if (!insets.equals(Insets.NONE)) { + insets = RotationUtils.rotateInsets( + insets, RotationUtils.deltaRotation(rotation, targetRot)); + } + if (!waterfallInsets.equals(Insets.NONE)) { + waterfallInsets = RotationUtils.rotateInsets( + waterfallInsets, RotationUtils.deltaRotation(rotation, targetRot)); + } + } + final int defaultSize = + context.getResources().getDimensionPixelSize(R.dimen.status_bar_height); + // The status bar height should be: + // Max(top cutout size, (status bar default height + waterfall top size)) + return Math.max(insets.top, defaultSize + waterfallInsets.top); + } + + /** + * Gets the height of area above QQS where battery/time go in notification panel. The height + * equals to status bar height if status bar height is bigger than the + * {@link R.dimen#quick_qs_offset_height}. + */ + public static int getQuickQsOffsetHeight(Context context) { + final int defaultSize = context.getResources().getDimensionPixelSize( + R.dimen.quick_qs_offset_height); + final int statusBarHeight = getStatusBarHeight(context); + // Equals to status bar height if status bar height is bigger. + return Math.max(defaultSize, statusBarHeight); + } +} diff --git a/core/java/com/android/internal/util/LatencyTracker.java b/core/java/com/android/internal/util/LatencyTracker.java index 5144a91706a1..4c519f4c779f 100644 --- a/core/java/com/android/internal/util/LatencyTracker.java +++ b/core/java/com/android/internal/util/LatencyTracker.java @@ -117,6 +117,11 @@ public class LatencyTracker { */ public static final int ACTION_LOCKSCREEN_UNLOCK = 11; + /** + * Time it takes to switch users. + */ + public static final int ACTION_USER_SWITCH = 12; + private static final int[] ACTIONS_ALL = { ACTION_EXPAND_PANEL, ACTION_TOGGLE_RECENTS, @@ -129,7 +134,8 @@ public class LatencyTracker { ACTION_START_RECENTS_ANIMATION, ACTION_ROTATE_SCREEN_SENSOR, ACTION_ROTATE_SCREEN_CAMERA_CHECK, - ACTION_LOCKSCREEN_UNLOCK + ACTION_LOCKSCREEN_UNLOCK, + ACTION_USER_SWITCH }; /** @hide */ @@ -145,7 +151,8 @@ public class LatencyTracker { ACTION_START_RECENTS_ANIMATION, ACTION_ROTATE_SCREEN_SENSOR, ACTION_ROTATE_SCREEN_CAMERA_CHECK, - ACTION_LOCKSCREEN_UNLOCK + ACTION_LOCKSCREEN_UNLOCK, + ACTION_USER_SWITCH }) @Retention(RetentionPolicy.SOURCE) public @interface Action { @@ -163,7 +170,8 @@ public class LatencyTracker { FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_START_RECENTS_ANIMATION, FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN_SENSOR, FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN_CAMERA_CHECK, - FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_LOCKSCREEN_UNLOCK + FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_LOCKSCREEN_UNLOCK, + FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_USER_SWITCH }; private static LatencyTracker sLatencyTracker; @@ -247,6 +255,8 @@ public class LatencyTracker { return "ACTION_ROTATE_SCREEN_SENSOR"; case 12: return "ACTION_LOCKSCREEN_UNLOCK"; + case 13: + return "ACTION_USER_SWITCH"; default: throw new IllegalArgumentException("Invalid action"); } @@ -424,7 +434,7 @@ public class LatencyTracker { // start counting timeout. mTimeoutRunnable = timeoutAction; BackgroundThread.getHandler() - .postDelayed(mTimeoutRunnable, TimeUnit.SECONDS.toMillis(2)); + .postDelayed(mTimeoutRunnable, TimeUnit.SECONDS.toMillis(15)); } void end() { diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto index 4af9d75682bb..061ecc8f7488 100644 --- a/core/proto/android/server/windowmanagerservice.proto +++ b/core/proto/android/server/windowmanagerservice.proto @@ -69,6 +69,7 @@ message RootWindowContainerProto { // know what activity types to check for when invoking splitscreen multi-window. optional bool is_home_recents_component = 6; repeated IdentifierProto pending_activities = 7 [deprecated=true]; + optional int32 default_min_size_resizable_task = 8; } message BarControllerProto { @@ -363,6 +364,7 @@ message ActivityRecordProto { optional bool translucent = 30; optional bool pip_auto_enter_enabled = 31; optional bool in_size_compat_mode = 32; + optional float min_aspect_ratio = 33; } /* represents WindowToken */ diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 1255dad27eed..3968193e044f 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -4866,15 +4866,15 @@ android:protectionLevel="signature|privileged" /> <!-- An application needs this permission for - {@link android.provider.Settings#ACTION_SETTINGS_LARGE_SCREEN_DEEP_LINK} to show its - {@link android.app.Activity} in 2-pane of Settings app. --> - <permission android:name="android.permission.LAUNCH_TWO_PANE_SETTINGS_DEEP_LINK" + {@link android.provider.Settings#ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY} to show its + {@link android.app.Activity} embedded in Settings app. --> + <permission android:name="android.permission.LAUNCH_MULTI_PANE_SETTINGS_DEEP_LINK" android:protectionLevel="signature|preinstalled" /> <!-- @SystemApi {@link android.app.Activity} should require this permission to ensure that only - the settings app can embed it in a 2-pane window. + the settings app can embed it in a multi pane window. @hide --> - <permission android:name="android.permission.ALLOW_PLACE_IN_TWO_PANE_SETTINGS" + <permission android:name="android.permission.ALLOW_PLACE_IN_MULTI_PANE_SETTINGS" android:protectionLevel="signature" /> <!-- @SystemApi Allows applications to set a live wallpaper. diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml index c33257df730e..c27ff94bfc94 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -1452,7 +1452,7 @@ <string name="usb_power_notification_message" msgid="7284765627437897702">"جارٍ شحن الجهاز المتصل. انقر لعرض خيارات أكثر."</string> <string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"تم اكتشاف ملحق صوتي تناظري"</string> <string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"الجهاز الذي تم توصيله بالهاتف غير متوافق معه. انقر للحصول على المزيد من المعلومات."</string> - <string name="adb_active_notification_title" msgid="408390247354560331">"تم توصيل أداة تصحيح أخطاء الجهاز عبر USB"</string> + <string name="adb_active_notification_title" msgid="408390247354560331">"تم توصيل USB لتصحيح أخطاء الجهاز"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"انقر لإيقاف تصحيح أخطاء الجهاز عبر USB."</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"اختيار إيقاف تصحيح أخطاء USB."</string> <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"تم تفعيل ميزة \"تصحيح الأخطاء اللاسلكي\"."</string> diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml index 8aafa0a6ac70..f9786ed3d3e0 100644 --- a/core/res/res/values-as/strings.xml +++ b/core/res/res/values-as/strings.xml @@ -291,12 +291,12 @@ <string name="notification_channel_retail_mode" msgid="3732239154256431213">"খুচুৰা ডেম\'"</string> <string name="notification_channel_usb" msgid="1528280969406244896">"ইউএছবি সংযোগ"</string> <string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"এপ্ চলি আছে"</string> - <string name="notification_channel_foreground_service" msgid="7102189948158885178">"বেটাৰি খৰচ কৰা এপসমূহ"</string> + <string name="notification_channel_foreground_service" msgid="7102189948158885178">"বেটাৰী খৰচ কৰা এপ্সমূহ"</string> <string name="notification_channel_accessibility_magnification" msgid="1707913872219798098">"বিবৰ্ধন"</string> <string name="notification_channel_accessibility_security_policy" msgid="1727787021725251912">"সাধ্য সুবিধাৰ ব্যৱহাৰ"</string> - <string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g>এ বেটাৰি ব্যৱহাৰ কৰি আছে"</string> - <string name="foreground_service_apps_in_background" msgid="7340037176412387863">"<xliff:g id="NUMBER">%1$d</xliff:g>টা এপে বেটাৰি ব্যৱহাৰ কৰি আছে"</string> - <string name="foreground_service_tap_for_details" msgid="9078123626015586751">"বেটাৰি আৰু ডেটাৰ ব্যৱহাৰৰ বিষয়ে বিশদভাৱে জানিবলৈ টিপক"</string> + <string name="foreground_service_app_in_background" msgid="1439289699671273555">"<xliff:g id="APP_NAME">%1$s</xliff:g>এ বেটাৰী ব্যৱহাৰ কৰি আছে"</string> + <string name="foreground_service_apps_in_background" msgid="7340037176412387863">"<xliff:g id="NUMBER">%1$d</xliff:g>টা এপে বেটাৰী ব্যৱহাৰ কৰি আছে"</string> + <string name="foreground_service_tap_for_details" msgid="9078123626015586751">"বেটাৰী আৰু ডেটাৰ ব্যৱহাৰৰ বিষয়ে সবিশেষ জানিবলৈ টিপক"</string> <string name="foreground_service_multiple_separator" msgid="5002287361849863168">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string> <string name="safeMode" msgid="8974401416068943888">"সুৰক্ষিত ম\'ড"</string> <string name="android_system_label" msgid="5974767339591067210">"Android ছিষ্টেম"</string> @@ -389,7 +389,7 @@ <string name="permlab_systemAlertWindow" msgid="5757218350944719065">"এই এপটো অইন এপৰ ওপৰত প্ৰদৰ্শিত হ\'ব পাৰে"</string> <string name="permdesc_systemAlertWindow" msgid="1145660714855738308">"এই এপ্টো অন্য এপৰ ওপৰত বা স্ক্ৰীনৰ অন্য অংশত প্ৰদৰ্শিত হ\'ব পাৰে। এই কাৰ্যই এপৰ স্বাভাৱিক ব্যৱহাৰত ব্যাঘাত জন্মাব পাৰে আৰু অন্য এপ্সমূহক স্ক্ৰীনত কেনেকৈ দেখা পোৱা যায় সেইটো সলনি কৰিব পাৰে।"</string> <string name="permlab_runInBackground" msgid="541863968571682785">"নেপথ্যত চলিব পাৰে"</string> - <string name="permdesc_runInBackground" msgid="4344539472115495141">"এই এপটো নেপথ্যত চলিব পাৰে। ইয়াৰ ফলত বেটাৰি সোনকালে শেষ হ\'ব পাৰে।"</string> + <string name="permdesc_runInBackground" msgid="4344539472115495141">"এই এপ্টো নেপথ্যত চলিব পাৰে। ইয়াৰ ফলত বেটাৰী সোনকালে শেষ হ’ব পাৰে।"</string> <string name="permlab_useDataInBackground" msgid="783415807623038947">"নেপথ্যত ডেটা ব্যৱহাৰ কৰিব পাৰে"</string> <string name="permdesc_useDataInBackground" msgid="1230753883865891987">"এই এপটোৱে নেপথ্যত ডেটা ব্যৱহাৰ কৰিব পাৰে। ইয়াৰ ফলত ডেটা বেছি খৰছ হ\'ব পাৰে।"</string> <string name="permlab_persistentActivity" msgid="464970041740567970">"এপক সদায়ে চলি থকা কৰক"</string> @@ -1462,8 +1462,8 @@ <string name="permdesc_requestInstallPackages" msgid="3969369278325313067">"পেকেজ ইনষ্টল কৰাৰ অনুৰোধ প্ৰেৰণ কৰিবলৈ এপটোক অনুমতি দিয়ে।"</string> <string name="permlab_requestDeletePackages" msgid="2541172829260106795">"পেকেজ মচাৰ অনুৰোধ কৰিব পাৰে"</string> <string name="permdesc_requestDeletePackages" msgid="6133633516423860381">"এপটোক পেকেজবোৰ মচাৰ অনুৰোধ কৰিবলৈ দিয়ে।"</string> - <string name="permlab_requestIgnoreBatteryOptimizations" msgid="7646611326036631439">"বেটাৰি অপ্টিমাইজেশ্বন উপেক্ষা কৰিবলৈ বিচাৰক"</string> - <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"কোনো এপক সেই এপটোৰ বাবে বেটাৰি অপ্টিমাইজেশ্বন উপেক্ষা কৰিবলৈ অনুমতি বিচাৰিবলৈ দিয়ে।"</string> + <string name="permlab_requestIgnoreBatteryOptimizations" msgid="7646611326036631439">"বেটাৰী অপ্টিমাইজেশ্বন উপেক্ষা কৰিবলৈ বিচাৰক"</string> + <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"কোনো এপক সেই এপ্টোৰ বাবে বেটাৰী অপ্টিমাইজেশ্বন উপেক্ষা কৰিবলৈ অনুমতি বিচাৰিবলৈ দিয়ে।"</string> <string name="permlab_queryAllPackages" msgid="2928450604653281650">"আটাইবোৰ পেকেজত প্ৰশ্ন সোধক"</string> <string name="permdesc_queryAllPackages" msgid="5339069855520996010">"এপক আটাইবোৰ ইনষ্টল কৰি থোৱা পেকেজ চাবলৈ দিয়ে।"</string> <string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"জুম নিয়ন্ত্ৰণ কৰিবলৈ দুবাৰ টিপক"</string> @@ -2103,10 +2103,10 @@ <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"অধিক জানক"</string> <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Android 12ত Androidৰ অভিযোজিত জাননীক উন্নত জাননীৰ দ্বাৰা সলনি কৰা হৈছে। এই সুবিধাটোৱে পৰামৰ্শ দিয়া কাৰ্য আৰু প্ৰত্যুত্তৰ দেখুৱায় আৰু আপোনাৰ জাননীসমূহ শৃংখলাবদ্ধ কৰে।\n\nউন্নত জাননীয়ে সম্পৰ্কৰ নাম আৰু বাৰ্তাৰ দৰে ব্যক্তিগত তথ্যকে ধৰি জাননীৰ সমল এক্সেছ কৰিব পাৰে। এই সুবিধাটোৱে জাননী অগ্ৰাহ্য কৰিব অথবা জাননীৰ প্ৰতি সঁহাৰি জনাবও পাৰে, যেনে ফ’ন কলৰ উত্তৰ দিয়া আৰু অসুবিধা নিদিব সুবিধাটো নিয়ন্ত্ৰণ কৰা আদি।"</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"ৰুটিন ম’ডৰ তথ্য জাননী"</string> - <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"চ্চাৰ্জ কৰাৰ সচৰাচৰ সময়ৰ আগতেই বেটাৰি শেষ হ’ব পাৰে"</string> - <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"বেটাৰিৰ খৰচ কমাবলৈ বেটাৰি সঞ্চয়কাৰী অন কৰা হৈছে"</string> + <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"চাৰ্জ কৰাৰ সচৰাচৰ সময়ৰ আগতেই বেটাৰী শেষ হ’ব পাৰে"</string> + <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"বেটাৰীৰ খৰচ কমাবলৈ বেটাৰী সঞ্চয়কাৰী অন কৰা হৈছে"</string> <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"বেটাৰী সঞ্চয়কাৰী"</string> - <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"বেটাৰি সঞ্চয়কাৰী অফ কৰা হ’ল"</string> + <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"বেটাৰী সঞ্চয়কাৰী অফ কৰা হ’ল"</string> <string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"ফ\'নটোত পর্যাপ্ত পৰিমাণে চার্জ আছে। সুবিধাবোৰ আৰু সীমাবদ্ধ কৰা নাই।"</string> <string name="battery_saver_charged_notification_summary" product="tablet" msgid="4426317048139996888">"টেবলেটটোত পর্যাপ্ত পৰিমাণে চার্জ আছে। সুবিধাবোৰ আৰু সীমাবদ্ধ কৰা নাই।"</string> <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"ডিভাইচটোত পর্যাপ্ত পৰিমাণে চার্জ আছে। সুবিধাবোৰ আৰু সীমাবদ্ধ কৰা নাই।"</string> diff --git a/core/res/res/values-land/dimens.xml b/core/res/res/values-land/dimens.xml index ca549aeba1f5..f1e5888d61b9 100644 --- a/core/res/res/values-land/dimens.xml +++ b/core/res/res/values-land/dimens.xml @@ -27,8 +27,6 @@ <dimen name="password_keyboard_spacebar_vertical_correction">2dip</dimen> <dimen name="preference_widget_width">72dp</dimen> - <!-- Height of the status bar --> - <dimen name="status_bar_height">@dimen/status_bar_height_landscape</dimen> <!-- Height of area above QQS where battery/time go --> <dimen name="quick_qs_offset_height">48dp</dimen> <!-- Default height of an action bar. --> diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml index eaed8c835bc1..8d4956d0cad0 100644 --- a/core/res/res/values-mr/strings.xml +++ b/core/res/res/values-mr/strings.xml @@ -299,7 +299,7 @@ <string name="foreground_service_tap_for_details" msgid="9078123626015586751">"बॅटरी आणि डेटा वापराच्या तपशीलांसाठी टॅप करा"</string> <string name="foreground_service_multiple_separator" msgid="5002287361849863168">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string> <string name="safeMode" msgid="8974401416068943888">"सुरक्षित मोड"</string> - <string name="android_system_label" msgid="5974767339591067210">"Android सिस्टम"</string> + <string name="android_system_label" msgid="5974767339591067210">"Android सिस्टीम"</string> <string name="user_owner_label" msgid="8628726904184471211">"वैयक्तिक प्रोफाइलवर स्विच करा"</string> <string name="managed_profile_label" msgid="7316778766973512382">"कार्य प्रोफाइलवर स्विच करा"</string> <string name="permgrouplab_contacts" msgid="4254143639307316920">"संपर्क"</string> diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml index 7b80f606c99e..70e0d1f37e63 100644 --- a/core/res/res/values-pa/strings.xml +++ b/core/res/res/values-pa/strings.xml @@ -358,7 +358,7 @@ <string name="permdesc_answerPhoneCalls" msgid="894386681983116838">"ਐਪ ਨੂੰ ਆਉਣ ਵਾਲੀ ਫ਼ੋਨ ਕਾਲ ਦਾ ਜਵਾਬ ਦੇਣ ਦੀ ਇਜਾਜ਼ਤ ਦਿੰਦੀ ਹੈ।"</string> <string name="permlab_receiveSms" msgid="505961632050451881">"ਲਿਖਤ ਸੁਨੇਹੇ (SMS) ਪ੍ਰਾਪਤ ਕਰੋ"</string> <string name="permdesc_receiveSms" msgid="1797345626687832285">"ਐਪ ਨੂੰ SMS ਸੁਨੇਹੇ ਪ੍ਰਾਪਤ ਕਰਨ ਅਤੇ ਉਹਨਾਂ ਦੀ ਪ੍ਰਕਿਰਿਆ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਇਸਦਾ ਮਤਲਬ ਹੈ ਕਿ ਐਪ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਤੇ ਭੇਜੇ ਗਏ ਸੁਨੇਹਿਆਂ ਨੂੰ ਤੁਹਾਨੂੰ ਦਿਖਾਏ ਬਿਨਾਂ ਨਿਰੀਖਣ ਕਰ ਸਕਦੀ ਹੈ ਜਾਂ ਮਿਟਾ ਸਕਦੀ ਹੈ।"</string> - <string name="permlab_receiveMms" msgid="4000650116674380275">"ਟੈਕਸਟ ਸੁਨੇਹੇ (MMS) ਪੜ੍ਹੋ"</string> + <string name="permlab_receiveMms" msgid="4000650116674380275">"ਲਿਖਤ ਸੁਨੇਹੇ (MMS) ਪ੍ਰਾਪਤ ਕਰੋ"</string> <string name="permdesc_receiveMms" msgid="958102423732219710">"ਐਪ ਨੂੰ MMS ਸੁਨੇਹੇ ਪ੍ਰਾਪਤ ਕਰਨ ਅਤੇ ਉਹਨਾਂ ਦੀ ਪ੍ਰਕਿਰਿਆ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਇਸਦਾ ਮਤਲਬ ਹੈ ਕਿ ਐਪ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਤੇ ਭੇਜੇ ਗਏ ਸੁਨੇਹਿਆਂ ਨੂੰ ਤੁਹਾਨੂੰ ਦਿਖਾਏ ਬਿਨਾਂ ਨਿਰੀਖਣ ਕਰ ਸਕਦੀ ਹੈ ਜਾਂ ਮਿਟਾ ਸਕਦੀ ਹੈ।"</string> <string name="permlab_bindCellBroadcastService" msgid="586746677002040651">"ਸੈੱਲ ਪ੍ਰਸਾਰਨ ਸੁਨੇਹਿਆਂ ਨੂੰ ਅੱਗੇ ਭੇਜੋ"</string> <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"ਐਪ ਨੂੰ ਸੈੱਲ ਪ੍ਰਸਾਰਨ ਸੁਨੇਹਿਆਂ ਦੇ ਪ੍ਰਾਪਤ ਹੁੰਦੇ ਹੀ ਉਹਨਾਂ ਨੂੰ ਅੱਗੇ ਭੇਜਣ ਲਈ ਸੈੱਲ ਪ੍ਰਸਾਰਨ ਮਾਡਿਊਲ ਨਾਲ ਜੋੜਨ ਦੀ ਇਜਾਜ਼ਤ ਦਿੱਤੀ ਜਾਂਦੀ ਹੈ। ਸੈੱਲ ਪ੍ਰਸਾਰਨ ਸੁਚੇਤਨਾਵਾਂ ਤੁਹਾਨੂੰ ਸੰਕਟਕਾਲੀ ਸਥਿਤੀਆਂ ਦੀ ਚਿਤਾਵਨੀ ਦੇਣ ਲਈ ਕੁਝ ਟਿਕਾਣਿਆਂ \'ਤੇ ਪ੍ਰਦਾਨ ਕੀਤੀਆਂ ਜਾਂਦੀਆਂ ਹਨ। ਭੈੜੀਆਂ ਐਪਾਂ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਦੀ ਕਾਰਗੁਜ਼ਾਰੀ ਜਾਂ ਓਪਰੇਸ਼ਨ ਵਿੱਚ ਵਿਘਨ ਪਾ ਸਕਦੀਆਂ ਹਨ ਜਦੋਂ ਇੱਕ ਸੰਕਟਕਾਲੀ ਸੈੱਲ ਪ੍ਰਸਾਰਨ ਪ੍ਰਾਪਤ ਕੀਤਾ ਜਾਂਦਾ ਹੈ।"</string> @@ -374,7 +374,7 @@ <string name="permdesc_readSms" product="tablet" msgid="7912990447198112829">"ਇਹ ਐਪ ਤੁਹਾਡੇ ਟੈਬਲੈੱਟ \'ਤੇ ਸਟੋਰ ਕੀਤੇ ਸਾਰੇ SMS (ਲਿਖਤ) ਸੁਨੇਹਿਆਂ ਨੂੰ ਪੜ੍ਹ ਸਕਦੀ ਹੈ।"</string> <string name="permdesc_readSms" product="tv" msgid="3054753345758011986">"ਇਹ ਐਪ ਤੁਹਾਡੇ Android TV ਡੀਵਾਈਸ \'ਤੇ ਸਟੋਰ ਕੀਤੇ ਸਾਰੇ SMS (ਲਿਖਤ) ਸੁਨੇਹਿਆਂ ਨੂੰ ਪੜ੍ਹ ਸਕਦੀ ਹੈ।"</string> <string name="permdesc_readSms" product="default" msgid="774753371111699782">"ਇਹ ਐਪ ਤੁਹਾਡੇ ਫ਼ੋਨ \'ਤੇ ਸਟੋਰ ਕੀਤੇ ਸਾਰੇ SMS (ਲਿਖਤ) ਸੁਨੇਹਿਆਂ ਨੂੰ ਪੜ੍ਹ ਸਕਦੀ ਹੈ।"</string> - <string name="permlab_receiveWapPush" msgid="4223747702856929056">"ਟੈਕਸਟ ਸੁਨੇਹੇ (WAP) ਪ੍ਰਾਪਤ ਕਰੋ"</string> + <string name="permlab_receiveWapPush" msgid="4223747702856929056">"ਲਿਖਤ ਸੁਨੇਹੇ (WAP) ਪ੍ਰਾਪਤ ਕਰੋ"</string> <string name="permdesc_receiveWapPush" msgid="1638677888301778457">"ਐਪ ਨੂੰ WAP ਸੁਨੇਹੇ ਪ੍ਰਾਪਤ ਕਰਨ ਅਤੇ ਉਹਨਾਂ ਦੀ ਪ੍ਰਕਿਰਿਆ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਇਸ ਇਜਾਜ਼ਤ ਵਿੱਚ ਸ਼ਾਮਲ ਹੈ ਐਪ ਦੀ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਤੇ ਭੇਜੇ ਗਏ ਸੁਨੇਹਿਆਂ ਨੂੰ ਤੁਹਾਨੂੰ ਦਿਖਾਏ ਬਿਨਾਂ ਨਿਰੀਖਣ ਕਰਨ ਅਤੇ ਮਿਟਾਉਣ ਦੀ ਸਮਰੱਥਾ।"</string> <string name="permlab_getTasks" msgid="7460048811831750262">"ਚੱਲ ਰਹੇ ਐਪਸ ਮੁੜ ਪ੍ਰਾਪਤ ਕਰੋ"</string> <string name="permdesc_getTasks" msgid="7388138607018233726">"ਐਪ ਨੂੰ ਵਰਤਮਾਨ ਵਿੱਚ ਅਤੇ ਹੁਣੇ ਜਿਹੇ ਚੱਲ ਰਹੇ ਕੰਮਾਂ ਬਾਰੇ ਵਿਸਤ੍ਰਿਤ ਜਾਣਕਾਰੀ ਮੁੜ ਪ੍ਰਾਪਤ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਇਹ ਐਪ ਨੂੰ ਇਸ ਬਾਰੇ ਜਾਣਕਾਰੀ ਖੋਜਣ ਦੀ ਆਗਿਆ ਦੇ ਸਕਦਾ ਹੈ ਕਿ ਡੀਵਾਈਸ ਤੇ ਕਿਹੜੀਆਂ ਐਪਲੀਕੇਸ਼ਨਾਂ ਵਰਤੀਆਂ ਜਾਂਦੀਆਂ ਹਨ।"</string> @@ -1046,7 +1046,7 @@ <string name="searchview_description_query" msgid="7430242366971716338">"ਖੋਜ ਪੁੱਛਗਿੱਛ"</string> <string name="searchview_description_clear" msgid="1989371719192982900">"ਸਵਾਲ ਹਟਾਓ"</string> <string name="searchview_description_submit" msgid="6771060386117334686">"ਸਵਾਲ ਪ੍ਰਸਤੁਤ ਕਰੋ"</string> - <string name="searchview_description_voice" msgid="42360159504884679">"ਵੌਇਸ ਖੋਜ"</string> + <string name="searchview_description_voice" msgid="42360159504884679">"ਅਵਾਜ਼ੀ ਖੋਜ"</string> <string name="enable_explore_by_touch_warning_title" msgid="5095399706284943314">"ਕੀ ਸਪੱਰਸ਼ ਰਾਹੀਂ ਪੜਚੋਲ ਕਰੋ ਨੂੰ ਚਾਲੂ ਕਰਨਾ ਹੈ?"</string> <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="1037295476738940824">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> \'ਸਪੱਰਸ਼ ਰਾਹੀਂ ਪੜਚੋਲ\' ਨੂੰ ਸਮਰੱਥ ਬਣਾਉਣਾ ਚਾਹੁੰਦੀ ਹੈ। ਜਦੋਂ \'ਸਪੱਰਸ਼ ਰਾਹੀਂ ਪੜਚੋਲ\' ਨੂੰ ਚਾਲੂ ਕੀਤਾ ਜਾਂਦਾ ਹੈ, ਤਾਂ ਤੁਸੀਂ ਇਸ ਬਾਰੇ ਵੇਰਵੇ ਸੁਣ ਜਾਂ ਦੇਖ ਸਕਦੇ ਹੋ ਕਿ ਤੁਹਾਡੀ ਉਂਗਲੀ ਦੇ ਹੇਠਾਂ ਕੀ ਹੈ ਜਾਂ ਟੈਬਲੈੱਟ ਨਾਲ ਇੰਟਰੈਕਟ ਕਰਨ ਲਈ ਸੰਕੇਤਾਂ ਦੀ ਪਾਲਣਾ ਕਰ ਸਕਦੇ ਹੋ।"</string> <string name="enable_explore_by_touch_warning_message" product="default" msgid="4312979647356179250">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ਸਪਰਸ਼ ਰਾਹੀਂ ਪੜਚੋਲ ਕਰੋ ਨੂੰ ਚਾਲੂ ਕਰਨਾ ਚਾਹੁੰਦਾ ਹੈ। ਜਦੋਂ ਸਪਰਸ਼ ਰਾਹੀਂ ਪੜਚੋਲ ਕਰੋ ਨੂੰ ਚਾਲੂ ਕੀਤਾ ਜਾਂਦਾ ਹੈ, ਤਾਂ ਤੁਸੀਂ ਇਸ ਬਾਰੇ ਵੇਰਵੇ ਸੁਣ ਜਾਂ ਦੇਖ ਸਕਦੇ ਹੋ ਤਿ ਤੁਹਾਡੀ ਉਂਗਲੀ ਦੇ ਹੇਠਾਂ ਕੀ ਹੈ ਜਾਂ ਫ਼ੋਨ ਨਾਲ ਇੰਟਰੈਕਟ ਕਰਨ ਲਈ ਸੰਕੇਤ ਪਰਫੌਰਮ ਕਰ ਸਕਦੇ ਹੋ।"</string> @@ -2010,7 +2010,7 @@ <string name="app_category_image" msgid="7307840291864213007">"ਫ਼ੋਟੋਆਂ ਅਤੇ ਚਿੱਤਰ"</string> <string name="app_category_social" msgid="2278269325488344054">"ਸਮਾਜਕ ਅਤੇ ਸੰਚਾਰ"</string> <string name="app_category_news" msgid="1172762719574964544">"ਖਬਰਾਂ ਅਤੇ ਰਸਾਲੇ"</string> - <string name="app_category_maps" msgid="6395725487922533156">"Maps ਅਤੇ ਨੈਵੀਗੇਸ਼ਨ"</string> + <string name="app_category_maps" msgid="6395725487922533156">"ਨਕਸ਼ੇ ਅਤੇ ਨੈਵੀਗੇਸ਼ਨ"</string> <string name="app_category_productivity" msgid="1844422703029557883">"ਉਤਪਾਦਕਤਾ"</string> <string name="app_category_accessibility" msgid="6643521607848547683">"ਪਹੁੰਚਯੋਗਤਾ"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"ਡੀਵਾਈਸ ਸਟੋਰੇਜ"</string> diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml index 1baaa1f3607d..b27af3447e66 100644 --- a/core/res/res/values-ta/strings.xml +++ b/core/res/res/values-ta/strings.xml @@ -176,10 +176,10 @@ <string name="contentServiceSync" msgid="2341041749565687871">"ஒத்திசை"</string> <string name="contentServiceSyncNotificationTitle" msgid="5766411446676388623">"ஒத்திசைக்க முடியவில்லை"</string> <string name="contentServiceTooManyDeletesNotificationDesc" msgid="4562226280528716090">"அதிகளவிலான <xliff:g id="CONTENT_TYPE">%s</xliff:g> உள்ளடக்க வகைகளை நீக்க முயன்றுள்ளீர்கள்."</string> - <string name="low_memory" product="tablet" msgid="5557552311566179924">"டேப்லெட் சேமிப்பிடம் நிரம்பியது. இடத்தைக் காலியாக்க சில கோப்புகளை அழிக்கவும்."</string> - <string name="low_memory" product="watch" msgid="3479447988234030194">"வாட்ச் சேமிப்பிடம் நிரம்பியது. இடத்தைக் காலியாக்க சில கோப்புகளை நீக்கவும்."</string> + <string name="low_memory" product="tablet" msgid="5557552311566179924">"டேப்லெட் சேமிப்பிடம் நிரம்பியது. இடத்தைக் காலியாக்க சில ஃபைல்களை அழிக்கவும்."</string> + <string name="low_memory" product="watch" msgid="3479447988234030194">"வாட்ச் சேமிப்பிடம் நிரம்பியது. இடத்தைக் காலியாக்க சில ஃபைல்களை நீக்கவும்."</string> <string name="low_memory" product="tv" msgid="6663680413790323318">"Android TVயின் சேமிப்பிடம் நிரம்பிவிட்டது. இடத்தைக் காலியாக்க சில ஃபைல்களை நீக்கவும்."</string> - <string name="low_memory" product="default" msgid="2539532364144025569">"மொபைல் சேமிப்பிடம் நிரம்பியது. இடத்தைக் காலியாக்க சில கோப்புகளை அழிக்கவும்."</string> + <string name="low_memory" product="default" msgid="2539532364144025569">"மொபைல் சேமிப்பிடம் நிரம்பியது. இடத்தைக் காலியாக்க சில ஃபைல்களை அழிக்கவும்."</string> <plurals name="ssl_ca_cert_warning" formatted="false" msgid="2288194355006173029"> <item quantity="other">சான்றிதழ் அங்கீகாரங்கள் நிறுவப்பட்டன</item> <item quantity="one">சான்றிதழ் அங்கீகாரம் நிறுவப்பட்டது</item> @@ -311,7 +311,7 @@ <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS அனுப்பலாம், வந்த SMSகளைப் பார்க்கலாம்"</string> <string name="permgrouplab_storage" msgid="1938416135375282333">"ஃபைல்களும் மீடியாவும்"</string> - <string name="permgroupdesc_storage" msgid="6351503740613026600">"உங்கள் சாதனத்தில் உள்ள படங்கள், மீடியா மற்றும் கோப்புகளை அணுக வேண்டும்"</string> + <string name="permgroupdesc_storage" msgid="6351503740613026600">"உங்கள் சாதனத்தில் உள்ள படங்கள், மீடியா மற்றும் ஃபைல்களை அணுக வேண்டும்"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"மைக்ரோஃபோன்"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"ஒலிப் பதிவு செய்யலாம்"</string> <string name="permgrouplab_activityRecognition" msgid="3324466667921775766">"உடல் செயல்பாடுகள்"</string> @@ -1413,7 +1413,7 @@ <string name="ext_media_new_notification_message" product="tv" msgid="216863352100263668">"அமைக்கத் தேர்ந்தெடுங்கள்"</string> <string name="ext_media_new_notification_message" product="automotive" msgid="5140127881613227162">"சாதனத்தை ரீஃபார்மேட் செய்ய வேண்டியிருக்கும். வெளியேற்ற தட்டவும்."</string> <string name="ext_media_ready_notification_message" msgid="777258143284919261">"படங்களையும் மீடியாவையும் மாற்றலாம்"</string> - <string name="ext_media_ready_notification_message" product="tv" msgid="8847134811163165935">"மீடியா கோப்புகளை உலாவுக"</string> + <string name="ext_media_ready_notification_message" product="tv" msgid="8847134811163165935">"மீடியா ஃபைல்களை உலாவுக"</string> <string name="ext_media_unmountable_notification_title" msgid="4895444667278979910">"<xliff:g id="NAME">%s</xliff:g> இல் சிக்கல்"</string> <string name="ext_media_unmountable_notification_title" product="automotive" msgid="3142723758949023280">"<xliff:g id="NAME">%s</xliff:g> வேலை செய்யவில்லை"</string> <string name="ext_media_unmountable_notification_message" msgid="3256290114063126205">"சரிசெய்ய, தட்டவும்"</string> diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml index 0cadb45eb0e5..8c30ebc8124b 100644 --- a/core/res/res/values-te/strings.xml +++ b/core/res/res/values-te/strings.xml @@ -430,7 +430,7 @@ <string name="permdesc_readCalendar" product="tablet" msgid="515452384059803326">"ఈ యాప్ మీ టాబ్లెట్లో నిల్వ చేసిన క్యాలెండర్ ఈవెంట్లన్నీ చదవగలదు మరియు మీ క్యాలెండర్ డేటాను షేర్ చేయగలదు లేదా సేవ్ చేయగలదు."</string> <string name="permdesc_readCalendar" product="tv" msgid="5811726712981647628">"ఈ యాప్ మీ Android TV పరికరంలో నిల్వ చేసిన క్యాలెండర్ ఈవెంట్లన్నీ చదవగలదు, మీ క్యాలెండర్ డేటాను షేర్ చేయగలదు లేదా సేవ్ చేయగలదు."</string> <string name="permdesc_readCalendar" product="default" msgid="9118823807655829957">"ఈ యాప్ మీ ఫోన్లో నిల్వ చేసిన క్యాలెండర్ ఈవెంట్లన్నీ చదవగలదు మరియు మీ క్యాలెండర్ డేటాను షేర్ చేయగలదు లేదా సేవ్ చేయగలదు."</string> - <string name="permlab_writeCalendar" msgid="6422137308329578076">"యజమానికి తెలియకుండానే క్యాలెండర్ ఈవెంట్లను జోడించి లేదా సవరించి, అతిథులకు ఇమెయిల్ పంపడం"</string> + <string name="permlab_writeCalendar" msgid="6422137308329578076">"యజమానికి తెలియకుండానే క్యాలెండర్ ఈవెంట్లను జోడించి లేదా సవరించి, అతిథులకు ఈమెయిల్ పంపడం"</string> <string name="permdesc_writeCalendar" product="tablet" msgid="8722230940717092850">"ఈ యాప్ మీ టాబ్లెట్లో క్యాలెండర్ ఈవెంట్లను జోడించగలదు, తీసివేయగలదు లేదా మార్చగలదు. ఈ యాప్ క్యాలెండర్ ఓనర్ల నుండి వచ్చినట్లుగా మెసేజ్లను పంపగలదు లేదా ఈవెంట్లను వాటి ఓనర్లకు తెలియకుండానే మార్చగలదు."</string> <string name="permdesc_writeCalendar" product="tv" msgid="951246749004952706">"ఈ యాప్ మీ Android TV పరికరంలో క్యాలెండర్ ఈవెంట్లను జోడించగలదు, తీసివేయగలదు లేదా మార్చగలదు. ఈ యాప్ క్యాలెండర్ ఓనర్ల నుండి వచ్చినట్లుగా మెసేజ్లను పంపగలదు లేదా ఈవెంట్లను వాటి ఓనర్లకు తెలియకుండానే మార్చగలదు."</string> <string name="permdesc_writeCalendar" product="default" msgid="5416380074475634233">"ఈ యాప్ మీ ఫోన్లో క్యాలెండర్ ఈవెంట్లను జోడించగలదు, తీసివేయగలదు లేదా మార్చగలదు. ఈ యాప్ క్యాలెండర్ ఓనర్ల నుండి వచ్చినట్లుగా మెసేజ్లను పంపగలదు, లేదా ఈవెంట్లను వాటి ఓనర్లకు తెలియకుండానే మార్చగలదు."</string> @@ -929,7 +929,7 @@ <string name="lockscreen_glogin_forgot_pattern" msgid="9218940117797602518">"ఖాతా అన్లాక్"</string> <string name="lockscreen_glogin_too_many_attempts" msgid="3775904917743034195">"చాలా ఎక్కువ ఆకృతి ప్రయత్నాలు చేశారు"</string> <string name="lockscreen_glogin_instructions" msgid="4695162942525531700">"అన్లాక్ చేయడానికి, మీ Google ఖాతాతో సైన్ ఇన్ చేయండి."</string> - <string name="lockscreen_glogin_username_hint" msgid="6916101478673157045">"వినియోగదారు పేరు (ఇమెయిల్)"</string> + <string name="lockscreen_glogin_username_hint" msgid="6916101478673157045">"వినియోగదారు పేరు (ఈమెయిల్)"</string> <string name="lockscreen_glogin_password_hint" msgid="3031027901286812848">"పాస్వర్డ్"</string> <string name="lockscreen_glogin_submit_button" msgid="3590556636347843733">"సైన్ ఇన్ చేయి"</string> <string name="lockscreen_glogin_invalid_input" msgid="4369219936865697679">"వినియోగదారు పేరు లేదా పాస్వర్డ్ చెల్లదు."</string> @@ -1668,7 +1668,7 @@ <string name="kg_invalid_confirm_pin_hint" product="default" msgid="4705368340409816254">"పిన్ కోడ్లు సరిపోలలేదు"</string> <string name="kg_login_too_many_attempts" msgid="699292728290654121">"చాలా ఎక్కువ ఆకృతి ప్రయత్నాలు చేశారు"</string> <string name="kg_login_instructions" msgid="3619844310339066827">"అన్లాక్ చేయడానికి, మీ Google ఖాతాతో సైన్ ఇన్ చేయండి."</string> - <string name="kg_login_username_hint" msgid="1765453775467133251">"వినియోగదారు పేరు (ఇమెయిల్)"</string> + <string name="kg_login_username_hint" msgid="1765453775467133251">"వినియోగదారు పేరు (ఈమెయిల్)"</string> <string name="kg_login_password_hint" msgid="3330530727273164402">"పాస్వర్డ్"</string> <string name="kg_login_submit_button" msgid="893611277617096870">"సైన్ ఇన్ చేయి"</string> <string name="kg_login_invalid_input" msgid="8292367491901220210">"చెల్లని వినియోగదారు పేరు లేదా పాస్వర్డ్."</string> @@ -1683,9 +1683,9 @@ <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2299099385175083308">"మీరు టాబ్లెట్ను అన్లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> చెల్లని ప్రయత్నాలు చేశారు. టాబ్లెట్ ఇప్పుడు ఫ్యాక్టరీ ఆటోమేటిక్కు రీసెట్ చేయబడుతుంది."</string> <string name="kg_failed_attempts_now_wiping" product="tv" msgid="5045460916106267585">"మీరు మీ Android TV పరికరాన్ని అన్లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> సార్లు విఫల ప్రయత్నాలు చేశారు. మీ Android TV పరికరం ఇప్పుడు ఫ్యాక్టరీ రీసెట్ చేయబడుతుంది."</string> <string name="kg_failed_attempts_now_wiping" product="default" msgid="5043730590446071189">"మీరు ఫోన్ను అన్లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> చెల్లని ప్రయత్నాలు చేశారు. ఫోన్ ఇప్పుడు ఫ్యాక్టరీ ఆటోమేటిక్కు రీసెట్ చేయబడుతుంది."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="7086799295109717623">"మీరు మీ అన్లాక్ నమూనాను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, ఇమెయిల్ ఖాతాను ఉపయోగించి మీ టాబ్లెట్ను అన్లాక్ చేయాల్సిందిగా మిమ్మల్ని అడుగుతారు.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string> - <string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4670840383567106114">"మీరు మీ అన్లాక్ నమూనాను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీశారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత మీ Android TV పరికరాన్ని ఇమెయిల్ ఖాతా ద్వారా అన్లాక్ చేయాల్సిందిగా మిమ్మల్ని కోరడం జరుగుతుంది.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"మీరు మీ అన్లాక్ నమూనాను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, ఇమెయిల్ ఖాతాను ఉపయోగించి మీ ఫోన్ను అన్లాక్ చేయాల్సిందిగా మిమ్మల్ని అడుగుతారు.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="7086799295109717623">"మీరు మీ అన్లాక్ నమూనాను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, ఈమెయిల్ ఖాతాను ఉపయోగించి మీ టాబ్లెట్ను అన్లాక్ చేయాల్సిందిగా మిమ్మల్ని అడుగుతారు.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string> + <string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4670840383567106114">"మీరు మీ అన్లాక్ నమూనాను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీశారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత మీ Android TV పరికరాన్ని ఈమెయిల్ ఖాతా ద్వారా అన్లాక్ చేయాల్సిందిగా మిమ్మల్ని కోరడం జరుగుతుంది.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"మీరు మీ అన్లాక్ నమూనాను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, ఈమెయిల్ ఖాతాను ఉపయోగించి మీ ఫోన్ను అన్లాక్ చేయాల్సిందిగా మిమ్మల్ని అడుగుతారు.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"తీసివేయి"</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"వాల్యూమ్ను సిఫార్సు చేయబడిన స్థాయి కంటే ఎక్కువగా పెంచాలా?\n\nసుదీర్ఘ వ్యవధుల పాటు అధిక వాల్యూమ్లో వినడం వలన మీ వినికిడి శక్తి దెబ్బ తినవచ్చు."</string> @@ -2051,7 +2051,7 @@ <string name="autofill_save_type_payment_card" msgid="6555012156728690856">"చెల్లింపు కార్డ్"</string> <string name="autofill_save_type_generic_card" msgid="1019367283921448608">"కార్డ్"</string> <string name="autofill_save_type_username" msgid="1018816929884640882">"వినియోగదారు పేరు"</string> - <string name="autofill_save_type_email_address" msgid="1303262336895591924">"ఇమెయిల్ అడ్రస్"</string> + <string name="autofill_save_type_email_address" msgid="1303262336895591924">"ఈమెయిల్ అడ్రస్"</string> <string name="etws_primary_default_message_earthquake" msgid="8401079517718280669">"ప్రశాంతంగా ఉండండి మరియు దగ్గర్లో తలదాచుకోండి."</string> <string name="etws_primary_default_message_tsunami" msgid="5828171463387976279">"వెంటనే తీర ప్రాంతాలు మరియు నదీ పరీవాహక ప్రాంతాలను ఖాళీ చేసి మెట్ట ప్రాంతాలకు తరలి వెళ్లండి."</string> <string name="etws_primary_default_message_earthquake_and_tsunami" msgid="4888224011071875068">"ప్రశాంతంగా ఉండండి మరియు దగ్గర్లో తలదాచుకోండి."</string> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 3718d2832f51..32db1866c151 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -2326,10 +2326,6 @@ <!-- Type of the ambient tap sensor per device posture (defined by WM Jetpack posture). Unspecified values use config_dozeTapSensor --> <string-array name="config_dozeTapSensorPostureMapping" translatable="false"> - <item></item> <!-- UNKNOWN --> - <item></item> <!-- CLOSED --> - <item></item> <!-- HALF_OPENED --> - <item></item> <!-- OPENED --> </string-array> <!-- Type of the long press sensor. Empty if long press is not supported. --> diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index ab923d0b8023..0706d8a8e4c6 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -39,15 +39,21 @@ <!-- Elevation of toast view --> <dimen name="toast_elevation">2dp</dimen> - <!-- Height of the status bar --> - <dimen name="status_bar_height">@dimen/status_bar_height_portrait</dimen> - <!-- Height of the status bar in portrait. The height should be - Max((status bar content height + waterfall top size), top cutout size) --> - <dimen name="status_bar_height_portrait">24dp</dimen> - <!-- Height of the status bar in landscape. The height should be - Max((status bar content height + waterfall top size), top cutout size) --> + <!-- Height of the status bar. + Do not read this dimen directly. Use {@link SystemBarUtils#getStatusBarHeight} instead. + --> + <dimen name="status_bar_height">24dp</dimen> + <!-- Height of the status bar in portrait. + Do not read this dimen directly. Use {@link SystemBarUtils#getStatusBarHeight} instead. + --> + <dimen name="status_bar_height_portrait">@dimen/status_bar_height</dimen> + <!-- Height of the status bar in landscape. + Do not read this dimen directly. Use {@link SystemBarUtils#getStatusBarHeight} instead. + --> <dimen name="status_bar_height_landscape">@dimen/status_bar_height_portrait</dimen> - <!-- Height of area above QQS where battery/time go --> + <!-- Height of area above QQS where battery/time go. + Do not read this dimen directly. Use {@link SystemBarUtils#getQuickQsOffsetHeight} instead. + --> <dimen name="quick_qs_offset_height">48dp</dimen> <!-- Height of the bottom navigation / system bar. --> <dimen name="navigation_bar_height">48dp</dimen> diff --git a/core/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java index d76037eb1cab..130f552f6e3a 100644 --- a/core/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java @@ -38,26 +38,28 @@ public class AmbientDisplayPowerCalculatorTest { @Rule public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule() - .setAveragePowerForOrdinal(POWER_GROUP_DISPLAY_AMBIENT, 0, 10.0); + .setAveragePowerForOrdinal(POWER_GROUP_DISPLAY_AMBIENT, 0, 10.0) + .setNumDisplays(1); @Test public void testMeasuredEnergyBasedModel() { mStatsRule.initMeasuredEnergyStatsLocked(); BatteryStatsImpl stats = mStatsRule.getBatteryStats(); - stats.updateDisplayMeasuredEnergyStatsLocked(300_000_000, Display.STATE_ON, 0); + stats.updateDisplayMeasuredEnergyStatsLocked(new long[]{300_000_000}, + new int[]{Display.STATE_ON}, 0); - stats.noteScreenStateLocked(Display.STATE_DOZE, 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS, + stats.noteScreenStateLocked(0, Display.STATE_DOZE, 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS); - stats.updateDisplayMeasuredEnergyStatsLocked(200_000_000, Display.STATE_DOZE, - 30 * MINUTE_IN_MS); + stats.updateDisplayMeasuredEnergyStatsLocked(new long[]{200_000_000}, + new int[]{Display.STATE_DOZE}, 30 * MINUTE_IN_MS); - stats.noteScreenStateLocked(Display.STATE_OFF, 120 * MINUTE_IN_MS, 120 * MINUTE_IN_MS, + stats.noteScreenStateLocked(0, Display.STATE_OFF, 120 * MINUTE_IN_MS, 120 * MINUTE_IN_MS, 120 * MINUTE_IN_MS); - stats.updateDisplayMeasuredEnergyStatsLocked(100_000_000, Display.STATE_OFF, - 120 * MINUTE_IN_MS); + stats.updateDisplayMeasuredEnergyStatsLocked(new long[]{100_000_000}, + new int[]{Display.STATE_OFF}, 120 * MINUTE_IN_MS); AmbientDisplayPowerCalculator calculator = new AmbientDisplayPowerCalculator(mStatsRule.getPowerProfile()); @@ -75,12 +77,73 @@ public class AmbientDisplayPowerCalculatorTest { } @Test + public void testMeasuredEnergyBasedModel_multiDisplay() { + mStatsRule.initMeasuredEnergyStatsLocked() + .setAveragePowerForOrdinal(POWER_GROUP_DISPLAY_AMBIENT, 1, 20.0) + .setNumDisplays(2); + BatteryStatsImpl stats = mStatsRule.getBatteryStats(); + + + final int[] screenStates = new int[] {Display.STATE_OFF, Display.STATE_OFF}; + + stats.noteScreenStateLocked(0, screenStates[0], 0, 0, 0); + stats.noteScreenStateLocked(1, screenStates[1], 0, 0, 0); + stats.updateDisplayMeasuredEnergyStatsLocked(new long[]{300, 400}, screenStates, 0); + + // Switch display0 to doze + screenStates[0] = Display.STATE_DOZE; + stats.noteScreenStateLocked(0, screenStates[0], 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS, + 30 * MINUTE_IN_MS); + stats.updateDisplayMeasuredEnergyStatsLocked(new long[]{200, 300}, + screenStates, 30 * MINUTE_IN_MS); + + // Switch display1 to doze + screenStates[1] = Display.STATE_DOZE; + stats.noteScreenStateLocked(1, Display.STATE_DOZE, 90 * MINUTE_IN_MS, 90 * MINUTE_IN_MS, + 90 * MINUTE_IN_MS); + // 100,000,000 uC should be attributed to display 0 doze here. + stats.updateDisplayMeasuredEnergyStatsLocked(new long[]{100_000_000, 700_000_000}, + screenStates, 90 * MINUTE_IN_MS); + + // Switch display0 to off + screenStates[0] = Display.STATE_OFF; + stats.noteScreenStateLocked(0, screenStates[0], 120 * MINUTE_IN_MS, 120 * MINUTE_IN_MS, + 120 * MINUTE_IN_MS); + // 40,000,000 and 70,000,000 uC should be attributed to display 0 and 1 doze here. + stats.updateDisplayMeasuredEnergyStatsLocked(new long[]{40_000_000, 70_000_000}, + screenStates, 120 * MINUTE_IN_MS); + + // Switch display1 to off + screenStates[1] = Display.STATE_OFF; + stats.noteScreenStateLocked(1, screenStates[1], 150 * MINUTE_IN_MS, 150 * MINUTE_IN_MS, + 150 * MINUTE_IN_MS); + stats.updateDisplayMeasuredEnergyStatsLocked(new long[]{100, 90_000_000}, screenStates, + 150 * MINUTE_IN_MS); + // 90,000,000 uC should be attributed to display 1 doze here. + + AmbientDisplayPowerCalculator calculator = + new AmbientDisplayPowerCalculator(mStatsRule.getPowerProfile()); + + mStatsRule.apply(calculator); + + BatteryConsumer consumer = mStatsRule.getDeviceBatteryConsumer(); + assertThat(consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_AMBIENT_DISPLAY)) + .isEqualTo(120 * MINUTE_IN_MS); + // 100,000,000 + 40,000,000 + 70,000,000 + 90,000,000 uC / 1000 (micro-/milli-) / 3600 + // (seconds/hour) = 27.777778 mAh + assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_AMBIENT_DISPLAY)) + .isWithin(PRECISION).of(83.33333); + assertThat(consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_AMBIENT_DISPLAY)) + .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY); + } + + @Test public void testPowerProfileBasedModel() { BatteryStatsImpl stats = mStatsRule.getBatteryStats(); - stats.noteScreenStateLocked(Display.STATE_DOZE, 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS, + stats.noteScreenStateLocked(0, Display.STATE_DOZE, 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS); - stats.noteScreenStateLocked(Display.STATE_OFF, 120 * MINUTE_IN_MS, 120 * MINUTE_IN_MS, + stats.noteScreenStateLocked(0, Display.STATE_OFF, 120 * MINUTE_IN_MS, 120 * MINUTE_IN_MS, 120 * MINUTE_IN_MS); AmbientDisplayPowerCalculator calculator = @@ -96,4 +159,36 @@ public class AmbientDisplayPowerCalculatorTest { assertThat(consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_AMBIENT_DISPLAY)) .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE); } + + @Test + public void testPowerProfileBasedModel_multiDisplay() { + mStatsRule.setAveragePowerForOrdinal(POWER_GROUP_DISPLAY_AMBIENT, 1, 20.0) + .setNumDisplays(2); + + BatteryStatsImpl stats = mStatsRule.getBatteryStats(); + + stats.noteScreenStateLocked(1, Display.STATE_OFF, 0, 0, 0); + stats.noteScreenStateLocked(0, Display.STATE_DOZE, 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS, + 30 * MINUTE_IN_MS); + stats.noteScreenStateLocked(1, Display.STATE_DOZE, 90 * MINUTE_IN_MS, 90 * MINUTE_IN_MS, + 90 * MINUTE_IN_MS); + stats.noteScreenStateLocked(0, Display.STATE_OFF, 120 * MINUTE_IN_MS, 120 * MINUTE_IN_MS, + 120 * MINUTE_IN_MS); + stats.noteScreenStateLocked(1, Display.STATE_OFF, 150 * MINUTE_IN_MS, 150 * MINUTE_IN_MS, + 150 * MINUTE_IN_MS); + + AmbientDisplayPowerCalculator calculator = + new AmbientDisplayPowerCalculator(mStatsRule.getPowerProfile()); + + mStatsRule.apply(BatteryUsageStatsRule.POWER_PROFILE_MODEL_ONLY, calculator); + + BatteryConsumer consumer = mStatsRule.getDeviceBatteryConsumer(); + // Duration should only be the union of + assertThat(consumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_AMBIENT_DISPLAY)) + .isEqualTo(120 * MINUTE_IN_MS); + assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_AMBIENT_DISPLAY)) + .isWithin(PRECISION).of(35.0); + assertThat(consumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_AMBIENT_DISPLAY)) + .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE); + } } diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java index d4799a8f5fd3..3e2885a74287 100644 --- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java +++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java @@ -16,9 +16,13 @@ package com.android.internal.os; +import static android.os.BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS; import static android.os.BatteryStats.STATS_SINCE_CHARGED; import static android.os.BatteryStats.WAKE_TYPE_PARTIAL; +import static com.android.internal.os.BatteryStatsImpl.ExternalStatsSync.UPDATE_CPU; +import static com.android.internal.os.BatteryStatsImpl.ExternalStatsSync.UPDATE_DISPLAY; + import android.app.ActivityManager; import android.os.BatteryStats; import android.os.BatteryStats.HistoryItem; @@ -37,8 +41,10 @@ import com.android.internal.power.MeasuredEnergyStats; import junit.framework.TestCase; +import java.util.Arrays; import java.util.HashMap; import java.util.Map; +import java.util.function.IntConsumer; /** * Test various BatteryStatsImpl noteStart methods. @@ -317,18 +323,130 @@ public class BatteryStatsNoteTest extends TestCase { public void testNoteScreenStateLocked() throws Exception { final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks); + bi.initMeasuredEnergyStats(new String[]{"FOO", "BAR"}); bi.updateTimeBasesLocked(true, Display.STATE_ON, 0, 0); - bi.noteScreenStateLocked(Display.STATE_ON); - bi.noteScreenStateLocked(Display.STATE_DOZE); + bi.noteScreenStateLocked(0, Display.STATE_ON); + + bi.noteScreenStateLocked(0, Display.STATE_DOZE); + assertTrue(bi.getOnBatteryScreenOffTimeBase().isRunning()); + assertEquals(Display.STATE_DOZE, bi.getScreenState()); + assertEquals(UPDATE_CPU | UPDATE_DISPLAY, bi.getAndClearExternalStatsSyncFlags()); + + bi.noteScreenStateLocked(0, Display.STATE_ON); + assertFalse(bi.getOnBatteryScreenOffTimeBase().isRunning()); + assertEquals(Display.STATE_ON, bi.getScreenState()); + assertEquals(UPDATE_CPU | UPDATE_DISPLAY, bi.getAndClearExternalStatsSyncFlags()); + + bi.noteScreenStateLocked(0, Display.STATE_OFF); + assertTrue(bi.getOnBatteryScreenOffTimeBase().isRunning()); + assertEquals(Display.STATE_OFF, bi.getScreenState()); + assertEquals(UPDATE_CPU | UPDATE_DISPLAY, bi.getAndClearExternalStatsSyncFlags()); + + bi.noteScreenStateLocked(0, Display.STATE_DOZE_SUSPEND); + assertTrue(bi.getOnBatteryScreenOffTimeBase().isRunning()); + assertEquals(Display.STATE_DOZE_SUSPEND, bi.getScreenState()); + assertEquals(UPDATE_CPU | UPDATE_DISPLAY, bi.getAndClearExternalStatsSyncFlags()); + + // STATE_VR note should map to STATE_ON. + bi.noteScreenStateLocked(0, Display.STATE_VR); + assertFalse(bi.getOnBatteryScreenOffTimeBase().isRunning()); + assertEquals(Display.STATE_ON, bi.getScreenState()); + assertEquals(UPDATE_CPU | UPDATE_DISPLAY, bi.getAndClearExternalStatsSyncFlags()); + + // STATE_ON_SUSPEND note should map to STATE_ON. + bi.noteScreenStateLocked(0, Display.STATE_ON_SUSPEND); + assertFalse(bi.getOnBatteryScreenOffTimeBase().isRunning()); + assertEquals(Display.STATE_ON, bi.getScreenState()); + // Transition from ON to ON state should not cause an External Sync + assertEquals(0, bi.getAndClearExternalStatsSyncFlags()); + } + + /** + * Test BatteryStatsImpl.noteScreenStateLocked sets timebases and screen states correctly for + * multi display devices + */ + @SmallTest + public void testNoteScreenStateLocked_multiDisplay() throws Exception { + final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms + MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks); + bi.setDisplayCountLocked(2); + bi.initMeasuredEnergyStats(new String[]{"FOO", "BAR"}); + + bi.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0); + bi.noteScreenStateLocked(0, Display.STATE_OFF); + bi.noteScreenStateLocked(1, Display.STATE_OFF); + + bi.noteScreenStateLocked(0, Display.STATE_DOZE); + assertTrue(bi.getOnBatteryScreenOffTimeBase().isRunning()); + assertEquals(Display.STATE_DOZE, bi.getScreenState()); + assertEquals(UPDATE_CPU | UPDATE_DISPLAY, bi.getAndClearExternalStatsSyncFlags()); + + bi.noteScreenStateLocked(0, Display.STATE_ON); + assertEquals(Display.STATE_ON, bi.getScreenState()); + assertFalse(bi.getOnBatteryScreenOffTimeBase().isRunning()); + assertEquals(UPDATE_CPU | UPDATE_DISPLAY, bi.getAndClearExternalStatsSyncFlags()); + + bi.noteScreenStateLocked(0, Display.STATE_OFF); + assertTrue(bi.getOnBatteryScreenOffTimeBase().isRunning()); + assertEquals(Display.STATE_OFF, bi.getScreenState()); + assertEquals(UPDATE_CPU | UPDATE_DISPLAY, bi.getAndClearExternalStatsSyncFlags()); + + bi.noteScreenStateLocked(0, Display.STATE_DOZE_SUSPEND); + assertTrue(bi.getOnBatteryScreenOffTimeBase().isRunning()); + assertEquals(Display.STATE_DOZE_SUSPEND, bi.getScreenState()); + assertEquals(UPDATE_CPU | UPDATE_DISPLAY, bi.getAndClearExternalStatsSyncFlags()); + + // STATE_VR note should map to STATE_ON. + bi.noteScreenStateLocked(0, Display.STATE_VR); + assertFalse(bi.getOnBatteryScreenOffTimeBase().isRunning()); + assertEquals(Display.STATE_ON, bi.getScreenState()); + assertEquals(UPDATE_CPU | UPDATE_DISPLAY, bi.getAndClearExternalStatsSyncFlags()); + + // STATE_ON_SUSPEND note should map to STATE_ON. + bi.noteScreenStateLocked(0, Display.STATE_ON_SUSPEND); + assertFalse(bi.getOnBatteryScreenOffTimeBase().isRunning()); + assertEquals(Display.STATE_ON, bi.getScreenState()); + // Transition from ON to ON state should not cause an External Sync + assertEquals(0, bi.getAndClearExternalStatsSyncFlags()); + + bi.noteScreenStateLocked(1, Display.STATE_DOZE); + assertFalse(bi.getOnBatteryScreenOffTimeBase().isRunning()); + // Should remain STATE_ON since display0 is still on. + assertEquals(Display.STATE_ON, bi.getScreenState()); + // Overall screen state did not change, so no need to sync CPU stats. + assertEquals(UPDATE_DISPLAY, bi.getAndClearExternalStatsSyncFlags()); + + bi.noteScreenStateLocked(0, Display.STATE_DOZE); assertTrue(bi.getOnBatteryScreenOffTimeBase().isRunning()); - assertEquals(bi.getScreenState(), Display.STATE_DOZE); - bi.noteScreenStateLocked(Display.STATE_ON); + assertEquals(Display.STATE_DOZE, bi.getScreenState()); + assertEquals(UPDATE_CPU | UPDATE_DISPLAY, bi.getAndClearExternalStatsSyncFlags()); + + bi.noteScreenStateLocked(0, Display.STATE_ON); assertFalse(bi.getOnBatteryScreenOffTimeBase().isRunning()); - assertEquals(bi.getScreenState(), Display.STATE_ON); - bi.noteScreenStateLocked(Display.STATE_OFF); + assertEquals(Display.STATE_ON, bi.getScreenState()); + assertEquals(UPDATE_CPU | UPDATE_DISPLAY, bi.getAndClearExternalStatsSyncFlags()); + + bi.noteScreenStateLocked(0, Display.STATE_OFF); + assertTrue(bi.getOnBatteryScreenOffTimeBase().isRunning()); + assertEquals(Display.STATE_DOZE, bi.getScreenState()); + assertEquals(UPDATE_CPU | UPDATE_DISPLAY, bi.getAndClearExternalStatsSyncFlags()); + + bi.noteScreenStateLocked(0, Display.STATE_DOZE_SUSPEND); assertTrue(bi.getOnBatteryScreenOffTimeBase().isRunning()); - assertEquals(bi.getScreenState(), Display.STATE_OFF); + assertEquals(Display.STATE_DOZE, bi.getScreenState()); + // Overall screen state did not change, so no need to sync CPU stats. + assertEquals(UPDATE_DISPLAY, bi.getAndClearExternalStatsSyncFlags()); + + bi.noteScreenStateLocked(0, Display.STATE_VR); + assertFalse(bi.getOnBatteryScreenOffTimeBase().isRunning()); + assertEquals(Display.STATE_ON, bi.getScreenState()); + assertEquals(UPDATE_CPU | UPDATE_DISPLAY, bi.getAndClearExternalStatsSyncFlags()); + + bi.noteScreenStateLocked(0, Display.STATE_ON_SUSPEND); + assertFalse(bi.getOnBatteryScreenOffTimeBase().isRunning()); + assertEquals(Display.STATE_ON, bi.getScreenState()); + assertEquals(0, bi.getAndClearExternalStatsSyncFlags()); } /* @@ -352,32 +470,317 @@ public class BatteryStatsNoteTest extends TestCase { bi.updateTimeBasesLocked(true, Display.STATE_UNKNOWN, 100_000, 100_000); // Turn on display at 200us clocks.realtime = clocks.uptime = 200; - bi.noteScreenStateLocked(Display.STATE_ON); + bi.noteScreenStateLocked(0, Display.STATE_ON); assertEquals(150_000, bi.computeBatteryRealtime(250_000, STATS_SINCE_CHARGED)); assertEquals(100_000, bi.computeBatteryScreenOffRealtime(250_000, STATS_SINCE_CHARGED)); assertEquals(50_000, bi.getScreenOnTime(250_000, STATS_SINCE_CHARGED)); assertEquals(0, bi.getScreenDozeTime(250_000, STATS_SINCE_CHARGED)); + assertEquals(50_000, bi.getDisplayScreenOnTime(0, 250_000)); + assertEquals(0, bi.getDisplayScreenDozeTime(0, 250_000)); clocks.realtime = clocks.uptime = 310; - bi.noteScreenStateLocked(Display.STATE_OFF); + bi.noteScreenStateLocked(0, Display.STATE_OFF); assertEquals(250_000, bi.computeBatteryRealtime(350_000, STATS_SINCE_CHARGED)); assertEquals(140_000, bi.computeBatteryScreenOffRealtime(350_000, STATS_SINCE_CHARGED)); assertEquals(110_000, bi.getScreenOnTime(350_000, STATS_SINCE_CHARGED)); assertEquals(0, bi.getScreenDozeTime(350_000, STATS_SINCE_CHARGED)); + assertEquals(110_000, bi.getDisplayScreenOnTime(0, 350_000)); + assertEquals(0, bi.getDisplayScreenDozeTime(0, 350_000)); clocks.realtime = clocks.uptime = 400; - bi.noteScreenStateLocked(Display.STATE_DOZE); + bi.noteScreenStateLocked(0, Display.STATE_DOZE); assertEquals(400_000, bi.computeBatteryRealtime(500_000, STATS_SINCE_CHARGED)); assertEquals(290_000, bi.computeBatteryScreenOffRealtime(500_000, STATS_SINCE_CHARGED)); assertEquals(110_000, bi.getScreenOnTime(500_000, STATS_SINCE_CHARGED)); assertEquals(100_000, bi.getScreenDozeTime(500_000, STATS_SINCE_CHARGED)); + assertEquals(110_000, bi.getDisplayScreenOnTime(0, 500_000)); + assertEquals(100_000, bi.getDisplayScreenDozeTime(0, 500_000)); clocks.realtime = clocks.uptime = 1000; - bi.noteScreenStateLocked(Display.STATE_OFF); + bi.noteScreenStateLocked(0, Display.STATE_OFF); assertEquals(1400_000, bi.computeBatteryRealtime(1500_000, STATS_SINCE_CHARGED)); assertEquals(1290_000, bi.computeBatteryScreenOffRealtime(1500_000, STATS_SINCE_CHARGED)); assertEquals(110_000, bi.getScreenOnTime(1500_000, STATS_SINCE_CHARGED)); assertEquals(600_000, bi.getScreenDozeTime(1500_000, STATS_SINCE_CHARGED)); + assertEquals(110_000, bi.getDisplayScreenOnTime(0, 1500_000)); + assertEquals(600_000, bi.getDisplayScreenDozeTime(0, 1500_000)); + } + + /* + * Test BatteryStatsImpl.noteScreenStateLocked updates timers correctly for multi display + * devices. + */ + @SmallTest + public void testNoteScreenStateTimersLocked_multiDisplay() throws Exception { + final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms + MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks); + bi.setDisplayCountLocked(2); + + clocks.realtime = clocks.uptime = 100; + // Device startup, setOnBatteryLocked calls updateTimebases + bi.updateTimeBasesLocked(true, Display.STATE_UNKNOWN, 100_000, 100_000); + // Turn on display at 200us + clocks.realtime = clocks.uptime = 200; + bi.noteScreenStateLocked(0, Display.STATE_ON); + bi.noteScreenStateLocked(1, Display.STATE_OFF); + assertEquals(150_000, bi.computeBatteryRealtime(250_000, STATS_SINCE_CHARGED)); + assertEquals(100_000, bi.computeBatteryScreenOffRealtime(250_000, STATS_SINCE_CHARGED)); + assertEquals(50_000, bi.getScreenOnTime(250_000, STATS_SINCE_CHARGED)); + assertEquals(0, bi.getScreenDozeTime(250_000, STATS_SINCE_CHARGED)); + assertEquals(50_000, bi.getDisplayScreenOnTime(0, 250_000)); + assertEquals(0, bi.getDisplayScreenDozeTime(0, 250_000)); + assertEquals(0, bi.getDisplayScreenOnTime(1, 250_000)); + assertEquals(0, bi.getDisplayScreenDozeTime(1, 250_000)); + + clocks.realtime = clocks.uptime = 310; + bi.noteScreenStateLocked(0, Display.STATE_OFF); + assertEquals(250_000, bi.computeBatteryRealtime(350_000, STATS_SINCE_CHARGED)); + assertEquals(140_000, bi.computeBatteryScreenOffRealtime(350_000, STATS_SINCE_CHARGED)); + assertEquals(110_000, bi.getScreenOnTime(350_000, STATS_SINCE_CHARGED)); + assertEquals(0, bi.getScreenDozeTime(350_000, STATS_SINCE_CHARGED)); + assertEquals(110_000, bi.getDisplayScreenOnTime(0, 350_000)); + assertEquals(0, bi.getDisplayScreenDozeTime(0, 350_000)); + assertEquals(0, bi.getDisplayScreenOnTime(1, 350_000)); + assertEquals(0, bi.getDisplayScreenDozeTime(1, 350_000)); + + clocks.realtime = clocks.uptime = 400; + bi.noteScreenStateLocked(0, Display.STATE_DOZE); + assertEquals(400_000, bi.computeBatteryRealtime(500_000, STATS_SINCE_CHARGED)); + assertEquals(290_000, bi.computeBatteryScreenOffRealtime(500_000, STATS_SINCE_CHARGED)); + assertEquals(110_000, bi.getScreenOnTime(500_000, STATS_SINCE_CHARGED)); + assertEquals(100_000, bi.getScreenDozeTime(500_000, STATS_SINCE_CHARGED)); + assertEquals(110_000, bi.getDisplayScreenOnTime(0, 500_000)); + assertEquals(100_000, bi.getDisplayScreenDozeTime(0, 500_000)); + assertEquals(0, bi.getDisplayScreenOnTime(1, 500_000)); + assertEquals(0, bi.getDisplayScreenDozeTime(1, 500_000)); + + clocks.realtime = clocks.uptime = 1000; + bi.noteScreenStateLocked(0, Display.STATE_OFF); + assertEquals(1000_000, bi.computeBatteryRealtime(1100_000, STATS_SINCE_CHARGED)); + assertEquals(890_000, bi.computeBatteryScreenOffRealtime(1100_000, STATS_SINCE_CHARGED)); + assertEquals(110_000, bi.getScreenOnTime(1100_000, STATS_SINCE_CHARGED)); + assertEquals(600_000, bi.getScreenDozeTime(1100_000, STATS_SINCE_CHARGED)); + assertEquals(110_000, bi.getDisplayScreenOnTime(0, 1100_000)); + assertEquals(600_000, bi.getDisplayScreenDozeTime(0, 1100_000)); + assertEquals(0, bi.getDisplayScreenOnTime(1, 1100_000)); + assertEquals(0, bi.getDisplayScreenDozeTime(1, 1100_000)); + + clocks.realtime = clocks.uptime = 1200; + // Change state of second display to doze + bi.noteScreenStateLocked(1, Display.STATE_DOZE); + assertEquals(1150_000, bi.computeBatteryRealtime(1250_000, STATS_SINCE_CHARGED)); + assertEquals(1040_000, bi.computeBatteryScreenOffRealtime(1250_000, STATS_SINCE_CHARGED)); + assertEquals(110_000, bi.getScreenOnTime(1250_000, STATS_SINCE_CHARGED)); + assertEquals(650_000, bi.getScreenDozeTime(1250_000, STATS_SINCE_CHARGED)); + assertEquals(110_000, bi.getDisplayScreenOnTime(0, 1250_000)); + assertEquals(600_000, bi.getDisplayScreenDozeTime(0, 1250_000)); + assertEquals(0, bi.getDisplayScreenOnTime(1, 1250_000)); + assertEquals(50_000, bi.getDisplayScreenDozeTime(1, 1250_000)); + + clocks.realtime = clocks.uptime = 1310; + bi.noteScreenStateLocked(0, Display.STATE_ON); + assertEquals(1250_000, bi.computeBatteryRealtime(1350_000, STATS_SINCE_CHARGED)); + assertEquals(1100_000, bi.computeBatteryScreenOffRealtime(1350_000, STATS_SINCE_CHARGED)); + assertEquals(150_000, bi.getScreenOnTime(1350_000, STATS_SINCE_CHARGED)); + assertEquals(710_000, bi.getScreenDozeTime(1350_000, STATS_SINCE_CHARGED)); + assertEquals(150_000, bi.getDisplayScreenOnTime(0, 1350_000)); + assertEquals(600_000, bi.getDisplayScreenDozeTime(0, 1350_000)); + assertEquals(0, bi.getDisplayScreenOnTime(1, 1350_000)); + assertEquals(150_000, bi.getDisplayScreenDozeTime(1, 1350_000)); + + clocks.realtime = clocks.uptime = 1400; + bi.noteScreenStateLocked(0, Display.STATE_DOZE); + assertEquals(1400_000, bi.computeBatteryRealtime(1500_000, STATS_SINCE_CHARGED)); + assertEquals(1200_000, bi.computeBatteryScreenOffRealtime(1500_000, STATS_SINCE_CHARGED)); + assertEquals(200_000, bi.getScreenOnTime(1500_000, STATS_SINCE_CHARGED)); + assertEquals(810_000, bi.getScreenDozeTime(1500_000, STATS_SINCE_CHARGED)); + assertEquals(200_000, bi.getDisplayScreenOnTime(0, 1500_000)); + assertEquals(700_000, bi.getDisplayScreenDozeTime(0, 1500_000)); + assertEquals(0, bi.getDisplayScreenOnTime(1, 1500_000)); + assertEquals(300_000, bi.getDisplayScreenDozeTime(1, 1500_000)); + + clocks.realtime = clocks.uptime = 2000; + bi.noteScreenStateLocked(0, Display.STATE_OFF); + assertEquals(2000_000, bi.computeBatteryRealtime(2100_000, STATS_SINCE_CHARGED)); + assertEquals(1800_000, bi.computeBatteryScreenOffRealtime(2100_000, STATS_SINCE_CHARGED)); + assertEquals(200_000, bi.getScreenOnTime(2100_000, STATS_SINCE_CHARGED)); + assertEquals(1410_000, bi.getScreenDozeTime(2100_000, STATS_SINCE_CHARGED)); + assertEquals(200_000, bi.getDisplayScreenOnTime(0, 2100_000)); + assertEquals(1200_000, bi.getDisplayScreenDozeTime(0, 2100_000)); + assertEquals(0, bi.getDisplayScreenOnTime(1, 2100_000)); + assertEquals(900_000, bi.getDisplayScreenDozeTime(1, 2100_000)); + + + clocks.realtime = clocks.uptime = 2200; + // Change state of second display to on + bi.noteScreenStateLocked(1, Display.STATE_ON); + assertEquals(2150_000, bi.computeBatteryRealtime(2250_000, STATS_SINCE_CHARGED)); + assertEquals(1900_000, bi.computeBatteryScreenOffRealtime(2250_000, STATS_SINCE_CHARGED)); + assertEquals(250_000, bi.getScreenOnTime(2250_000, STATS_SINCE_CHARGED)); + assertEquals(1510_000, bi.getScreenDozeTime(2250_000, STATS_SINCE_CHARGED)); + assertEquals(200_000, bi.getDisplayScreenOnTime(0, 2250_000)); + assertEquals(1200_000, bi.getDisplayScreenDozeTime(0, 2250_000)); + assertEquals(50_000, bi.getDisplayScreenOnTime(1, 2250_000)); + assertEquals(1000_000, bi.getDisplayScreenDozeTime(1, 2250_000)); + + clocks.realtime = clocks.uptime = 2310; + bi.noteScreenStateLocked(0, Display.STATE_ON); + assertEquals(2250_000, bi.computeBatteryRealtime(2350_000, STATS_SINCE_CHARGED)); + assertEquals(1900_000, bi.computeBatteryScreenOffRealtime(2350_000, STATS_SINCE_CHARGED)); + assertEquals(350_000, bi.getScreenOnTime(2350_000, STATS_SINCE_CHARGED)); + assertEquals(1510_000, bi.getScreenDozeTime(2350_000, STATS_SINCE_CHARGED)); + assertEquals(240_000, bi.getDisplayScreenOnTime(0, 2350_000)); + assertEquals(1200_000, bi.getDisplayScreenDozeTime(0, 2350_000)); + assertEquals(150_000, bi.getDisplayScreenOnTime(1, 2350_000)); + assertEquals(1000_000, bi.getDisplayScreenDozeTime(1, 2350_000)); + + clocks.realtime = clocks.uptime = 2400; + bi.noteScreenStateLocked(0, Display.STATE_DOZE); + assertEquals(2400_000, bi.computeBatteryRealtime(2500_000, STATS_SINCE_CHARGED)); + assertEquals(1900_000, bi.computeBatteryScreenOffRealtime(2500_000, STATS_SINCE_CHARGED)); + assertEquals(500_000, bi.getScreenOnTime(2500_000, STATS_SINCE_CHARGED)); + assertEquals(1510_000, bi.getScreenDozeTime(2500_000, STATS_SINCE_CHARGED)); + assertEquals(290_000, bi.getDisplayScreenOnTime(0, 2500_000)); + assertEquals(1300_000, bi.getDisplayScreenDozeTime(0, 2500_000)); + assertEquals(300_000, bi.getDisplayScreenOnTime(1, 2500_000)); + assertEquals(1000_000, bi.getDisplayScreenDozeTime(1, 2500_000)); + + clocks.realtime = clocks.uptime = 3000; + bi.noteScreenStateLocked(0, Display.STATE_OFF); + assertEquals(3000_000, bi.computeBatteryRealtime(3100_000, STATS_SINCE_CHARGED)); + assertEquals(1900_000, bi.computeBatteryScreenOffRealtime(3100_000, STATS_SINCE_CHARGED)); + assertEquals(1100_000, bi.getScreenOnTime(3100_000, STATS_SINCE_CHARGED)); + assertEquals(1510_000, bi.getScreenDozeTime(3100_000, STATS_SINCE_CHARGED)); + assertEquals(290_000, bi.getDisplayScreenOnTime(0, 3100_000)); + assertEquals(1800_000, bi.getDisplayScreenDozeTime(0, 3100_000)); + assertEquals(900_000, bi.getDisplayScreenOnTime(1, 3100_000)); + assertEquals(1000_000, bi.getDisplayScreenDozeTime(1, 3100_000)); + } + + + /** + * Test BatteryStatsImpl.noteScreenBrightnessLocked updates timers correctly. + */ + @SmallTest + public void testScreenBrightnessLocked_multiDisplay() throws Exception { + final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms + MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks); + + final int numDisplay = 2; + bi.setDisplayCountLocked(numDisplay); + + + final long[] overallExpected = new long[NUM_SCREEN_BRIGHTNESS_BINS]; + final long[][] perDisplayExpected = new long[numDisplay][NUM_SCREEN_BRIGHTNESS_BINS]; + class Bookkeeper { + public long currentTimeMs = 100; + public int overallActiveBin = -1; + public int[] perDisplayActiveBin = new int[numDisplay]; + } + final Bookkeeper bk = new Bookkeeper(); + Arrays.fill(bk.perDisplayActiveBin, -1); + + IntConsumer incrementTime = inc -> { + bk.currentTimeMs += inc; + if (bk.overallActiveBin >= 0) { + overallExpected[bk.overallActiveBin] += inc; + } + for (int i = 0; i < numDisplay; i++) { + final int bin = bk.perDisplayActiveBin[i]; + if (bin >= 0) { + perDisplayExpected[i][bin] += inc; + } + } + clocks.realtime = clocks.uptime = bk.currentTimeMs; + }; + + bi.updateTimeBasesLocked(true, Display.STATE_ON, 0, 0); + bi.noteScreenStateLocked(0, Display.STATE_ON); + bi.noteScreenStateLocked(1, Display.STATE_ON); + + incrementTime.accept(100); + bi.noteScreenBrightnessLocked(0, 25); + bi.noteScreenBrightnessLocked(1, 25); + // floor(25/256*5) = bin 0 + bk.overallActiveBin = 0; + bk.perDisplayActiveBin[0] = 0; + bk.perDisplayActiveBin[1] = 0; + + incrementTime.accept(50); + checkScreenBrightnesses(overallExpected, perDisplayExpected, bi, bk.currentTimeMs); + + incrementTime.accept(13); + bi.noteScreenBrightnessLocked(0, 100); + // floor(25/256*5) = bin 1 + bk.overallActiveBin = 1; + bk.perDisplayActiveBin[0] = 1; + + incrementTime.accept(44); + checkScreenBrightnesses(overallExpected, perDisplayExpected, bi, bk.currentTimeMs); + + incrementTime.accept(22); + bi.noteScreenBrightnessLocked(1, 200); + // floor(200/256*5) = bin 3 + bk.overallActiveBin = 3; + bk.perDisplayActiveBin[1] = 3; + + incrementTime.accept(33); + checkScreenBrightnesses(overallExpected, perDisplayExpected, bi, bk.currentTimeMs); + + incrementTime.accept(77); + bi.noteScreenBrightnessLocked(0, 150); + // floor(150/256*5) = bin 2 + // Overall active bin should not change + bk.perDisplayActiveBin[0] = 2; + + incrementTime.accept(88); + checkScreenBrightnesses(overallExpected, perDisplayExpected, bi, bk.currentTimeMs); + + incrementTime.accept(11); + bi.noteScreenStateLocked(1, Display.STATE_OFF); + // Display 1 should timers should stop incrementing + // Overall active bin should fallback to display 0's bin + bk.overallActiveBin = 2; + bk.perDisplayActiveBin[1] = -1; + + incrementTime.accept(99); + checkScreenBrightnesses(overallExpected, perDisplayExpected, bi, bk.currentTimeMs); + + incrementTime.accept(200); + bi.noteScreenBrightnessLocked(0, 255); + // floor(150/256*5) = bin 4 + bk.overallActiveBin = 4; + bk.perDisplayActiveBin[0] = 4; + + incrementTime.accept(300); + checkScreenBrightnesses(overallExpected, perDisplayExpected, bi, bk.currentTimeMs); + + incrementTime.accept(200); + bi.noteScreenStateLocked(0, Display.STATE_DOZE); + // No displays are on. No brightness timers should be active. + bk.overallActiveBin = -1; + bk.perDisplayActiveBin[0] = -1; + + incrementTime.accept(300); + checkScreenBrightnesses(overallExpected, perDisplayExpected, bi, bk.currentTimeMs); + + incrementTime.accept(400); + bi.noteScreenStateLocked(1, Display.STATE_ON); + // Display 1 turned back on. + bk.overallActiveBin = 3; + bk.perDisplayActiveBin[1] = 3; + + incrementTime.accept(500); + checkScreenBrightnesses(overallExpected, perDisplayExpected, bi, bk.currentTimeMs); + + incrementTime.accept(600); + bi.noteScreenStateLocked(0, Display.STATE_ON); + // Display 0 turned back on. + bk.overallActiveBin = 4; + bk.perDisplayActiveBin[0] = 4; + + incrementTime.accept(700); + checkScreenBrightnesses(overallExpected, perDisplayExpected, bi, bk.currentTimeMs); } @SmallTest @@ -595,7 +998,7 @@ public class BatteryStatsNoteTest extends TestCase { bi.initMeasuredEnergyStats(new String[]{"FOO", "BAR"}); clocks.realtime = 0; - int screen = Display.STATE_OFF; + int[] screen = new int[]{Display.STATE_OFF}; boolean battery = false; final int uid1 = 10500; @@ -605,35 +1008,35 @@ public class BatteryStatsNoteTest extends TestCase { long globalDoze = 0; // Case A: uid1 off, uid2 off, battery off, screen off - bi.updateTimeBasesLocked(battery, screen, clocks.realtime*1000, 0); + bi.updateTimeBasesLocked(battery, screen[0], clocks.realtime * 1000, 0); bi.setOnBatteryInternal(battery); - bi.updateDisplayMeasuredEnergyStatsLocked(500_000, screen, clocks.realtime); + bi.updateDisplayMeasuredEnergyStatsLocked(new long[]{500_000}, screen, clocks.realtime); checkMeasuredCharge("A", uid1, blame1, uid2, blame2, globalDoze, bi); // Case B: uid1 off, uid2 off, battery ON, screen off clocks.realtime += 17; battery = true; - bi.updateTimeBasesLocked(battery, screen, clocks.realtime*1000, 0); + bi.updateTimeBasesLocked(battery, screen[0], clocks.realtime * 1000, 0); bi.setOnBatteryInternal(battery); clocks.realtime += 19; - bi.updateDisplayMeasuredEnergyStatsLocked(510_000, screen, clocks.realtime); + bi.updateDisplayMeasuredEnergyStatsLocked(new long[]{510_000}, screen, clocks.realtime); checkMeasuredCharge("B", uid1, blame1, uid2, blame2, globalDoze, bi); // Case C: uid1 ON, uid2 off, battery on, screen off clocks.realtime += 18; setFgState(uid1, true, bi); clocks.realtime += 18; - bi.updateDisplayMeasuredEnergyStatsLocked(520_000, screen, clocks.realtime); + bi.updateDisplayMeasuredEnergyStatsLocked(new long[]{520_000}, screen, clocks.realtime); checkMeasuredCharge("C", uid1, blame1, uid2, blame2, globalDoze, bi); // Case D: uid1 on, uid2 off, battery on, screen ON clocks.realtime += 17; - screen = Display.STATE_ON; - bi.updateDisplayMeasuredEnergyStatsLocked(521_000, screen, clocks.realtime); + screen[0] = Display.STATE_ON; + bi.updateDisplayMeasuredEnergyStatsLocked(new long[]{521_000}, screen, clocks.realtime); blame1 += 0; // Screen had been off during the measurement period checkMeasuredCharge("D.1", uid1, blame1, uid2, blame2, globalDoze, bi); clocks.realtime += 101; - bi.updateDisplayMeasuredEnergyStatsLocked(530_000, screen, clocks.realtime); + bi.updateDisplayMeasuredEnergyStatsLocked(new long[]{530_000}, screen, clocks.realtime); blame1 += 530_000; checkMeasuredCharge("D.2", uid1, blame1, uid2, blame2, globalDoze, bi); @@ -641,33 +1044,33 @@ public class BatteryStatsNoteTest extends TestCase { clocks.realtime += 20; setFgState(uid2, true, bi); clocks.realtime += 40; - bi.updateDisplayMeasuredEnergyStatsLocked(540_000, screen, clocks.realtime); + bi.updateDisplayMeasuredEnergyStatsLocked(new long[]{540_000}, screen, clocks.realtime); // In the past 60ms, sum of fg is 20+40+40=100ms. uid1 is blamed for 60/100; uid2 for 40/100 blame1 += 540_000 * (20 + 40) / (20 + 40 + 40); - blame2 += 540_000 * ( 0 + 40) / (20 + 40 + 40); + blame2 += 540_000 * (0 + 40) / (20 + 40 + 40); checkMeasuredCharge("E", uid1, blame1, uid2, blame2, globalDoze, bi); // Case F: uid1 on, uid2 OFF, battery on, screen on clocks.realtime += 40; setFgState(uid2, false, bi); clocks.realtime += 120; - bi.updateDisplayMeasuredEnergyStatsLocked(550_000, screen, clocks.realtime); + bi.updateDisplayMeasuredEnergyStatsLocked(new long[]{550_000}, screen, clocks.realtime); // In the past 160ms, sum f fg is 200ms. uid1 is blamed for 40+120 of it; uid2 for 40 of it. blame1 += 550_000 * (40 + 120) / (40 + 40 + 120); - blame2 += 550_000 * (40 + 0 ) / (40 + 40 + 120); + blame2 += 550_000 * (40 + 0) / (40 + 40 + 120); checkMeasuredCharge("F", uid1, blame1, uid2, blame2, globalDoze, bi); // Case G: uid1 on, uid2 off, battery on, screen DOZE clocks.realtime += 5; - screen = Display.STATE_DOZE; - bi.updateDisplayMeasuredEnergyStatsLocked(570_000, screen, clocks.realtime); + screen[0] = Display.STATE_DOZE; + bi.updateDisplayMeasuredEnergyStatsLocked(new long[]{570_000}, screen, clocks.realtime); blame1 += 570_000; // All of this pre-doze time is blamed on uid1. checkMeasuredCharge("G", uid1, blame1, uid2, blame2, globalDoze, bi); // Case H: uid1 on, uid2 off, battery on, screen ON clocks.realtime += 6; - screen = Display.STATE_ON; - bi.updateDisplayMeasuredEnergyStatsLocked(580_000, screen, clocks.realtime); + screen[0] = Display.STATE_ON; + bi.updateDisplayMeasuredEnergyStatsLocked(new long[]{580_000}, screen, clocks.realtime); blame1 += 0; // The screen had been doze during the energy period globalDoze += 580_000; checkMeasuredCharge("H", uid1, blame1, uid2, blame2, globalDoze, bi); @@ -822,4 +1225,19 @@ public class BatteryStatsNoteTest extends TestCase { assertEquals("Wrong uid2 blame in bucket 1 for Case " + caseName, blame2B, actualUid2[1]); } + + private void checkScreenBrightnesses(long[] overallExpected, long[][] perDisplayExpected, + BatteryStatsImpl bi, long currentTimeMs) { + final int numDisplay = bi.getDisplayCount(); + for (int bin = 0; bin < NUM_SCREEN_BRIGHTNESS_BINS; bin++) { + for (int display = 0; display < numDisplay; display++) { + assertEquals("Failure for display " + display + " screen brightness bin " + bin, + perDisplayExpected[display][bin] * 1000, + bi.getDisplayScreenBrightnessTime(display, bin, currentTimeMs * 1000)); + } + assertEquals("Failure for overall screen brightness bin " + bin, + overallExpected[bin] * 1000, + bi.getScreenBrightnessTime(bin, currentTimeMs * 1000, STATS_SINCE_CHARGED)); + } + } } diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java index ab38f017936d..ac87806b1639 100644 --- a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java +++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java @@ -118,6 +118,12 @@ public class BatteryUsageStatsRule implements TestRule { return this; } + public BatteryUsageStatsRule setNumDisplays(int value) { + when(mPowerProfile.getNumDisplays()).thenReturn(value); + mBatteryStats.setDisplayCountLocked(value); + return this; + } + /** Call only after setting the power profile information. */ public BatteryUsageStatsRule initMeasuredEnergyStatsLocked() { return initMeasuredEnergyStatsLocked(new String[0]); diff --git a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java index cee1a0352a7e..cfecf15b55ef 100644 --- a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java +++ b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java @@ -39,13 +39,14 @@ public class MockBatteryStatsImpl extends BatteryStatsImpl { public BatteryStatsImpl.Clocks clocks; public boolean mForceOnBattery; private NetworkStats mNetworkStats; + private DummyExternalStatsSync mExternalStatsSync = new DummyExternalStatsSync(); MockBatteryStatsImpl(Clocks clocks) { super(clocks); this.clocks = mClocks; initTimersAndCounters(); - setExternalStatsSyncLocked(new DummyExternalStatsSync()); + setExternalStatsSyncLocked(mExternalStatsSync); informThatAllExternalStatsAreFlushed(); // A no-op handler. @@ -182,7 +183,15 @@ public class MockBatteryStatsImpl extends BatteryStatsImpl { return mPendingUids; } + public int getAndClearExternalStatsSyncFlags() { + final int flags = mExternalStatsSync.flags; + mExternalStatsSync.flags = 0; + return flags; + } + private class DummyExternalStatsSync implements ExternalStatsSync { + public int flags = 0; + @Override public Future<?> scheduleSync(String reason, int flags) { return null; @@ -211,8 +220,9 @@ public class MockBatteryStatsImpl extends BatteryStatsImpl { } @Override - public Future<?> scheduleSyncDueToScreenStateChange( - int flag, boolean onBattery, boolean onBatteryScreenOff, int screenState) { + public Future<?> scheduleSyncDueToScreenStateChange(int flag, boolean onBattery, + boolean onBatteryScreenOff, int screenState, int[] perDisplayScreenStates) { + flags |= flag; return null; } diff --git a/core/tests/coretests/src/com/android/internal/os/ScreenPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/ScreenPowerCalculatorTest.java index 50e0a1512819..eee5d57c7bc6 100644 --- a/core/tests/coretests/src/com/android/internal/os/ScreenPowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/ScreenPowerCalculatorTest.java @@ -42,24 +42,27 @@ public class ScreenPowerCalculatorTest { private static final int APP_UID2 = Process.FIRST_APPLICATION_UID + 43; private static final long MINUTE_IN_MS = 60 * 1000; private static final long MINUTE_IN_US = 60 * 1000 * 1000; + private static final long HOUR_IN_MS = 60 * MINUTE_IN_MS; @Rule public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule() .setAveragePowerForOrdinal(POWER_GROUP_DISPLAY_SCREEN_ON, 0, 36.0) - .setAveragePowerForOrdinal(POWER_GROUP_DISPLAY_SCREEN_FULL, 0, 48.0); + .setAveragePowerForOrdinal(POWER_GROUP_DISPLAY_SCREEN_FULL, 0, 48.0) + .setNumDisplays(1); @Test public void testMeasuredEnergyBasedModel() { mStatsRule.initMeasuredEnergyStatsLocked(); BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats(); - batteryStats.noteScreenStateLocked(Display.STATE_ON, 0, 0, 0); - batteryStats.updateDisplayMeasuredEnergyStatsLocked(0, Display.STATE_ON, 0); + batteryStats.noteScreenStateLocked(0, Display.STATE_ON, 0, 0, 0); + batteryStats.updateDisplayMeasuredEnergyStatsLocked(new long[]{0}, + new int[]{Display.STATE_ON}, 0); setProcState(APP_UID1, ActivityManager.PROCESS_STATE_TOP, true, 0, 0); - batteryStats.updateDisplayMeasuredEnergyStatsLocked(200_000_000, Display.STATE_ON, - 15 * MINUTE_IN_MS); + batteryStats.updateDisplayMeasuredEnergyStatsLocked(new long[]{200_000_000}, + new int[]{Display.STATE_ON}, 15 * MINUTE_IN_MS); setProcState(APP_UID1, ActivityManager.PROCESS_STATE_CACHED_EMPTY, false, 20 * MINUTE_IN_MS, 20 * MINUTE_IN_MS); @@ -67,16 +70,16 @@ public class ScreenPowerCalculatorTest { setProcState(APP_UID2, ActivityManager.PROCESS_STATE_TOP, true, 20 * MINUTE_IN_MS, 20 * MINUTE_IN_MS); - batteryStats.updateDisplayMeasuredEnergyStatsLocked(300_000_000, Display.STATE_ON, - 60 * MINUTE_IN_MS); + batteryStats.updateDisplayMeasuredEnergyStatsLocked(new long[]{300_000_000}, + new int[]{Display.STATE_ON}, 60 * MINUTE_IN_MS); - batteryStats.noteScreenStateLocked(Display.STATE_OFF, + batteryStats.noteScreenStateLocked(0, Display.STATE_OFF, 80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS); setProcState(APP_UID2, ActivityManager.PROCESS_STATE_TOP_SLEEPING, false, 80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS); - batteryStats.updateDisplayMeasuredEnergyStatsLocked(100_000_000, Display.STATE_DOZE, - 120 * MINUTE_IN_MS); + batteryStats.updateDisplayMeasuredEnergyStatsLocked(new long[]{100_000_000}, + new int[]{Display.STATE_DOZE}, 120 * MINUTE_IN_MS); mStatsRule.setTime(120 * MINUTE_IN_US, 120 * MINUTE_IN_US); @@ -129,24 +132,122 @@ public class ScreenPowerCalculatorTest { .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY); } + + @Test + public void testMeasuredEnergyBasedModel_multiDisplay() { + mStatsRule.initMeasuredEnergyStatsLocked() + .setAveragePowerForOrdinal(POWER_GROUP_DISPLAY_SCREEN_ON, 1, 60.0) + .setAveragePowerForOrdinal(POWER_GROUP_DISPLAY_SCREEN_FULL, 1, 100.0) + .setNumDisplays(2); + + BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats(); + + final int[] screenStates = new int[]{Display.STATE_ON, Display.STATE_OFF}; + + batteryStats.noteScreenStateLocked(0, screenStates[0], 0, 0, 0); + batteryStats.noteScreenStateLocked(1, screenStates[1], 0, 0, 0); + batteryStats.noteScreenBrightnessLocked(0, 255, 0, 0); + setProcState(APP_UID1, ActivityManager.PROCESS_STATE_TOP, true, 0, 0); + batteryStats.updateDisplayMeasuredEnergyStatsLocked(new long[]{300, 400}, screenStates, 0); + + batteryStats.noteScreenBrightnessLocked(0, 100, 5 * MINUTE_IN_MS, 5 * MINUTE_IN_MS); + batteryStats.noteScreenBrightnessLocked(0, 200, 10 * MINUTE_IN_MS, 10 * MINUTE_IN_MS); + + setProcState(APP_UID1, ActivityManager.PROCESS_STATE_CACHED_EMPTY, false, + 20 * MINUTE_IN_MS, 20 * MINUTE_IN_MS); + setProcState(APP_UID2, ActivityManager.PROCESS_STATE_TOP, true, + 20 * MINUTE_IN_MS, 20 * MINUTE_IN_MS); + + screenStates[0] = Display.STATE_OFF; + screenStates[1] = Display.STATE_ON; + batteryStats.noteScreenStateLocked(0, screenStates[0], + 80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS); + batteryStats.noteScreenStateLocked(1, screenStates[1], 80 * MINUTE_IN_MS, + 80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS); + batteryStats.updateDisplayMeasuredEnergyStatsLocked(new long[]{600_000_000, 500}, + screenStates, 80 * MINUTE_IN_MS); + + batteryStats.noteScreenBrightnessLocked(1, 25, 80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS); + batteryStats.noteScreenBrightnessLocked(1, 250, 86 * MINUTE_IN_MS, 86 * MINUTE_IN_MS); + batteryStats.noteScreenBrightnessLocked(1, 75, 98 * MINUTE_IN_MS, 98 * MINUTE_IN_MS); + + screenStates[1] = Display.STATE_OFF; + batteryStats.noteScreenStateLocked(1, screenStates[1], 110 * MINUTE_IN_MS, + 110 * MINUTE_IN_MS, 110 * MINUTE_IN_MS); + batteryStats.updateDisplayMeasuredEnergyStatsLocked(new long[]{700, 800_000_000}, + screenStates, 110 * MINUTE_IN_MS); + + setProcState(APP_UID2, ActivityManager.PROCESS_STATE_TOP_SLEEPING, false, + 110 * MINUTE_IN_MS, 110 * MINUTE_IN_MS); + + mStatsRule.setTime(120 * MINUTE_IN_US, 120 * MINUTE_IN_US); + + ScreenPowerCalculator calculator = + new ScreenPowerCalculator(mStatsRule.getPowerProfile()); + + mStatsRule.apply(calculator); + + BatteryConsumer deviceConsumer = mStatsRule.getDeviceBatteryConsumer(); + assertThat(deviceConsumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN)) + .isEqualTo(110 * MINUTE_IN_MS); + // (600000000 + 800000000) uAs * (1 mA / 1000 uA) * (1 h / 3600 s) = 166.66666 mAh + assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN)) + .isWithin(PRECISION).of(388.88888); + assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_SCREEN)) + .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY); + + UidBatteryConsumer uid1 = mStatsRule.getUidBatteryConsumer(APP_UID1); + assertThat(uid1.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN)) + .isEqualTo(20 * MINUTE_IN_MS); + + // Uid1 ran for 20 out of 80 min during the first Display update. + // It also ran for 5 out of 45 min during the second Display update: + // Uid1 charge = 20 / 80 * 600000000 mAs = 41.66666 mAh + assertThat(uid1.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN)) + .isWithin(PRECISION).of(41.66666); + assertThat(uid1.getPowerModel(BatteryConsumer.POWER_COMPONENT_SCREEN)) + .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY); + + UidBatteryConsumer uid2 = mStatsRule.getUidBatteryConsumer(APP_UID2); + assertThat(uid2.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN)) + .isEqualTo(90 * MINUTE_IN_MS); + + // Uid2 ran for 60 out of 80 min during the first Display update. + // It also ran for all of the second Display update: + // Uid1 charge = 60 / 80 * 600000000 + 800000000 mAs = 347.22222 mAh + assertThat(uid2.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN)) + .isWithin(PRECISION).of(347.22222); + assertThat(uid2.getPowerModel(BatteryConsumer.POWER_COMPONENT_SCREEN)) + .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY); + + BatteryConsumer appsConsumer = mStatsRule.getAppsBatteryConsumer(); + assertThat(appsConsumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN)) + .isEqualTo(110 * MINUTE_IN_MS); + assertThat(appsConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN)) + .isWithin(PRECISION).of(388.88888); + assertThat(appsConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_SCREEN)) + .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY); + + } + @Test public void testPowerProfileBasedModel() { BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats(); - batteryStats.noteScreenStateLocked(Display.STATE_ON, 0, 0, 0); - batteryStats.noteScreenBrightnessLocked(255, 0, 0); + batteryStats.noteScreenStateLocked(0, Display.STATE_ON, 0, 0, 0); + batteryStats.noteScreenBrightnessLocked(0, 255, 0, 0); setProcState(APP_UID1, ActivityManager.PROCESS_STATE_TOP, true, 0, 0); - batteryStats.noteScreenBrightnessLocked(100, 5 * MINUTE_IN_MS, 5 * MINUTE_IN_MS); - batteryStats.noteScreenBrightnessLocked(200, 10 * MINUTE_IN_MS, 10 * MINUTE_IN_MS); + batteryStats.noteScreenBrightnessLocked(0, 100, 5 * MINUTE_IN_MS, 5 * MINUTE_IN_MS); + batteryStats.noteScreenBrightnessLocked(0, 200, 10 * MINUTE_IN_MS, 10 * MINUTE_IN_MS); setProcState(APP_UID1, ActivityManager.PROCESS_STATE_CACHED_EMPTY, false, 20 * MINUTE_IN_MS, 20 * MINUTE_IN_MS); setProcState(APP_UID2, ActivityManager.PROCESS_STATE_TOP, true, 20 * MINUTE_IN_MS, 20 * MINUTE_IN_MS); - batteryStats.noteScreenStateLocked(Display.STATE_OFF, + batteryStats.noteScreenStateLocked(0, Display.STATE_OFF, 80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS); setProcState(APP_UID2, ActivityManager.PROCESS_STATE_TOP_SLEEPING, false, 80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS); @@ -197,6 +298,95 @@ public class ScreenPowerCalculatorTest { .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE); } + + @Test + public void testPowerProfileBasedModel_multiDisplay() { + mStatsRule.setAveragePowerForOrdinal(POWER_GROUP_DISPLAY_SCREEN_ON, 1, 60.0) + .setAveragePowerForOrdinal(POWER_GROUP_DISPLAY_SCREEN_FULL, 1, 100.0) + .setNumDisplays(2); + + BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats(); + + batteryStats.noteScreenStateLocked(0, Display.STATE_ON, 0, 0, 0); + batteryStats.noteScreenStateLocked(1, Display.STATE_OFF, 0, 0, 0); + batteryStats.noteScreenBrightnessLocked(0, 255, 0, 0); + setProcState(APP_UID1, ActivityManager.PROCESS_STATE_TOP, true, + 0, 0); + + batteryStats.noteScreenBrightnessLocked(0, 100, 5 * MINUTE_IN_MS, 5 * MINUTE_IN_MS); + batteryStats.noteScreenBrightnessLocked(0, 200, 10 * MINUTE_IN_MS, 10 * MINUTE_IN_MS); + + setProcState(APP_UID1, ActivityManager.PROCESS_STATE_CACHED_EMPTY, false, + 20 * MINUTE_IN_MS, 20 * MINUTE_IN_MS); + setProcState(APP_UID2, ActivityManager.PROCESS_STATE_TOP, true, + 20 * MINUTE_IN_MS, 20 * MINUTE_IN_MS); + + batteryStats.noteScreenStateLocked(0, Display.STATE_OFF, + 80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS); + batteryStats.noteScreenStateLocked(1, Display.STATE_ON, 80 * MINUTE_IN_MS, + 80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS); + batteryStats.noteScreenBrightnessLocked(1, 20, 80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS); + + batteryStats.noteScreenBrightnessLocked(1, 250, 86 * MINUTE_IN_MS, 86 * MINUTE_IN_MS); + batteryStats.noteScreenBrightnessLocked(1, 75, 98 * MINUTE_IN_MS, 98 * MINUTE_IN_MS); + batteryStats.noteScreenStateLocked(1, Display.STATE_OFF, 110 * MINUTE_IN_MS, + 110 * MINUTE_IN_MS, 110 * MINUTE_IN_MS); + + setProcState(APP_UID2, ActivityManager.PROCESS_STATE_TOP_SLEEPING, false, + 110 * MINUTE_IN_MS, 110 * MINUTE_IN_MS); + + mStatsRule.setTime(120 * MINUTE_IN_US, 120 * MINUTE_IN_US); + ScreenPowerCalculator calculator = + new ScreenPowerCalculator(mStatsRule.getPowerProfile()); + + mStatsRule.apply(BatteryUsageStatsRule.POWER_PROFILE_MODEL_ONLY, calculator); + + BatteryConsumer deviceConsumer = mStatsRule.getDeviceBatteryConsumer(); + assertThat(deviceConsumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN)) + .isEqualTo(110 * MINUTE_IN_MS); + // First display consumed 92 mAh. + // Second display ran for 0.5 hours at a base drain rate of 60 mA. + // 6 minutes (0.1 hours) spent in the first brightness level which drains an extra 10 mA. + // 12 minutes (0.2 hours) spent in the fifth brightness level which drains an extra 90 mA. + // 12 minutes (0.2 hours) spent in the second brightness level which drains an extra 30 mA. + // 92 + 60 * 0.5 + 10 * 0.1 + 90 * 0.2 + 30 * 0.2 = 147 + assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN)) + .isWithin(PRECISION).of(147); + assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_SCREEN)) + .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE); + + UidBatteryConsumer uid1 = mStatsRule.getUidBatteryConsumer(APP_UID1); + assertThat(uid1.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN)) + .isEqualTo(20 * MINUTE_IN_MS); + + // Uid1 took 20 out of the total of 110 min of foreground activity + // Uid1 charge = 20 / 110 * 147.0 = 23.0 mAh + assertThat(uid1.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN)) + .isWithin(PRECISION).of(26.72727); + assertThat(uid1.getPowerModel(BatteryConsumer.POWER_COMPONENT_SCREEN)) + .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE); + + UidBatteryConsumer uid2 = mStatsRule.getUidBatteryConsumer(APP_UID2); + assertThat(uid2.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN)) + .isEqualTo(90 * MINUTE_IN_MS); + + // Uid2 took 90 out of the total of 110 min of foreground activity + // Uid2 charge = 90 / 110 * 92.0 = 69.0 mAh + assertThat(uid2.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN)) + .isWithin(PRECISION).of(120.272727); + assertThat(uid2.getPowerModel(BatteryConsumer.POWER_COMPONENT_SCREEN)) + .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE); + + BatteryConsumer appsConsumer = mStatsRule.getAppsBatteryConsumer(); + assertThat(appsConsumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_SCREEN)) + .isEqualTo(110 * MINUTE_IN_MS); + assertThat(appsConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SCREEN)) + .isWithin(PRECISION).of(147); + assertThat(appsConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_SCREEN)) + .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE); + + } + private void setProcState(int uid, int procState, boolean resumed, long realtimeMs, long uptimeMs) { BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats(); diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index 95736074a3ef..6e92755be98e 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -1141,6 +1141,12 @@ "group": "WM_DEBUG_BOOT", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "-863438038": { + "message": "Aborting Transition: %d", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/Transition.java" + }, "-861859917": { "message": "Attempted to add window to a display that does not exist: %d. Aborting.", "level": "WARN", diff --git a/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SidecarProvider.java b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SidecarProvider.java index 224db0291902..62959b7b95e9 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SidecarProvider.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SidecarProvider.java @@ -28,7 +28,7 @@ public class SidecarProvider { * an OEM by overriding this method. */ public static SidecarInterface getSidecarImpl(Context context) { - return new SampleSidecarImpl(context); + return new SampleSidecarImpl(context.getApplicationContext()); } /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/RootDisplayAreaOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/RootDisplayAreaOrganizer.java new file mode 100644 index 000000000000..14ba9df93f24 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/RootDisplayAreaOrganizer.java @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell; + +import android.util.SparseArray; +import android.view.SurfaceControl; +import android.window.DisplayAreaAppearedInfo; +import android.window.DisplayAreaInfo; +import android.window.DisplayAreaOrganizer; + +import androidx.annotation.NonNull; + +import java.io.PrintWriter; +import java.util.List; +import java.util.concurrent.Executor; + +/** Display area organizer for the root display areas */ +public class RootDisplayAreaOrganizer extends DisplayAreaOrganizer { + + private static final String TAG = RootDisplayAreaOrganizer.class.getSimpleName(); + + /** {@link DisplayAreaInfo} list, which is mapped by display IDs. */ + private final SparseArray<DisplayAreaInfo> mDisplayAreasInfo = new SparseArray<>(); + /** Display area leashes, which is mapped by display IDs. */ + private final SparseArray<SurfaceControl> mLeashes = new SparseArray<>(); + + public RootDisplayAreaOrganizer(Executor executor) { + super(executor); + List<DisplayAreaAppearedInfo> infos = registerOrganizer(FEATURE_ROOT); + for (int i = infos.size() - 1; i >= 0; --i) { + onDisplayAreaAppeared(infos.get(i).getDisplayAreaInfo(), infos.get(i).getLeash()); + } + } + + public void attachToDisplayArea(int displayId, SurfaceControl.Builder b) { + final SurfaceControl sc = mLeashes.get(displayId); + if (sc != null) { + b.setParent(sc); + } + } + + @Override + public void onDisplayAreaAppeared(@NonNull DisplayAreaInfo displayAreaInfo, + @NonNull SurfaceControl leash) { + if (displayAreaInfo.featureId != FEATURE_ROOT) { + throw new IllegalArgumentException( + "Unknown feature: " + displayAreaInfo.featureId + + "displayAreaInfo:" + displayAreaInfo); + } + + final int displayId = displayAreaInfo.displayId; + if (mDisplayAreasInfo.get(displayId) != null) { + throw new IllegalArgumentException( + "Duplicate DA for displayId: " + displayId + + " displayAreaInfo:" + displayAreaInfo + + " mDisplayAreasInfo.get():" + mDisplayAreasInfo.get(displayId)); + } + + mDisplayAreasInfo.put(displayId, displayAreaInfo); + mLeashes.put(displayId, leash); + } + + @Override + public void onDisplayAreaVanished(@NonNull DisplayAreaInfo displayAreaInfo) { + final int displayId = displayAreaInfo.displayId; + if (mDisplayAreasInfo.get(displayId) == null) { + throw new IllegalArgumentException( + "onDisplayAreaVanished() Unknown DA displayId: " + displayId + + " displayAreaInfo:" + displayAreaInfo + + " mDisplayAreasInfo.get():" + mDisplayAreasInfo.get(displayId)); + } + + mDisplayAreasInfo.remove(displayId); + } + + @Override + public void onDisplayAreaInfoChanged(@NonNull DisplayAreaInfo displayAreaInfo) { + final int displayId = displayAreaInfo.displayId; + if (mDisplayAreasInfo.get(displayId) == null) { + throw new IllegalArgumentException( + "onDisplayAreaInfoChanged() Unknown DA displayId: " + displayId + + " displayAreaInfo:" + displayAreaInfo + + " mDisplayAreasInfo.get():" + mDisplayAreasInfo.get(displayId)); + } + + mDisplayAreasInfo.put(displayId, displayAreaInfo); + } + + public void dump(@NonNull PrintWriter pw, String prefix) { + final String innerPrefix = prefix + " "; + final String childPrefix = innerPrefix + " "; + pw.println(prefix + this); + } + + @Override + public String toString() { + return TAG + "#" + mDisplayAreasInfo.size(); + } + +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java index 10d7725b6184..6a252e0d7dcb 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java @@ -232,7 +232,7 @@ class AppPair implements ShellTaskOrganizer.TaskListener, SplitLayout.SplitLayou if (mSplitLayout != null && mSplitLayout.updateConfiguration(mRootTaskInfo.configuration)) { - onLayoutChanged(mSplitLayout); + onLayoutSizeChanged(mSplitLayout); } } else if (taskInfo.taskId == getTaskId1()) { mTaskInfo1 = taskInfo; @@ -313,13 +313,19 @@ class AppPair implements ShellTaskOrganizer.TaskListener, SplitLayout.SplitLayou } @Override - public void onLayoutChanging(SplitLayout layout) { + public void onLayoutPositionChanging(SplitLayout layout) { mSyncQueue.runInSync(t -> layout.applySurfaceChanges(t, mTaskLeash1, mTaskLeash2, mDimLayer1, mDimLayer2)); } @Override - public void onLayoutChanged(SplitLayout layout) { + public void onLayoutSizeChanging(SplitLayout layout) { + mSyncQueue.runInSync(t -> + layout.applySurfaceChanges(t, mTaskLeash1, mTaskLeash2, mDimLayer1, mDimLayer2)); + } + + @Override + public void onLayoutSizeChanged(SplitLayout layout) { final WindowContainerTransaction wct = new WindowContainerTransaction(); layout.applyTaskChanges(wct, mTaskInfo1, mTaskInfo2); mSyncQueue.queue(wct); @@ -328,9 +334,9 @@ class AppPair implements ShellTaskOrganizer.TaskListener, SplitLayout.SplitLayou } @Override - public void onLayoutShifted(int offsetX, int offsetY, SplitLayout layout) { + public void setLayoutOffsetTarget(int offsetX, int offsetY, SplitLayout layout) { final WindowContainerTransaction wct = new WindowContainerTransaction(); - layout.applyLayoutShifted(wct, offsetX, offsetY, mTaskInfo1, mTaskInfo2); + layout.applyLayoutOffsetTarget(wct, offsetX, offsetY, mTaskInfo1, mTaskInfo2); mController.getTaskOrganizer().applyTransaction(wct); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java index 05ebbba4e955..8d43f1375a8c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java @@ -121,7 +121,7 @@ public class Bubble implements BubbleViewProvider { @Nullable private Icon mIcon; private boolean mIsBubble; - private boolean mIsVisuallyInterruptive; + private boolean mIsTextChanged; private boolean mIsClearable; private boolean mShouldSuppressNotificationDot; private boolean mShouldSuppressNotificationList; @@ -342,12 +342,12 @@ public class Bubble implements BubbleViewProvider { } /** - * Sets whether this bubble is considered visually interruptive. This method is purely for + * Sets whether this bubble is considered text changed. This method is purely for * testing. */ @VisibleForTesting - void setVisuallyInterruptiveForTest(boolean visuallyInterruptive) { - mIsVisuallyInterruptive = visuallyInterruptive; + void setTextChangedForTest(boolean textChanged) { + mIsTextChanged = textChanged; } /** @@ -454,7 +454,7 @@ public class Bubble implements BubbleViewProvider { mFlyoutMessage = extractFlyoutMessage(entry); if (entry.getRanking() != null) { mShortcutInfo = entry.getRanking().getConversationShortcutInfo(); - mIsVisuallyInterruptive = entry.getRanking().visuallyInterruptive(); + mIsTextChanged = entry.getRanking().isTextChanged(); if (entry.getRanking().getChannel() != null) { mIsImportantConversation = entry.getRanking().getChannel().isImportantConversation(); @@ -495,8 +495,8 @@ public class Bubble implements BubbleViewProvider { return mIcon; } - boolean isVisuallyInterruptive() { - return mIsVisuallyInterruptive; + boolean isTextChanged() { + return mIsTextChanged; } /** 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 c126f32387f0..b6d65bebff28 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 @@ -939,7 +939,7 @@ public class BubbleController { public void updateBubble(BubbleEntry notif, boolean suppressFlyout, boolean showInShade) { // If this is an interruptive notif, mark that it's interrupted mSysuiProxy.setNotificationInterruption(notif.getKey()); - if (!notif.getRanking().visuallyInterruptive() + if (!notif.getRanking().isTextChanged() && (notif.getBubbleMetadata() != null && !notif.getBubbleMetadata().getAutoExpandBubble()) && mBubbleData.hasOverflowBubbleWithKey(notif.getKey())) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java index bef26bfffef3..519a856538c7 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java @@ -323,7 +323,7 @@ public class BubbleData { } mPendingBubbles.remove(bubble.getKey()); // No longer pending once we're here Bubble prevBubble = getBubbleInStackWithKey(bubble.getKey()); - suppressFlyout |= !bubble.isVisuallyInterruptive(); + suppressFlyout |= !bubble.isTextChanged(); if (prevBubble == null) { // Create a new bubble 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 d590ab112aae..300319a2f78f 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 @@ -120,8 +120,6 @@ public class BubbleStackView extends FrameLayout private static final int EXPANDED_VIEW_ALPHA_ANIMATION_DURATION = 150; - private static final int MANAGE_MENU_SCRIM_ANIM_DURATION = 150; - private static final float SCRIM_ALPHA = 0.6f; /** @@ -894,6 +892,7 @@ public class BubbleStackView extends FrameLayout updatePointerPosition(false /* forIme */); mExpandedAnimationController.expandFromStack(() -> { afterExpandedViewAnimation(); + showManageMenu(mShowingManage); } /* after */); final float translationY = mPositioner.getExpandedViewY(mExpandedBubble, getBubbleIndex(mExpandedBubble)); @@ -1253,9 +1252,6 @@ public class BubbleStackView extends FrameLayout mRelativeStackPositionBeforeRotation = new RelativeStackPosition( mPositioner.getRestingPosition(), mStackAnimationController.getAllowableStackPositionRegion()); - mManageMenu.setVisibility(View.INVISIBLE); - mShowingManage = false; - addOnLayoutChangeListener(mOrientationChangedListener); hideFlyoutImmediate(); } @@ -2555,16 +2551,19 @@ public class BubbleStackView extends FrameLayout invalidate(); } - private void showManageMenu(boolean show) { + /** Hide or show the manage menu for the currently expanded bubble. */ + @VisibleForTesting + public void showManageMenu(boolean show) { mShowingManage = show; // This should not happen, since the manage menu is only visible when there's an expanded // bubble. If we end up in this state, just hide the menu immediately. if (mExpandedBubble == null || mExpandedBubble.getExpandedView() == null) { mManageMenu.setVisibility(View.INVISIBLE); + mManageMenuScrim.setVisibility(INVISIBLE); + mBubbleController.getSysuiProxy().onManageMenuExpandChanged(false /* show */); return; } - if (show) { mManageMenuScrim.setVisibility(VISIBLE); mManageMenuScrim.setTranslationZ(mManageMenu.getElevation() - 1f); @@ -2576,8 +2575,8 @@ public class BubbleStackView extends FrameLayout } }; + mBubbleController.getSysuiProxy().onManageMenuExpandChanged(show); mManageMenuScrim.animate() - .setDuration(MANAGE_MENU_SCRIM_ANIM_DURATION) .setInterpolator(show ? ALPHA_IN : ALPHA_OUT) .alpha(show ? SCRIM_ALPHA : 0f) .withEndAction(endAction) 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 9b7eb2f1cfb3..c82249b8a369 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 @@ -284,6 +284,8 @@ public interface Bubbles { void onStackExpandChanged(boolean shouldExpand); + void onManageMenuExpandChanged(boolean menuExpanded); + void onUnbubbleConversation(String key); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java index 962aca122b4d..7784665b3031 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java @@ -48,9 +48,11 @@ import android.view.Gravity; import android.view.InsetsSource; import android.view.InsetsState; import android.view.Surface; -import android.view.WindowInsets; + +import androidx.annotation.VisibleForTesting; import com.android.internal.R; +import com.android.internal.policy.SystemBarUtils; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -198,12 +200,13 @@ public class DisplayLayout { recalcInsets(res); } - private void recalcInsets(Resources res) { + @VisibleForTesting + void recalcInsets(Resources res) { computeNonDecorInsets(res, mRotation, mWidth, mHeight, mCutout, mInsetsState, mUiMode, mNonDecorInsets, mHasNavigationBar); mStableInsets.set(mNonDecorInsets); if (mHasStatusBar) { - convertNonDecorInsetsToStableInsets(res, mStableInsets, mWidth, mHeight, mHasStatusBar); + convertNonDecorInsetsToStableInsets(res, mStableInsets, mCutout, mHasStatusBar); } mNavBarFrameHeight = getNavigationBarFrameHeight(res, mWidth > mHeight); } @@ -323,12 +326,12 @@ public class DisplayLayout { /** * Calculates the stable insets if we already have the non-decor insets. */ - private static void convertNonDecorInsetsToStableInsets(Resources res, Rect inOutInsets, - int displayWidth, int displayHeight, boolean hasStatusBar) { + private void convertNonDecorInsetsToStableInsets(Resources res, Rect inOutInsets, + DisplayCutout cutout, boolean hasStatusBar) { if (!hasStatusBar) { return; } - int statusBarHeight = getStatusBarHeight(displayWidth > displayHeight, res); + int statusBarHeight = SystemBarUtils.getStatusBarHeight(res, cutout); inOutInsets.top = Math.max(inOutInsets.top, statusBarHeight); } @@ -377,35 +380,6 @@ public class DisplayLayout { } } - /** - * Calculates the stable insets without running a layout. - * - * @param displayRotation the current display rotation - * @param displayWidth the current display width - * @param displayHeight the current display height - * @param displayCutout the current display cutout - * @param outInsets the insets to return - */ - static void computeStableInsets(Resources res, int displayRotation, int displayWidth, - int displayHeight, DisplayCutout displayCutout, InsetsState insetsState, int uiMode, - Rect outInsets, boolean hasNavigationBar, boolean hasStatusBar) { - outInsets.setEmpty(); - - // Navigation bar and status bar. - computeNonDecorInsets(res, displayRotation, displayWidth, displayHeight, displayCutout, - insetsState, uiMode, outInsets, hasNavigationBar); - convertNonDecorInsetsToStableInsets(res, outInsets, displayWidth, displayHeight, - hasStatusBar); - } - - /** Retrieve the statusbar height from resources. */ - static int getStatusBarHeight(boolean landscape, Resources res) { - return landscape ? res.getDimensionPixelSize( - com.android.internal.R.dimen.status_bar_height_landscape) - : res.getDimensionPixelSize( - com.android.internal.R.dimen.status_bar_height_portrait); - } - /** Calculate the DisplayCutout for a particular display size/rotation. */ public static DisplayCutout calculateDisplayCutoutForRotation( DisplayCutout cutout, int rotation, int displayWidth, int displayHeight) { 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 596a2f4467c3..5b3ce2dbaeb9 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 @@ -291,13 +291,13 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange void updateDivideBounds(int position) { updateBounds(position); mSplitWindowManager.setResizingSplits(true); - mSplitLayoutHandler.onLayoutChanging(this); + mSplitLayoutHandler.onLayoutSizeChanging(this); } void setDividePosition(int position) { mDividePosition = position; updateBounds(mDividePosition); - mSplitLayoutHandler.onLayoutChanged(this); + mSplitLayoutHandler.onLayoutSizeChanged(this); mSplitWindowManager.setResizingSplits(false); } @@ -451,7 +451,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange * Shift configuration bounds to prevent client apps get configuration changed or relaunch. And * restore shifted configuration bounds if it's no longer shifted. */ - public void applyLayoutShifted(WindowContainerTransaction wct, int offsetX, int offsetY, + public void applyLayoutOffsetTarget(WindowContainerTransaction wct, int offsetX, int offsetY, ActivityManager.RunningTaskInfo taskInfo1, ActivityManager.RunningTaskInfo taskInfo2) { if (offsetX == 0 && offsetY == 0) { wct.setBounds(taskInfo1.token, mBounds1); @@ -492,19 +492,43 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange /** Calls when dismissing split. */ void onSnappedToDismiss(boolean snappedToEnd); - /** Calls when the bounds is changing due to animation or dragging divider bar. */ - void onLayoutChanging(SplitLayout layout); + /** + * Calls when resizing the split bounds. + * + * @see #applySurfaceChanges(SurfaceControl.Transaction, SurfaceControl, SurfaceControl, + * SurfaceControl, SurfaceControl) + */ + void onLayoutSizeChanging(SplitLayout layout); - /** Calls when the target bounds changed. */ - void onLayoutChanged(SplitLayout layout); + /** + * Calls when finish resizing the split bounds. + * + * @see #applyTaskChanges(WindowContainerTransaction, ActivityManager.RunningTaskInfo, + * ActivityManager.RunningTaskInfo) + * @see #applySurfaceChanges(SurfaceControl.Transaction, SurfaceControl, SurfaceControl, + * SurfaceControl, SurfaceControl) + */ + void onLayoutSizeChanged(SplitLayout layout); /** - * Notifies when the layout shifted. So the layout handler can shift configuration + * Calls when re-positioning the split bounds. Like moving split bounds while showing IME + * panel. + * + * @see #applySurfaceChanges(SurfaceControl.Transaction, SurfaceControl, SurfaceControl, + * SurfaceControl, SurfaceControl) + */ + void onLayoutPositionChanging(SplitLayout layout); + + /** + * Notifies the target offset for shifting layout. So layout handler can shift configuration * bounds correspondingly to make sure client apps won't get configuration changed or - * relaunch. If the layout is no longer shifted, layout handler should restore shifted + * relaunched. If the layout is no longer shifted, layout handler should restore shifted * configuration bounds. + * + * @see #applyLayoutOffsetTarget(WindowContainerTransaction, int, int, + * ActivityManager.RunningTaskInfo, ActivityManager.RunningTaskInfo) */ - void onLayoutShifted(int offsetX, int offsetY, SplitLayout layout); + void setLayoutOffsetTarget(int offsetX, int offsetY, SplitLayout layout); /** Calls when user double tapped on the divider bar. */ default void onDoubleTappedDivider() { @@ -674,9 +698,9 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange // changed or relaunch. This is required to make sure client apps will calculate // insets properly after layout shifted. if (mTargetYOffset == 0) { - mSplitLayoutHandler.onLayoutShifted(0, 0, SplitLayout.this); + mSplitLayoutHandler.setLayoutOffsetTarget(0, 0, SplitLayout.this); } else { - mSplitLayoutHandler.onLayoutShifted(0, mTargetYOffset - mLastYOffset, + mSplitLayoutHandler.setLayoutOffsetTarget(0, mTargetYOffset - mLastYOffset, SplitLayout.this); } } @@ -695,7 +719,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange public void onImePositionChanged(int displayId, int imeTop, SurfaceControl.Transaction t) { if (displayId != mDisplayId) return; onProgress(getProgress(imeTop)); - mSplitLayoutHandler.onLayoutChanging(SplitLayout.this); + mSplitLayoutHandler.onLayoutPositionChanging(SplitLayout.this); } @Override @@ -703,7 +727,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange SurfaceControl.Transaction t) { if (displayId != mDisplayId || cancel) return; onProgress(1.0f); - mSplitLayoutHandler.onLayoutChanging(SplitLayout.this); + mSplitLayoutHandler.onLayoutPositionChanging(SplitLayout.this); } @Override @@ -713,7 +737,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange if (!controlling && mImeShown) { reset(); mSplitWindowManager.setInteractive(true); - mSplitLayoutHandler.onLayoutChanging(SplitLayout.this); + mSplitLayoutHandler.onLayoutPositionChanging(SplitLayout.this); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/displayareahelper/DisplayAreaHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/displayareahelper/DisplayAreaHelper.java new file mode 100644 index 000000000000..defbd5af01d9 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/displayareahelper/DisplayAreaHelper.java @@ -0,0 +1,39 @@ +/* + * 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.wm.shell.displayareahelper; + +import android.view.SurfaceControl; + +import java.util.function.Consumer; + +/** + * Interface that allows to perform various display area related actions + */ +public interface DisplayAreaHelper { + + /** + * Updates SurfaceControl builder to reparent it to the root display area + * @param displayId id of the display to which root display area it should be reparented to + * @param builder surface control builder that should be updated + * @param onUpdated callback that is invoked after updating the builder, called on + * the shell main thread + */ + default void attachToRootDisplayArea(int displayId, SurfaceControl.Builder builder, + Consumer<SurfaceControl.Builder> onUpdated) { + } + +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/displayareahelper/DisplayAreaHelperController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/displayareahelper/DisplayAreaHelperController.java new file mode 100644 index 000000000000..ef9ad6d10e6b --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/displayareahelper/DisplayAreaHelperController.java @@ -0,0 +1,45 @@ +/* + * 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.wm.shell.displayareahelper; + +import android.view.SurfaceControl; + +import com.android.wm.shell.RootDisplayAreaOrganizer; + +import java.util.concurrent.Executor; +import java.util.function.Consumer; + +public class DisplayAreaHelperController implements DisplayAreaHelper { + + private final Executor mExecutor; + private final RootDisplayAreaOrganizer mRootDisplayAreaOrganizer; + + public DisplayAreaHelperController(Executor executor, + RootDisplayAreaOrganizer rootDisplayAreaOrganizer) { + mExecutor = executor; + mRootDisplayAreaOrganizer = rootDisplayAreaOrganizer; + } + + @Override + public void attachToRootDisplayArea(int displayId, SurfaceControl.Builder builder, + Consumer<SurfaceControl.Builder> onUpdated) { + mExecutor.execute(() -> { + mRootDisplayAreaOrganizer.attachToDisplayArea(displayId, builder); + onUpdated.accept(builder); + }); + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizer.java index 75a1ddeccb22..3f7d78dda037 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizer.java @@ -39,7 +39,7 @@ import androidx.annotation.GuardedBy; import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; -import com.android.internal.R; +import com.android.internal.policy.SystemBarUtils; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.common.ShellExecutor; @@ -307,12 +307,9 @@ class HideDisplayCutoutOrganizer extends DisplayAreaOrganizer { t.apply(); } - private int getStatusBarHeight() { - final boolean isLandscape = - mIsDefaultPortrait ? isDisplaySizeFlipped() : !isDisplaySizeFlipped(); - return mContext.getResources().getDimensionPixelSize( - isLandscape ? R.dimen.status_bar_height_landscape - : R.dimen.status_bar_height_portrait); + @VisibleForTesting + int getStatusBarHeight() { + return SystemBarUtils.getStatusBarHeight(mContext); } void dump(@NonNull PrintWriter pw) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java index 38079aff9a6f..900743712227 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java @@ -689,6 +689,8 @@ public class OneHandedController implements RemoteCallable<OneHandedController>, pw.println(mUserId); pw.print(innerPrefix + "isShortcutEnabled="); pw.println(isShortcutEnabled()); + pw.print(innerPrefix + "mIsSwipeToNotificationEnabled="); + pw.println(mIsSwipeToNotificationEnabled); if (mBackgroundPanelOrganizer != null) { mBackgroundPanelOrganizer.dump(pw); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java index ff333c8c659d..2cb7d1b0fa0d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java @@ -244,6 +244,8 @@ public final class OneHandedSettingsUtil { pw.println(TAG); pw.print(innerPrefix + "isOneHandedModeEnable="); pw.println(getSettingsOneHandedModeEnabled(resolver, userId)); + pw.print(innerPrefix + "isSwipeToNotificationEnabled="); + pw.println(getSettingsSwipeToNotificationEnabled(resolver, userId)); pw.print(innerPrefix + "oneHandedTimeOut="); pw.println(getSettingsOneHandedModeTimeout(resolver, userId)); pw.print(innerPrefix + "tapsAppToExit="); 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 96867761cc7e..291cbb3676dc 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 @@ -282,6 +282,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, mMainExecutor.execute(() -> { mTaskOrganizer.addListenerForType(this, TASK_LISTENER_TYPE_PIP); }); + mPipTransitionController.setPipOrganizer(this); displayController.addDisplayWindowListener(this); } @@ -349,6 +350,10 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, } } + public ActivityManager.RunningTaskInfo getTaskInfo() { + return mTaskInfo; + } + public SurfaceControl getSurfaceControl() { return mLeash; } @@ -716,6 +721,9 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, mOnDisplayIdChangeCallback.accept(Display.DEFAULT_DISPLAY); } + if (Transitions.ENABLE_SHELL_TRANSITIONS) { + mPipTransitionController.forceFinishTransition(); + } final PipAnimationController.PipTransitionAnimator<?> animator = mPipAnimationController.getCurrentAnimator(); if (animator != null) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java index 6fec1fbda7b0..328f3ed73f2e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java @@ -32,17 +32,18 @@ import static com.android.wm.shell.pip.PipAnimationController.isOutPipDirection; import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP; import static com.android.wm.shell.transition.Transitions.TRANSIT_REMOVE_PIP; +import android.app.ActivityManager; import android.app.TaskInfo; import android.content.Context; import android.graphics.Matrix; import android.graphics.Rect; import android.os.IBinder; +import android.util.Log; import android.view.Surface; import android.view.SurfaceControl; import android.window.TransitionInfo; import android.window.TransitionRequestInfo; import android.window.WindowContainerTransaction; -import android.window.WindowContainerTransactionCallback; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -57,11 +58,14 @@ import com.android.wm.shell.transition.Transitions; */ public class PipTransition extends PipTransitionController { + private static final String TAG = PipTransition.class.getSimpleName(); + private final PipTransitionState mPipTransitionState; private final int mEnterExitAnimationDuration; private @PipAnimationController.AnimationType int mOneShotAnimationType = ANIM_TYPE_BOUNDS; private Transitions.TransitionFinishCallback mFinishCallback; private Rect mExitDestinationBounds = new Rect(); + private IBinder mExitTransition = null; public PipTransition(Context context, PipBoundsState pipBoundsState, @@ -96,7 +100,7 @@ public class PipTransition extends PipTransitionController { public void startTransition(Rect destinationBounds, WindowContainerTransaction out) { if (destinationBounds != null) { mExitDestinationBounds.set(destinationBounds); - mTransitions.startTransition(TRANSIT_EXIT_PIP, out, this); + mExitTransition = mTransitions.startTransition(TRANSIT_EXIT_PIP, out, this); } else { mTransitions.startTransition(TRANSIT_REMOVE_PIP, out, this); } @@ -109,14 +113,19 @@ public class PipTransition extends PipTransitionController { @android.annotation.NonNull SurfaceControl.Transaction finishTransaction, @android.annotation.NonNull Transitions.TransitionFinishCallback finishCallback) { - if (info.getType() == TRANSIT_EXIT_PIP && info.getChanges().size() == 1) { - final TransitionInfo.Change change = info.getChanges().get(0); - mFinishCallback = finishCallback; - startTransaction.apply(); - boolean success = startExpandAnimation(change.getTaskInfo(), change.getLeash(), - new Rect(mExitDestinationBounds)); - mExitDestinationBounds.setEmpty(); - return success; + if (mExitTransition == transition || info.getType() == TRANSIT_EXIT_PIP) { + mExitTransition = null; + if (info.getChanges().size() == 1) { + final TransitionInfo.Change change = info.getChanges().get(0); + mFinishCallback = finishCallback; + startTransaction.apply(); + boolean success = startExpandAnimation(change.getTaskInfo(), change.getLeash(), + new Rect(mExitDestinationBounds)); + mExitDestinationBounds.setEmpty(); + return success; + } else { + Log.e(TAG, "Got an exit-pip transition with unexpected change-list"); + } } if (info.getType() == TRANSIT_REMOVE_PIP) { @@ -183,26 +192,58 @@ public class PipTransition extends PipTransitionController { } @Override + public void onTransitionMerged(@NonNull IBinder transition) { + if (transition != mExitTransition) { + return; + } + // This means an expand happened before enter-pip finished and we are now "merging" a + // no-op transition that happens to match our exit-pip. + boolean cancelled = false; + if (mPipAnimationController.getCurrentAnimator() != null) { + mPipAnimationController.getCurrentAnimator().cancel(); + cancelled = true; + } + // Unset exitTransition AFTER cancel so that finishResize knows we are merging. + mExitTransition = null; + if (!cancelled) return; + final ActivityManager.RunningTaskInfo taskInfo = mPipOrganizer.getTaskInfo(); + if (taskInfo != null) { + startExpandAnimation(taskInfo, mPipOrganizer.getSurfaceControl(), + new Rect(mExitDestinationBounds)); + } + mExitDestinationBounds.setEmpty(); + } + + @Override public void onFinishResize(TaskInfo taskInfo, Rect destinationBounds, @PipAnimationController.TransitionDirection int direction, - SurfaceControl.Transaction tx) { + @Nullable SurfaceControl.Transaction tx) { if (isInPipDirection(direction)) { mPipTransitionState.setTransitionState(PipTransitionState.ENTERED_PIP); } - WindowContainerTransaction wct = new WindowContainerTransaction(); - prepareFinishResizeTransaction(taskInfo, destinationBounds, - direction, tx, wct); - mFinishCallback.onTransitionFinished(wct, new WindowContainerTransactionCallback() { - @Override - public void onTransactionReady(int id, @NonNull SurfaceControl.Transaction t) { - t.merge(tx); - t.apply(); + // If there is an expected exit transition, then the exit will be "merged" into this + // transition so don't fire the finish-callback in that case. + if (mExitTransition == null && mFinishCallback != null) { + WindowContainerTransaction wct = new WindowContainerTransaction(); + prepareFinishResizeTransaction(taskInfo, destinationBounds, + direction, wct); + if (tx != null) { + wct.setBoundsChangeTransaction(taskInfo.token, tx); } - }); + mFinishCallback.onTransitionFinished(wct, null /* wctCallback */); + mFinishCallback = null; + } finishResizeForMenu(destinationBounds); } + @Override + public void forceFinishTransition() { + if (mFinishCallback == null) return; + mFinishCallback.onTransitionFinished(null /* wct */, null /* wctCallback */); + mFinishCallback = null; + } + private boolean startExpandAnimation(final TaskInfo taskInfo, final SurfaceControl leash, final Rect destinationBounds) { PipAnimationController.PipTransitionAnimator animator = @@ -243,7 +284,7 @@ public class PipTransition extends PipTransitionController { startTransaction.merge(tx); startTransaction.apply(); mPipBoundsState.setBounds(destinationBounds); - onFinishResize(taskInfo, destinationBounds, TRANSITION_DIRECTION_TO_PIP, tx); + onFinishResize(taskInfo, destinationBounds, TRANSITION_DIRECTION_TO_PIP, null /* tx */); sendOnPipTransitionFinished(TRANSITION_DIRECTION_TO_PIP); mFinishCallback = null; mPipTransitionState.setInSwipePipToHomeTransition(false); @@ -292,7 +333,6 @@ public class PipTransition extends PipTransitionController { private void prepareFinishResizeTransaction(TaskInfo taskInfo, Rect destinationBounds, @PipAnimationController.TransitionDirection int direction, - SurfaceControl.Transaction tx, WindowContainerTransaction wct) { Rect taskBounds = null; if (isInPipDirection(direction)) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java index dbf603ca72d9..376f3298a83c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java @@ -49,6 +49,7 @@ public abstract class PipTransitionController implements Transitions.TransitionH protected final Transitions mTransitions; private final Handler mMainHandler; private final List<PipTransitionCallback> mPipTransitionCallbacks = new ArrayList<>(); + protected PipTaskOrganizer mPipOrganizer; protected final PipAnimationController.PipAnimationCallback mPipAnimationCallback = new PipAnimationController.PipAnimationCallback() { @@ -103,6 +104,13 @@ public abstract class PipTransitionController implements Transitions.TransitionH // Default implementation does nothing. } + /** + * Called when the transition animation can't continue (eg. task is removed during + * animation) + */ + public void forceFinishTransition() { + } + public PipTransitionController(PipBoundsState pipBoundsState, PipMenuController pipMenuController, PipBoundsAlgorithm pipBoundsAlgorithm, PipAnimationController pipAnimationController, Transitions transitions, @@ -119,6 +127,10 @@ public abstract class PipTransitionController implements Transitions.TransitionH } } + void setPipOrganizer(PipTaskOrganizer pto) { + mPipOrganizer = pto; + } + /** * Registers {@link PipTransitionCallback} to receive transition callbacks. */ diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java index 7f82ebde77af..a47a15287dda 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java @@ -49,25 +49,24 @@ class MainStage extends StageTaskListener { return mIsActive; } - void activate(Rect rootBounds, WindowContainerTransaction wct) { + void activate(Rect rootBounds, WindowContainerTransaction wct, boolean includingTopTask) { if (mIsActive) return; final WindowContainerToken rootToken = mRootTaskInfo.token; wct.setBounds(rootToken, rootBounds) .setWindowingMode(rootToken, WINDOWING_MODE_MULTI_WINDOW) - .setLaunchRoot( - rootToken, - CONTROLLED_WINDOWING_MODES, - CONTROLLED_ACTIVITY_TYPES) - .reparentTasks( - null /* currentParent */, - rootToken, - CONTROLLED_WINDOWING_MODES, - CONTROLLED_ACTIVITY_TYPES, - true /* onTop */) // Moving the root task to top after the child tasks were re-parented , or the root // task cannot be visible and focused. .reorder(rootToken, true /* onTop */); + if (includingTopTask) { + wct.reparentTasks( + null /* currentParent */, + rootToken, + CONTROLLED_WINDOWING_MODES, + CONTROLLED_ACTIVITY_TYPES, + true /* onTop */, + true /* reparentTopOnly */); + } mIsActive = true; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java index 0d5271924375..3b75bfb933c9 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java @@ -16,6 +16,8 @@ package com.android.wm.shell.splitscreen; +import static android.app.ActivityManager.START_SUCCESS; +import static android.app.ActivityManager.START_TASK_TO_FRONT; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.RemoteAnimationTarget.MODE_OPENING; @@ -213,7 +215,13 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, options = mStageCoordinator.resolveStartStage(stage, position, options, null /* wct */); try { - ActivityTaskManager.getService().startActivityFromRecents(taskId, options); + final WindowContainerTransaction evictWct = new WindowContainerTransaction(); + mStageCoordinator.prepareEvictChildTasks(position, evictWct); + final int result = + ActivityTaskManager.getService().startActivityFromRecents(taskId, options); + if (result == START_SUCCESS || result == START_TASK_TO_FRONT) { + mSyncQueue.queue(evictWct); + } } catch (RemoteException e) { Slog.e(TAG, "Failed to launch task", e); } @@ -223,12 +231,15 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, @SplitScreen.StageType int stage, @SplitPosition int position, @Nullable Bundle options, UserHandle user) { options = mStageCoordinator.resolveStartStage(stage, position, options, null /* wct */); + final WindowContainerTransaction evictWct = new WindowContainerTransaction(); + mStageCoordinator.prepareEvictChildTasks(position, evictWct); try { LauncherApps launcherApps = mContext.getSystemService(LauncherApps.class); launcherApps.startShortcut(packageName, shortcutId, null /* sourceBounds */, options, user); + mSyncQueue.queue(evictWct); } catch (ActivityNotFoundException e) { Slog.e(TAG, "Failed to launch shortcut", e); } @@ -248,6 +259,9 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, private void startIntentLegacy(PendingIntent intent, Intent fillInIntent, @SplitScreen.StageType int stage, @SplitPosition int position, @Nullable Bundle options) { + final WindowContainerTransaction evictWct = new WindowContainerTransaction(); + mStageCoordinator.prepareEvictChildTasks(position, evictWct); + LegacyTransitions.ILegacyTransition transition = new LegacyTransitions.ILegacyTransition() { @Override public void onAnimationStart(int transit, RemoteAnimationTarget[] apps, @@ -272,9 +286,12 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, Slog.e(TAG, "Error finishing legacy transition: ", e); } } + + mSyncQueue.queue(evictWct); } }; - WindowContainerTransaction wct = new WindowContainerTransaction(); + + final WindowContainerTransaction wct = new WindowContainerTransaction(); options = mStageCoordinator.resolveStartStage(stage, position, options, wct); wct.sendPendingIntent(intent, fillInIntent, options); mSyncQueue.queue(transition, WindowManager.TRANSIT_OPEN, wct); 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 414b4e48efdd..72d9880d0aa1 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 @@ -263,7 +263,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, @SplitPosition int sideStagePosition) { final WindowContainerTransaction wct = new WindowContainerTransaction(); setSideStagePosition(sideStagePosition, wct); - mMainStage.activate(getMainStageBounds(), wct); + mMainStage.activate(getMainStageBounds(), wct, true /* reparent */); mSideStage.addTask(task, getSideStageBounds(), wct); mSyncQueue.queue(wct); mSyncQueue.runInSync(t -> updateSurfaceBounds(null /* layout */, t)); @@ -299,7 +299,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, // Build a request WCT that will launch both apps such that task 0 is on the main stage // while task 1 is on the side stage. - mMainStage.activate(getMainStageBounds(), wct); + mMainStage.activate(getMainStageBounds(), wct, false /* reparent */); mSideStage.setBounds(getSideStageBounds(), wct); // Make sure the launch options will put tasks in the corresponding split roots @@ -368,7 +368,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, // Build a request WCT that will launch both apps such that task 0 is on the main stage // while task 1 is on the side stage. - mMainStage.activate(getMainStageBounds(), wct); + mMainStage.activate(getMainStageBounds(), wct, false /* reparent */); mSideStage.setBounds(getSideStageBounds(), wct); // Make sure the launch options will put tasks in the corresponding split roots @@ -394,6 +394,18 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE, wct, remoteTransition, this); } + /** + * Collects all the current child tasks of a specific split and prepares transaction to evict + * them to display. + */ + void prepareEvictChildTasks(@SplitPosition int position, WindowContainerTransaction wct) { + if (position == mSideStagePosition) { + mSideStage.evictAllChildren(wct); + } else { + mMainStage.evictAllChildren(wct); + } + } + Bundle resolveStartStage(@SplitScreen.StageType int stage, @SplitPosition int position, @androidx.annotation.Nullable Bundle options, @androidx.annotation.Nullable WindowContainerTransaction wct) { @@ -471,7 +483,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, if (mSideStageListener.mVisible && updateBounds) { if (wct == null) { // onLayoutChanged builds/applies a wct with the contents of updateWindowBounds. - onLayoutChanged(mSplitLayout); + onLayoutSizeChanged(mSplitLayout); } else { updateWindowBounds(mSplitLayout, wct); updateUnfoldBounds(); @@ -756,7 +768,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, } else if (isSideStage) { final WindowContainerTransaction wct = new WindowContainerTransaction(); // Make sure the main stage is active. - mMainStage.activate(getMainStageBounds(), wct); + mMainStage.activate(getMainStageBounds(), wct, true /* reparent */); mSideStage.setBounds(getSideStageBounds(), wct); mTaskOrganizer.applyTransaction(wct); } @@ -799,13 +811,18 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, } @Override - public void onLayoutChanging(SplitLayout layout) { + public void onLayoutPositionChanging(SplitLayout layout) { + mSyncQueue.runInSync(t -> updateSurfaceBounds(layout, t)); + } + + @Override + public void onLayoutSizeChanging(SplitLayout layout) { mSyncQueue.runInSync(t -> updateSurfaceBounds(layout, t)); mSideStage.setOutlineVisibility(false); } @Override - public void onLayoutChanged(SplitLayout layout) { + public void onLayoutSizeChanged(SplitLayout layout) { final WindowContainerTransaction wct = new WindowContainerTransaction(); updateWindowBounds(layout, wct); updateUnfoldBounds(); @@ -859,13 +876,13 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, } @Override - public void onLayoutShifted(int offsetX, int offsetY, SplitLayout layout) { + public void setLayoutOffsetTarget(int offsetX, int offsetY, SplitLayout layout) { final StageTaskListener topLeftStage = mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mSideStage : mMainStage; final StageTaskListener bottomRightStage = mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mMainStage : mSideStage; final WindowContainerTransaction wct = new WindowContainerTransaction(); - layout.applyLayoutShifted(wct, offsetX, offsetY, topLeftStage.mRootTaskInfo, + layout.applyLayoutOffsetTarget(wct, offsetX, offsetY, topLeftStage.mRootTaskInfo, bottomRightStage.mRootTaskInfo); mTaskOrganizer.applyTransaction(wct); } @@ -897,7 +914,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, if (mSplitLayout != null && mSplitLayout.updateConfiguration(mDisplayAreaInfo.configuration) && mMainStage.isActive()) { - onLayoutChanged(mSplitLayout); + onLayoutSizeChanged(mSplitLayout); } } 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 84d570f4be44..6f1a09dc88e6 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 @@ -68,6 +68,7 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener { void onChildTaskStatusChanged(int taskId, boolean present, boolean visible); void onRootTaskVanished(); + void onNoLongerSupportMultiWindow(); } @@ -247,6 +248,14 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener { wct.reorder(mChildrenTaskInfo.get(taskId).token, onTop /* onTop */); } + /** Collects all the current child tasks and prepares transaction to evict them to display. */ + void evictAllChildren(WindowContainerTransaction wct) { + for (int i = mChildrenTaskInfo.size() - 1; i >= 0; i--) { + final ActivityManager.RunningTaskInfo taskInfo = mChildrenTaskInfo.valueAt(i); + wct.reparent(taskInfo.token, null /* parent */, false /* onTop */); + } + } + void setVisibility(boolean visible, WindowContainerTransaction wct) { wct.reorder(mRootTaskInfo.token, visible /* onTop */); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/StageCoordinator.java index 2f75f8bdc64c..574e379921b1 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/StageCoordinator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/StageCoordinator.java @@ -470,8 +470,8 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, if (mSideStageListener.mVisible && updateBounds) { if (wct == null) { - // onLayoutChanged builds/applies a wct with the contents of updateWindowBounds. - onLayoutChanged(mSplitLayout); + // onLayoutSizeChanged builds/applies a wct with the contents of updateWindowBounds. + onLayoutSizeChanged(mSplitLayout); } else { updateWindowBounds(mSplitLayout, wct); updateUnfoldBounds(); @@ -800,13 +800,18 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, } @Override - public void onLayoutChanging(SplitLayout layout) { + public void onLayoutPositionChanging(SplitLayout layout) { + mSyncQueue.runInSync(t -> updateSurfaceBounds(layout, t)); + } + + @Override + public void onLayoutSizeChanging(SplitLayout layout) { mSyncQueue.runInSync(t -> updateSurfaceBounds(layout, t)); mSideStage.setOutlineVisibility(false); } @Override - public void onLayoutChanged(SplitLayout layout) { + public void onLayoutSizeChanged(SplitLayout layout) { final WindowContainerTransaction wct = new WindowContainerTransaction(); updateWindowBounds(layout, wct); updateUnfoldBounds(); @@ -860,13 +865,13 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, } @Override - public void onLayoutShifted(int offsetX, int offsetY, SplitLayout layout) { + public void setLayoutOffsetTarget(int offsetX, int offsetY, SplitLayout layout) { final StageTaskListener topLeftStage = mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mSideStage : mMainStage; final StageTaskListener bottomRightStage = mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mMainStage : mSideStage; final WindowContainerTransaction wct = new WindowContainerTransaction(); - layout.applyLayoutShifted(wct, offsetX, offsetY, topLeftStage.mRootTaskInfo, + layout.applyLayoutOffsetTarget(wct, offsetX, offsetY, topLeftStage.mRootTaskInfo, bottomRightStage.mRootTaskInfo); mTaskOrganizer.applyTransaction(wct); } @@ -898,7 +903,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, if (mSplitLayout != null && mSplitLayout.updateConfiguration(mDisplayAreaInfo.configuration) && mMainStage.isActive()) { - onLayoutChanged(mSplitLayout); + onLayoutSizeChanged(mSplitLayout); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java index 8df7cbb27807..b191cabcf6aa 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java @@ -110,9 +110,9 @@ public class SplashscreenContentDrawer { @VisibleForTesting final ColorCache mColorCache; - SplashscreenContentDrawer(Context context, TransactionPool pool) { + SplashscreenContentDrawer(Context context, IconProvider iconProvider, TransactionPool pool) { mContext = context; - mIconProvider = new IconProvider(context); + mIconProvider = iconProvider; mTransactionPool = pool; // Initialize Splashscreen worker thread diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java index f0685a81d25f..38122ffc032b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java @@ -38,6 +38,7 @@ import android.graphics.drawable.Animatable; import android.graphics.drawable.Drawable; import android.os.Handler; import android.os.Trace; +import android.util.Log; import android.util.PathParser; import android.window.SplashScreenView; @@ -50,6 +51,8 @@ import com.android.internal.R; */ public class SplashscreenIconDrawableFactory { + private static final String TAG = "SplashscreenIconDrawableFactory"; + /** * @return An array containing the foreground drawable at index 0 and if needed a background * drawable at index 1. @@ -282,7 +285,12 @@ public class SplashscreenIconDrawableFactory { if (startListener != null) { startListener.run(); } - mAnimatableIcon.start(); + try { + mAnimatableIcon.start(); + } catch (Exception ex) { + Log.e(TAG, "Error while running the splash screen animated icon", ex); + animation.cancel(); + } } @Override diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java index 979bf0056b72..bd4869670bec 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java @@ -61,6 +61,7 @@ import android.window.TaskSnapshot; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; +import com.android.launcher3.icons.IconProvider; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.TransactionPool; import com.android.wm.shell.common.annotations.ShellSplashscreenThread; @@ -123,11 +124,11 @@ public class StartingSurfaceDrawer { * @param splashScreenExecutor The thread used to control add and remove starting window. */ public StartingSurfaceDrawer(Context context, ShellExecutor splashScreenExecutor, - TransactionPool pool) { + IconProvider iconProvider, TransactionPool pool) { mContext = context; mDisplayManager = mContext.getSystemService(DisplayManager.class); mSplashScreenExecutor = splashScreenExecutor; - mSplashscreenContentDrawer = new SplashscreenContentDrawer(mContext, pool); + mSplashscreenContentDrawer = new SplashscreenContentDrawer(mContext, iconProvider, pool); mSplashScreenExecutor.execute(() -> mChoreographer = Choreographer.getInstance()); mWindowManagerGlobal = WindowManagerGlobal.getInstance(); mDisplayManager.getDisplay(DEFAULT_DISPLAY); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java index 99644f9493d2..a86e07a5602d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java @@ -43,6 +43,7 @@ import androidx.annotation.BinderThread; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.function.TriConsumer; +import com.android.launcher3.icons.IconProvider; import com.android.wm.shell.common.RemoteCallable; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.TransactionPool; @@ -85,9 +86,11 @@ public class StartingWindowController implements RemoteCallable<StartingWindowCo private final SparseIntArray mTaskBackgroundColors = new SparseIntArray(); public StartingWindowController(Context context, ShellExecutor splashScreenExecutor, - StartingWindowTypeAlgorithm startingWindowTypeAlgorithm, TransactionPool pool) { + StartingWindowTypeAlgorithm startingWindowTypeAlgorithm, IconProvider iconProvider, + TransactionPool pool) { mContext = context; - mStartingSurfaceDrawer = new StartingSurfaceDrawer(context, splashScreenExecutor, pool); + mStartingSurfaceDrawer = new StartingSurfaceDrawer(context, splashScreenExecutor, + iconProvider, pool); mStartingWindowTypeAlgorithm = startingWindowTypeAlgorithm; mSplashScreenExecutor = splashScreenExecutor; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java index 663d6477c3fe..7abda994bb5e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java @@ -70,6 +70,7 @@ import android.view.animation.AlphaAnimation; import android.view.animation.Animation; import android.view.animation.Transformation; import android.window.TransitionInfo; +import android.window.TransitionMetrics; import android.window.TransitionRequestInfo; import android.window.WindowContainerToken; import android.window.WindowContainerTransaction; @@ -362,6 +363,7 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { } } startTransaction.apply(); + TransitionMetrics.getInstance().reportAnimationStart(transition); // run finish now in-case there are no animations onAnimFinish.run(); return true; 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 27201572d3e8..c36983189a71 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 @@ -44,6 +44,7 @@ import android.window.ITransitionPlayer; import android.window.RemoteTransition; import android.window.TransitionFilter; import android.window.TransitionInfo; +import android.window.TransitionMetrics; import android.window.TransitionRequestInfo; import android.window.WindowContainerTransaction; import android.window.WindowContainerTransactionCallback; @@ -192,6 +193,8 @@ public class Transitions implements RemoteCallable<Transitions> { public void register(ShellTaskOrganizer taskOrganizer) { if (mPlayerImpl == null) return; taskOrganizer.registerTransitionPlayer(mPlayerImpl); + // Pre-load the instance. + TransitionMetrics.getInstance(); } /** diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java index 091022a139f3..bc701d0c70bc 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java @@ -131,7 +131,7 @@ public class BubbleDataTest extends ShellTestCase { NotificationListenerService.Ranking ranking = mock(NotificationListenerService.Ranking.class); - when(ranking.visuallyInterruptive()).thenReturn(true); + when(ranking.isTextChanged()).thenReturn(true); mEntryInterruptive = createBubbleEntry(1, "interruptive", "package.d", ranking); mBubbleInterruptive = new Bubble(mEntryInterruptive, mSuppressionListener, null, mMainExecutor); @@ -1014,15 +1014,15 @@ public class BubbleDataTest extends ShellTestCase { } private void sendUpdatedEntryAtTime(BubbleEntry entry, long postTime) { - sendUpdatedEntryAtTime(entry, postTime, true /* visuallyInterruptive */); + sendUpdatedEntryAtTime(entry, postTime, true /* isTextChanged */); } private void sendUpdatedEntryAtTime(BubbleEntry entry, long postTime, - boolean visuallyInterruptive) { + boolean textChanged) { setPostTime(entry, postTime); // BubbleController calls this: Bubble b = mBubbleData.getOrCreateBubble(entry, null /* persistedBubble */); - b.setVisuallyInterruptiveForTest(visuallyInterruptive); + b.setTextChangedForTest(textChanged); // And then this mBubbleData.notificationEntryUpdated(b, false /* suppressFlyout*/, true /* showInShade */); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayLayoutTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayLayoutTest.java index 88e754c58792..0ffa5b35331d 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayLayoutTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayLayoutTest.java @@ -21,9 +21,14 @@ import static android.view.Surface.ROTATION_0; import static android.view.Surface.ROTATION_270; import static android.view.Surface.ROTATION_90; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; + import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import android.content.res.Configuration; import android.content.res.Resources; @@ -35,8 +40,12 @@ import android.view.DisplayInfo; import androidx.test.filters.SmallTest; import com.android.internal.R; +import com.android.internal.policy.SystemBarUtils; +import org.junit.After; +import org.junit.Before; import org.junit.Test; +import org.mockito.MockitoSession; /** * Tests for {@link DisplayLayout}. @@ -46,29 +55,48 @@ import org.junit.Test; */ @SmallTest public class DisplayLayoutTest { + private MockitoSession mMockitoSession; + + @Before + public void setup() { + mMockitoSession = mockitoSession() + .initMocks(this) + .mockStatic(SystemBarUtils.class) + .startMocking(); + } + + @After + public void tearDown() { + mMockitoSession.finishMocking(); + } @Test public void testInsets() { - Resources res = createResources(40, 50, false, 30, 40); + Resources res = createResources(40, 50, false); // Test empty display, no bars or anything DisplayInfo info = createDisplayInfo(1000, 1500, 0, ROTATION_0); DisplayLayout dl = new DisplayLayout(info, res, false, false); + when(SystemBarUtils.getStatusBarHeight(eq(res), any())).thenReturn(40); + dl.recalcInsets(res); assertEquals(new Rect(0, 0, 0, 0), dl.stableInsets()); assertEquals(new Rect(0, 0, 0, 0), dl.nonDecorInsets()); // Test with bars dl = new DisplayLayout(info, res, true, true); + dl.recalcInsets(res); assertEquals(new Rect(0, 40, 0, 50), dl.stableInsets()); assertEquals(new Rect(0, 0, 0, 50), dl.nonDecorInsets()); // Test just cutout info = createDisplayInfo(1000, 1500, 60, ROTATION_0); dl = new DisplayLayout(info, res, false, false); + dl.recalcInsets(res); assertEquals(new Rect(0, 60, 0, 0), dl.stableInsets()); assertEquals(new Rect(0, 60, 0, 0), dl.nonDecorInsets()); // Test with bars and cutout dl = new DisplayLayout(info, res, true, true); + dl.recalcInsets(res); assertEquals(new Rect(0, 60, 0, 50), dl.stableInsets()); assertEquals(new Rect(0, 60, 0, 50), dl.nonDecorInsets()); } @@ -76,27 +104,30 @@ public class DisplayLayoutTest { @Test public void testRotate() { // Basic rotate utility - Resources res = createResources(40, 50, false, 30, 40); + Resources res = createResources(40, 50, false); DisplayInfo info = createDisplayInfo(1000, 1500, 60, ROTATION_0); DisplayLayout dl = new DisplayLayout(info, res, true, true); + when(SystemBarUtils.getStatusBarHeight(eq(res), any())).thenReturn(40); + dl.recalcInsets(res); assertEquals(new Rect(0, 60, 0, 50), dl.stableInsets()); assertEquals(new Rect(0, 60, 0, 50), dl.nonDecorInsets()); // Rotate to 90 + when(SystemBarUtils.getStatusBarHeight(eq(res), any())).thenReturn(30); dl.rotateTo(res, ROTATION_90); assertEquals(new Rect(60, 30, 0, 40), dl.stableInsets()); assertEquals(new Rect(60, 0, 0, 40), dl.nonDecorInsets()); // Rotate with moving navbar - res = createResources(40, 50, true, 30, 40); + res = createResources(40, 50, true); dl = new DisplayLayout(info, res, true, true); + when(SystemBarUtils.getStatusBarHeight(eq(res), any())).thenReturn(30); dl.rotateTo(res, ROTATION_270); assertEquals(new Rect(40, 30, 60, 0), dl.stableInsets()); assertEquals(new Rect(40, 0, 60, 0), dl.nonDecorInsets()); } - private Resources createResources( - int navLand, int navPort, boolean navMoves, int statusLand, int statusPort) { + private Resources createResources(int navLand, int navPort, boolean navMoves) { Configuration cfg = new Configuration(); cfg.uiMode = UI_MODE_TYPE_NORMAL; Resources res = mock(Resources.class); @@ -108,8 +139,6 @@ public class DisplayLayoutTest { doReturn(navPort).when(res).getDimensionPixelSize(R.dimen.navigation_bar_height); doReturn(navLand).when(res).getDimensionPixelSize(R.dimen.navigation_bar_width); doReturn(navMoves).when(res).getBoolean(R.bool.config_navBarCanMove); - doReturn(statusLand).when(res).getDimensionPixelSize(R.dimen.status_bar_height_landscape); - doReturn(statusPort).when(res).getDimensionPixelSize(R.dimen.status_bar_height_portrait); doReturn(cfg).when(res).getConfiguration(); return res; } 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 defa58d7fe93..b4caeb5de4ec 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 @@ -95,13 +95,13 @@ public class SplitLayoutTests extends ShellTestCase { @Test public void testUpdateDivideBounds() { mSplitLayout.updateDivideBounds(anyInt()); - verify(mSplitLayoutHandler).onLayoutChanging(any(SplitLayout.class)); + verify(mSplitLayoutHandler).onLayoutSizeChanging(any(SplitLayout.class)); } @Test public void testSetDividePosition() { mSplitLayout.setDividePosition(anyInt()); - verify(mSplitLayoutHandler).onLayoutChanged(any(SplitLayout.class)); + verify(mSplitLayoutHandler).onLayoutSizeChanged(any(SplitLayout.class)); } @Test diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizerTest.java index 3c124bafc18a..078e2b6cf574 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizerTest.java @@ -48,7 +48,6 @@ import android.window.WindowContainerToken; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; -import com.android.internal.R; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.common.ShellExecutor; @@ -124,6 +123,7 @@ public class HideDisplayCutoutOrganizerTest { @Test public void testEnableHideDisplayCutout() { + doReturn(mFakeStatusBarHeightPortrait).when(mOrganizer).getStatusBarHeight(); mOrganizer.enableHideDisplayCutout(); verify(mOrganizer).registerOrganizer(DisplayAreaOrganizer.FEATURE_HIDE_DISPLAY_CUTOUT); @@ -154,8 +154,7 @@ public class HideDisplayCutoutOrganizerTest { doReturn(mFakeDefaultBounds).when(mOrganizer).getDisplayBoundsOfNaturalOrientation(); doReturn(mFakeDefaultCutoutInsets).when(mOrganizer) .getDisplayCutoutInsetsOfNaturalOrientation(); - mContext.getOrCreateTestableResources().addOverride( - R.dimen.status_bar_height_portrait, mFakeStatusBarHeightPortrait); + doReturn(mFakeStatusBarHeightPortrait).when(mOrganizer).getStatusBarHeight(); doReturn(Surface.ROTATION_0).when(mDisplayLayout).rotation(); mOrganizer.enableHideDisplayCutout(); @@ -173,8 +172,7 @@ public class HideDisplayCutoutOrganizerTest { doReturn(mFakeDefaultBounds).when(mOrganizer).getDisplayBoundsOfNaturalOrientation(); doReturn(mFakeDefaultCutoutInsets).when(mOrganizer) .getDisplayCutoutInsetsOfNaturalOrientation(); - mContext.getOrCreateTestableResources().addOverride( - R.dimen.status_bar_height_landscape, mFakeStatusBarHeightLandscape); + doReturn(mFakeStatusBarHeightLandscape).when(mOrganizer).getStatusBarHeight(); doReturn(Surface.ROTATION_90).when(mDisplayLayout).rotation(); mOrganizer.enableHideDisplayCutout(); @@ -192,8 +190,7 @@ public class HideDisplayCutoutOrganizerTest { doReturn(mFakeDefaultBounds).when(mOrganizer).getDisplayBoundsOfNaturalOrientation(); doReturn(mFakeDefaultCutoutInsets).when(mOrganizer) .getDisplayCutoutInsetsOfNaturalOrientation(); - mContext.getOrCreateTestableResources().addOverride( - R.dimen.status_bar_height_landscape, mFakeStatusBarHeightLandscape); + doReturn(mFakeStatusBarHeightLandscape).when(mOrganizer).getStatusBarHeight(); doReturn(Surface.ROTATION_270).when(mDisplayLayout).rotation(); mOrganizer.enableHideDisplayCutout(); @@ -211,8 +208,7 @@ public class HideDisplayCutoutOrganizerTest { doReturn(mFakeDefaultBounds).when(mOrganizer).getDisplayBoundsOfNaturalOrientation(); doReturn(mFakeDefaultCutoutInsets).when(mOrganizer) .getDisplayCutoutInsetsOfNaturalOrientation(); - mContext.getOrCreateTestableResources().addOverride( - R.dimen.status_bar_height_portrait, mFakeStatusBarHeightPortrait); + doReturn(mFakeStatusBarHeightPortrait).when(mOrganizer).getStatusBarHeight(); mOrganizer.enableHideDisplayCutout(); // disable hide display cutout @@ -230,8 +226,7 @@ public class HideDisplayCutoutOrganizerTest { doReturn(200).when(mDisplayLayout).height(); doReturn(mFakeDefaultCutoutInsets).when(mOrganizer) .getDisplayCutoutInsetsOfNaturalOrientation(); - mContext.getOrCreateTestableResources().addOverride( - R.dimen.status_bar_height_portrait, mFakeStatusBarHeightPortrait); + doReturn(mFakeStatusBarHeightPortrait).when(mOrganizer).getStatusBarHeight(); doReturn(Surface.ROTATION_0).when(mDisplayLayout).rotation(); mOrganizer.enableHideDisplayCutout(); assertThat(mOrganizer.mCurrentDisplayBounds).isEqualTo(new Rect(0, 15, 100, 200)); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/MainStageTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/MainStageTests.java index 12b547a765be..2bcc45e2587d 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/MainStageTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/MainStageTests.java @@ -62,7 +62,8 @@ public class MainStageTests { @Test public void testActiveDeactivate() { - mMainStage.activate(mRootTaskInfo.configuration.windowConfiguration.getBounds(), mWct); + mMainStage.activate(mRootTaskInfo.configuration.windowConfiguration.getBounds(), mWct, + true /* reparent */); assertThat(mMainStage.isActive()).isTrue(); mMainStage.deactivate(mWct); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java index be103863a0f2..05496b059030 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java @@ -316,7 +316,8 @@ public class SplitTransitionTests extends ShellTestCase { mock(SurfaceControl.Transaction.class), mock(SurfaceControl.Transaction.class), mock(Transitions.TransitionFinishCallback.class)); - mMainStage.activate(new Rect(0, 0, 100, 100), new WindowContainerTransaction()); + mMainStage.activate(new Rect(0, 0, 100, 100), new WindowContainerTransaction(), + true /* includingTopTask */); } private boolean containsSplitExit(@NonNull WindowContainerTransaction wct) { diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java index a39d331ca884..cd29220bb96a 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java @@ -18,9 +18,11 @@ package com.android.wm.shell.splitscreen; import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.view.Display.DEFAULT_DISPLAY; + import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__RETURN_HOME; import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_BOTTOM_OR_RIGHT; import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_TOP_OR_LEFT; + import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.clearInvocations; @@ -111,7 +113,8 @@ public class StageCoordinatorTests extends ShellTestCase { mStageCoordinator.moveToSideStage(task, SPLIT_POSITION_BOTTOM_OR_RIGHT); - verify(mMainStage).activate(any(Rect.class), any(WindowContainerTransaction.class)); + verify(mMainStage).activate(any(Rect.class), any(WindowContainerTransaction.class), + eq(true /* includingTopTask */)); verify(mSideStage).addTask(eq(task), any(Rect.class), any(WindowContainerTransaction.class)); } @@ -130,7 +133,7 @@ public class StageCoordinatorTests extends ShellTestCase { mStageCoordinator.setSideStagePosition(SPLIT_POSITION_TOP_OR_LEFT, null); clearInvocations(mMainUnfoldController, mSideUnfoldController); - mStageCoordinator.onLayoutChanged(mSplitLayout); + mStageCoordinator.onLayoutSizeChanged(mSplitLayout); verify(mMainUnfoldController).onLayoutChanged(mBounds2); verify(mSideUnfoldController).onLayoutChanged(mBounds1); @@ -142,7 +145,7 @@ public class StageCoordinatorTests extends ShellTestCase { mStageCoordinator.setSideStagePosition(SPLIT_POSITION_BOTTOM_OR_RIGHT, null); clearInvocations(mMainUnfoldController, mSideUnfoldController); - mStageCoordinator.onLayoutChanged(mSplitLayout); + mStageCoordinator.onLayoutSizeChanged(mSplitLayout); verify(mMainUnfoldController).onLayoutChanged(mBounds1); verify(mSideUnfoldController).onLayoutChanged(mBounds2); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java index a5746a49da2b..3ed72e2c079e 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java @@ -21,6 +21,8 @@ import static android.view.Display.DEFAULT_DISPLAY; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeFalse; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.clearInvocations; @@ -31,6 +33,7 @@ import android.app.ActivityManager; import android.os.SystemProperties; import android.view.SurfaceControl; import android.view.SurfaceSession; +import android.window.WindowContainerTransaction; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; @@ -50,7 +53,7 @@ import org.mockito.MockitoAnnotations; /** * Tests for {@link StageTaskListener} * Build/Install/Run: - * atest WMShellUnitTests:StageTaskListenerTests + * atest WMShellUnitTests:StageTaskListenerTests */ @SmallTest @RunWith(AndroidJUnit4.class) @@ -58,11 +61,16 @@ public final class StageTaskListenerTests { private static final boolean ENABLE_SHELL_TRANSITIONS = SystemProperties.getBoolean("persist.debug.shell_transit", false); - @Mock private ShellTaskOrganizer mTaskOrganizer; - @Mock private StageTaskListener.StageListenerCallbacks mCallbacks; - @Mock private SyncTransactionQueue mSyncQueue; - @Mock private StageTaskUnfoldController mStageTaskUnfoldController; - @Captor private ArgumentCaptor<SyncTransactionQueue.TransactionRunnable> mRunnableCaptor; + @Mock + private ShellTaskOrganizer mTaskOrganizer; + @Mock + private StageTaskListener.StageListenerCallbacks mCallbacks; + @Mock + private SyncTransactionQueue mSyncQueue; + @Mock + private StageTaskUnfoldController mStageTaskUnfoldController; + @Captor + private ArgumentCaptor<SyncTransactionQueue.TransactionRunnable> mRunnableCaptor; private SurfaceSession mSurfaceSession = new SurfaceSession(); private SurfaceControl mSurfaceControl; private ActivityManager.RunningTaskInfo mRootTask; @@ -167,4 +175,18 @@ public final class StageTaskListenerTests { mStageTaskListener.onTaskInfoChanged(childTask); verify(mCallbacks).onNoLongerSupportMultiWindow(); } + + @Test + public void testEvictAllChildren() { + final WindowContainerTransaction wct = new WindowContainerTransaction(); + mStageTaskListener.evictAllChildren(wct); + assertTrue(wct.isEmpty()); + + final ActivityManager.RunningTaskInfo childTask = + new TestRunningTaskInfoBuilder().setParentTaskId(mRootTask.taskId).build(); + mStageTaskListener.onTaskAppeared(childTask, mSurfaceControl); + + mStageTaskListener.evictAllChildren(wct); + assertFalse(wct.isEmpty()); + } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java index e5a8aa043d1a..b866bf9d4192 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java @@ -69,6 +69,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import androidx.test.platform.app.InstrumentationRegistry; +import com.android.launcher3.icons.IconProvider; import com.android.wm.shell.common.HandlerExecutor; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.TransactionPool; @@ -93,6 +94,8 @@ public class StartingSurfaceDrawerTests { @Mock private WindowManager mMockWindowManager; @Mock + private IconProvider mIconProvider; + @Mock private TransactionPool mTransactionPool; private final Handler mTestHandler = new Handler(Looper.getMainLooper()); @@ -105,8 +108,8 @@ public class StartingSurfaceDrawerTests { int mAddWindowForTask = 0; TestStartingSurfaceDrawer(Context context, ShellExecutor splashScreenExecutor, - TransactionPool pool) { - super(context, splashScreenExecutor, pool); + IconProvider iconProvider, TransactionPool pool) { + super(context, splashScreenExecutor, iconProvider, pool); } @Override @@ -156,7 +159,8 @@ public class StartingSurfaceDrawerTests { doNothing().when(mMockWindowManager).addView(any(), any()); mTestExecutor = new HandlerExecutor(mTestHandler); mStartingSurfaceDrawer = spy( - new TestStartingSurfaceDrawer(mTestContext, mTestExecutor, mTransactionPool)); + new TestStartingSurfaceDrawer(mTestContext, mTestExecutor, mIconProvider, + mTransactionPool)); } @Test diff --git a/media/java/android/media/IMediaRouterService.aidl b/media/java/android/media/IMediaRouterService.aidl index 48289ecde9e0..25b582d2fc8d 100644 --- a/media/java/android/media/IMediaRouterService.aidl +++ b/media/java/android/media/IMediaRouterService.aidl @@ -39,6 +39,7 @@ interface IMediaRouterService { MediaRouterClientState getState(IMediaRouterClient client); boolean isPlaybackActive(IMediaRouterClient client); + void setBluetoothA2dpOn(IMediaRouterClient client, boolean on); void setDiscoveryRequest(IMediaRouterClient client, int routeTypes, boolean activeScan); void setSelectedRoute(IMediaRouterClient client, String routeId, boolean explicit); void requestSetVolume(IMediaRouterClient client, String routeId, int volume); diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java index 9bf0db52f66d..028ae2b3487c 100644 --- a/media/java/android/media/MediaFormat.java +++ b/media/java/android/media/MediaFormat.java @@ -683,6 +683,19 @@ public final class MediaFormat { public static final String KEY_CHANNEL_MASK = "channel-mask"; /** + * A key describing the maximum number of channels that can be output by an audio decoder. + * By default, the decoder will output the same number of channels as present in the encoded + * stream, if supported. Set this value to limit the number of output channels, and use + * the downmix information in the stream, if available. + * <p>Values larger than the number of channels in the content to decode behave like the number + * of channels in the content (if applicable), for instance passing 99 for a 5.1 audio stream + * behaves like passing 6. + * <p>This key is only used during decoding. + */ + public static final String KEY_MAX_OUTPUT_CHANNEL_COUNT = + "max-output-channel_count"; + + /** * A key describing the number of frames to trim from the start of the decoded audio stream. * The associated value is an integer. */ diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java index 345d9b27c8a8..748ae52d6c0c 100644 --- a/media/java/android/media/MediaRouter.java +++ b/media/java/android/media/MediaRouter.java @@ -1087,7 +1087,8 @@ public class MediaRouter { && (types & ROUTE_TYPE_LIVE_AUDIO) != 0 && (route.isBluetooth() || route.isDefault())) { try { - sStatic.mAudioService.setBluetoothA2dpOn(route.isBluetooth()); + sStatic.mMediaRouterService.setBluetoothA2dpOn(sStatic.mClient, + route.isBluetooth()); } catch (RemoteException e) { Log.e(TAG, "Error changing Bluetooth A2DP state", e); } diff --git a/packages/PrintSpooler/res/values-pa/strings.xml b/packages/PrintSpooler/res/values-pa/strings.xml index 601fa836902d..ddcec40bd643 100644 --- a/packages/PrintSpooler/res/values-pa/strings.xml +++ b/packages/PrintSpooler/res/values-pa/strings.xml @@ -50,8 +50,8 @@ <string name="search" msgid="5421724265322228497">"ਖੋਜੋ"</string> <string name="all_printers_label" msgid="3178848870161526399">"ਸਾਰੇ ਪ੍ਰਿੰਟਰ"</string> <string name="add_print_service_label" msgid="5356702546188981940">"ਸੇਵਾ ਸ਼ਾਮਲ ਕਰੋ"</string> - <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"ਖੋਜ ਬਾਕਸ ਦਿਖਾਇਆ"</string> - <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"ਖੋਜ ਬਾਕਸ ਲੁਕਾਇਆ"</string> + <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"ਖੋਜ ਬਾਕਸ ਦਿਖਾਇਆ ਗਿਆ"</string> + <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"ਖੋਜ ਬਾਕਸ ਲੁਕਾਇਆ ਗਿਆ"</string> <string name="print_add_printer" msgid="1088656468360653455">"ਪ੍ਰਿੰਟਰ ਸ਼ਾਮਲ ਕਰੋ"</string> <string name="print_select_printer" msgid="7388760939873368698">"ਪ੍ਰਿੰਟਰ ਚੁਣੋ"</string> <string name="print_forget_printer" msgid="5035287497291910766">"ਪ੍ਰਿੰਟਰ ਭੁੱਲੋ"</string> diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml index eafa87bbbf7d..75f7c5e58b32 100644 --- a/packages/SettingsLib/res/values-as/strings.xml +++ b/packages/SettingsLib/res/values-as/strings.xml @@ -73,14 +73,14 @@ <string name="bluetooth_connected_no_a2dp" msgid="8566874395813947092">"সংযোগ কৰা হ’ল (মিডিয়া নাই)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string> <string name="bluetooth_connected_no_map" msgid="3381860077002724689">"সংযোগ কৰা হ’ল (বাৰ্তাত প্ৰৱেশাধিকাৰ নাই)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string> <string name="bluetooth_connected_no_headset_no_a2dp" msgid="2893204819854215433">"সংযোগ কৰা হ’ল (কোনো ফ\'ন বা মিডিয়া নাই)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string> - <string name="bluetooth_connected_battery_level" msgid="5410325759372259950">"সংযোগ কৰা হ’ল, বেটাৰিৰ স্তৰ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string> - <string name="bluetooth_connected_no_headset_battery_level" msgid="2661863370509206428">"সংযোগ কৰা হ’ল (ফ\'ন নাই), বেটাৰিৰ স্তৰ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string> - <string name="bluetooth_connected_no_a2dp_battery_level" msgid="6499078454894324287">"সংযোগ কৰা হ’ল (মিডিয়া নাই), বেটাৰিৰ স্তৰ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string> - <string name="bluetooth_connected_no_headset_no_a2dp_battery_level" msgid="8477440576953067242">"সংযোগ কৰা হ’ল (কোনো ফ\'ন বা মিডিয়া নাই), বেটাৰিৰ স্তৰ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string> - <string name="bluetooth_active_battery_level" msgid="3450745316700494425">"সক্ৰিয়, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> বেটাৰি"</string> - <string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"সক্ৰিয়, L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> বেটাৰি, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> বেটাৰি"</string> + <string name="bluetooth_connected_battery_level" msgid="5410325759372259950">"সংযোগ কৰা হ’ল, বেটাৰীৰ স্তৰ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string> + <string name="bluetooth_connected_no_headset_battery_level" msgid="2661863370509206428">"সংযোগ কৰা হ’ল (ফ\'ন নাই), বেটাৰীৰ স্তৰ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string> + <string name="bluetooth_connected_no_a2dp_battery_level" msgid="6499078454894324287">"সংযোগ কৰা হ’ল (মিডিয়া নাই), বেটাৰীৰ স্তৰ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string> + <string name="bluetooth_connected_no_headset_no_a2dp_battery_level" msgid="8477440576953067242">"সংযোগ কৰা হ’ল (কোনো ফ\'ন বা মিডিয়া নাই), বেটাৰীৰ স্তৰ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string> + <string name="bluetooth_active_battery_level" msgid="3450745316700494425">"সক্ৰিয়, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> বেটাৰী"</string> + <string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"সক্ৰিয়, L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> বেটাৰী, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> বেটাৰী"</string> <string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> বেটাৰী"</string> - <string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> বেটাৰি, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> বেটাৰি"</string> + <string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> বেটাৰী, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> বেটাৰী"</string> <string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"সক্ৰিয়"</string> <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"মিডিয়াৰ অডিঅ’"</string> <string name="bluetooth_profile_headset" msgid="5395952236133499331">"ফ\'ন কলসমূহ"</string> @@ -130,8 +130,8 @@ <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"ব্লুটুথ"</string> <string name="bluetooth_hearingaid_left_pairing_message" msgid="8561855779703533591">"বাওঁফালৰ শ্ৰৱণ যন্ত্ৰটো যোৰ পতোৱা হৈছে…"</string> <string name="bluetooth_hearingaid_right_pairing_message" msgid="2655347721696331048">"সোঁফালৰ শ্ৰৱণ যন্ত্ৰটো যোৰ পতোৱা হৈছে…"</string> - <string name="bluetooth_hearingaid_left_battery_level" msgid="7375621694748104876">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> বেটাৰি বাকী আছে"</string> - <string name="bluetooth_hearingaid_right_battery_level" msgid="1850094448499089312">"সোঁ - বেটাৰি <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> + <string name="bluetooth_hearingaid_left_battery_level" msgid="7375621694748104876">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> বেটাৰী বাকী আছে"</string> + <string name="bluetooth_hearingaid_right_battery_level" msgid="1850094448499089312">"সোঁ - বেটাৰী <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> <string name="accessibility_wifi_off" msgid="1195445715254137155">"ৱাই-ফাই অফ হৈ আছে।"</string> <string name="accessibility_no_wifi" msgid="5297119459491085771">"ৱাইফাই সংযোগ বিচ্ছিন্ন হৈ আছে।"</string> <string name="accessibility_wifi_one_bar" msgid="6025652717281815212">"ৱাই-ফাই এদাল দণ্ড।"</string> @@ -289,7 +289,7 @@ <string name="wifi_unmetered_label" msgid="6174142840934095093">"নিৰিখ অনিৰ্দিষ্ট"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"লগাৰৰ বাফাৰৰ আকাৰ"</string> <string name="select_logd_size_dialog_title" msgid="2105401994681013578">"প্ৰতিটো লগ বাফাৰত ল\'গাৰৰ আকাৰ বাছনি কৰক"</string> - <string name="dev_logpersist_clear_warning_title" msgid="8631859265777337991">"লগাৰৰ স্থায়ী সঞ্চয়াগাৰৰ বস্তুবোৰ মচিবনে?"</string> + <string name="dev_logpersist_clear_warning_title" msgid="8631859265777337991">"লগাৰৰ স্থায়ী ষ্ট’ৰেজৰ বস্তুবোৰ মচিবনে?"</string> <string name="dev_logpersist_clear_warning_message" msgid="6447590867594287413">"পাৰ্ছিছটেণ্ট লগাৰ ব্যৱহাৰ কৰ নিৰীক্ষণ নকৰাৰ সময়ত, আমি আপোনাৰ ডিভাইচত থকা লগাৰ ডেটা নিৱাসীক মচা দৰকাৰ।"</string> <string name="select_logpersist_title" msgid="447071974007104196">"ডিভাইচটোত লগাৰৰ ডেটা নিৰবচ্ছিন্নভাৱে সঞ্চয় কৰক"</string> <string name="select_logpersist_dialog_title" msgid="7745193591195485594">"ডিভাইচত স্থায়ীভাৱে সঞ্চয় কৰিবলৈ লগ বাফাৰবোৰ বাছনি কৰক"</string> @@ -375,7 +375,7 @@ <string name="show_notification_channel_warnings" msgid="3448282400127597331">"জাননী চ্চেনেলৰ সকীয়নিসমূহ দেখুৱাওক"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"কোনো এপে বৈধ চ্চেনেল নোহোৱাকৈ কোনো জাননী প\'ষ্ট কৰিলে স্ক্ৰীনত সকীয়নি প্ৰদৰ্শন হয়"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"বাহ্যিক সঞ্চয়াগাৰত এপক বলেৰে অনুমতি দিয়ক"</string> - <string name="force_allow_on_external_summary" msgid="8525425782530728238">"মেনিফেষ্টৰ মান যিয়েই নহওক, বাহ্যিক সঞ্চয়াগাৰত লিখিবলৈ যিকোনো এপক উপযুক্ত কৰি তোলে"</string> + <string name="force_allow_on_external_summary" msgid="8525425782530728238">"মেনিফেষ্টৰ মান যিয়েই নহওক, বাহ্যিক ষ্ট’ৰেজত লিখিবলৈ যিকোনো এপক উপযুক্ত কৰি তোলে"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"বলেৰে কাৰ্যকলাপসমূহৰ আকাৰ সলনি কৰিব পৰা কৰক"</string> <string name="force_resizable_activities_summary" msgid="2490382056981583062">"মেনিফেষ্টৰ মান যিয়েই নহওক, মাল্টি-ৱিণ্ডৰ বাবে সকলো কাৰ্যকলাপৰ আকাৰ সলনি কৰিব পৰা কৰক।"</string> <string name="enable_freeform_support" msgid="7599125687603914253">"ফ্ৰিফৰ্ম ৱিণ্ড\'জ সক্ষম কৰক"</string> diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml index 127f571a5529..940e5d3cac1b 100644 --- a/packages/SettingsLib/res/values-pa/strings.xml +++ b/packages/SettingsLib/res/values-pa/strings.xml @@ -164,11 +164,11 @@ <string name="tts_default_lang_title" msgid="4698933575028098940">"ਭਾਸ਼ਾ"</string> <string name="tts_lang_use_system" msgid="6312945299804012406">"ਸਿਸਟਮ ਭਾਸ਼ਾ ਵਰਤੋ"</string> <string name="tts_lang_not_selected" msgid="7927823081096056147">"ਭਾਸ਼ਾ ਨਹੀਂ ਚੁਣੀ"</string> - <string name="tts_default_lang_summary" msgid="9042620014800063470">"ਬੋਲੇ ਗਏ ਟੈਕਸਟ ਲਈ ਭਾਸ਼ਾ-ਵਿਸ਼ੇਸ਼ ਵੌਇਸ ਸੈਟ ਕਰਦਾ ਹੈ"</string> + <string name="tts_default_lang_summary" msgid="9042620014800063470">"ਬੋਲੀ ਗਈ ਲਿਖਤ ਲਈ ਭਾਸ਼ਾ-ਵਿਸ਼ੇਸ਼ ਅਵਾਜ਼ ਸੈੱਟ ਕਰਦਾ ਹੈ"</string> <string name="tts_play_example_title" msgid="1599468547216481684">"ਇੱਕ ਉਦਾਹਰਨ ਲਈ ਸੁਣੋ"</string> <string name="tts_play_example_summary" msgid="634044730710636383">"ਸਪੀਚ ਸਿੰਥੈਸਿਸ ਦਾ ਇੱਕ ਛੋਟਾ ਪ੍ਰਦਰਸ਼ਨ ਪਲੇ ਕਰੋ"</string> - <string name="tts_install_data_title" msgid="1829942496472751703">"ਵੌਇਸ ਡਾਟਾ ਸਥਾਪਤ ਕਰੋ"</string> - <string name="tts_install_data_summary" msgid="3608874324992243851">"ਸਪੀਚ ਸਿੰਥੈਸਿਸ ਲਈ ਲੋੜੀਂਦਾ ਵੌਇਸ ਡਾਟਾ ਸਥਾਪਤ ਕਰੋ"</string> + <string name="tts_install_data_title" msgid="1829942496472751703">"ਅਵਾਜ਼ੀ ਡਾਟਾ ਸਥਾਪਤ ਕਰੋ"</string> + <string name="tts_install_data_summary" msgid="3608874324992243851">"ਸਪੀਚ ਸਿੰਥੈਸਿਸ ਲਈ ਲੋੜੀਂਦਾ ਅਵਾਜ਼ੀ ਡਾਟਾ ਸਥਾਪਤ ਕਰੋ"</string> <string name="tts_engine_security_warning" msgid="3372432853837988146">"ਇਹ ਸਪੀਚ ਸਿੰਥੈਸਿਸ ਇੰਜਣ ਉਹ ਸਭ ਲਿਖਤ ਇਕੱਤਰ ਕਰਨ ਵਿੱਚ ਸਮਰੱਥ ਹੋ ਸਕਦਾ ਹੈ, ਜੋ ਬੋਲਿਆ ਜਾਏਗਾ, ਨਿੱਜੀ ਡਾਟਾ ਸਮੇਤ ਜਿਵੇਂ ਪਾਸਵਰਡ ਅਤੇ ਕ੍ਰੈਡਿਟ ਕਾਰਡ ਨੰਬਰ। ਇਹ <xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g> ਇੰਜਣ ਤੋਂ ਆਉਂਦਾ ਹੈ। ਕੀ ਇਸ ਸਪੀਚ ਸਿੰਥੈਸਿਸ ਇੰਜਣ ਦੀ ਵਰਤੋਂ ਨੂੰ ਚਾਲੂ ਕਰਨਾ ਹੈੈ?"</string> <string name="tts_engine_network_required" msgid="8722087649733906851">"ਇਸ ਭਾਸ਼ਾ ਲਈ ਲਿਖਤ ਤੋਂ ਬੋਲੀ ਆਊਟਪੁੱਟ ਲਈ ਇੱਕ ਚਾਲੂ ਨੈੱਟਵਰਕ ਕਨੈਕਸ਼ਨ ਦੀ ਲੋੜ ਹੈ।"</string> <string name="tts_default_sample_string" msgid="6388016028292967973">"ਇਹ ਸਪੀਚ ਸਿੰਥੈਸਿਸ ਦਾ ਇੱਕ ਉਦਾਹਰਨ ਹੈ"</string> diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java index fe92e2664eda..7beb82457e18 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java @@ -106,6 +106,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> private boolean mIsA2dpProfileConnectedFail = false; private boolean mIsHeadsetProfileConnectedFail = false; private boolean mIsHearingAidProfileConnectedFail = false; + private boolean mUnpairing = false; // Group second device for Hearing Aid private CachedBluetoothDevice mSubDevice; @VisibleForTesting @@ -402,6 +403,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> if (state != BluetoothDevice.BOND_NONE) { final BluetoothDevice dev = mDevice; if (dev != null) { + mUnpairing = true; final boolean successful = dev.removeBond(); if (successful) { releaseLruCache(); @@ -1243,4 +1245,8 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> void releaseLruCache() { mDrawableCache.evictAll(); } + + boolean getUnpairing() { + return mUnpairing; + } } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java index 20ece69d7281..818f5ca33ebf 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java @@ -180,6 +180,9 @@ public class HearingAidDeviceManager { break; case BluetoothProfile.STATE_DISCONNECTED: mainDevice = findMainDevice(cachedDevice); + if (cachedDevice.getUnpairing()) { + return true; + } if (mainDevice != null) { // When main device exists, receiving sub device disconnection // To update main device UI diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java index 22001c9c925a..c40b7b7d88af 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java @@ -479,9 +479,9 @@ public class LocalMediaManager implements BluetoothCallback { @Override public void onDeviceListAdded(List<MediaDevice> devices) { synchronized (mMediaDevicesLock) { + Collections.sort(devices, COMPARATOR); mMediaDevices.clear(); mMediaDevices.addAll(devices); - Collections.sort(devices, COMPARATOR); // Add disconnected bluetooth devices only when phone output device is available. for (MediaDevice device : devices) { final int type = device.getDeviceType(); diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 9de1c5ea1a3d..58e3d398553c 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -183,6 +183,9 @@ <permission android:name="com.android.systemui.permission.PLUGIN" android:protectionLevel="signature" /> + <permission android:name="com.android.systemui.permission.FLAGS" + android:protectionLevel="signature" /> + <!-- Adding Quick Settings tiles --> <uses-permission android:name="android.permission.BIND_QUICK_SETTINGS_TILE" /> diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt index f7e0d588407f..3ccf5e4fbdd0 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt @@ -209,8 +209,13 @@ open class GhostedViewLaunchAnimatorController( val heightRatio = state.height.toFloat() / ghostedViewState.height val scale = min(widthRatio, heightRatio) + if (ghostedView.parent is ViewGroup) { + // Recalculate the matrix in case the ghosted view moved. We ensure that the ghosted + // view is still attached to a ViewGroup, otherwise calculateMatrix will throw. + GhostView.calculateMatrix(ghostedView, launchContainer, ghostViewMatrix) + } + launchContainer.getLocationOnScreen(launchContainerLocation) - GhostView.calculateMatrix(ghostedView, launchContainer, ghostViewMatrix) ghostViewMatrix.postScale( scale, scale, ghostedViewState.centerX - launchContainerLocation[0], diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java b/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java index a3d924fbad60..80634832acd9 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java @@ -197,26 +197,6 @@ public class Interpolators { return MathUtils.max(0.0f, (float) (1.0f - Math.exp(-4 * progress))); } - /** - * Interpolate alpha for notifications background scrim during shade expansion. - * @param fraction Shade expansion fraction - * @param forUiContent If we want the alpha of the scrims, or ui that's on top of them. - */ - public static float getNotificationScrimAlpha(float fraction, boolean forUiContent) { - if (forUiContent) { - fraction = MathUtils.constrainedMap(0f, 1f, 0.3f, 1f, fraction); - } else { - fraction = MathUtils.constrainedMap(0f, 1f, 0f, 0.5f, fraction); - } - fraction = fraction * 1.2f - 0.2f; - if (fraction <= 0) { - return 0; - } else { - final float oneMinusFrac = 1f - fraction; - return (float) (1f - 0.5f * (1f - Math.cos(3.14159f * oneMinusFrac * oneMinusFrac))); - } - } - // Create the default emphasized interpolator private static PathInterpolator createEmphasizedInterpolator() { Path path = new Path(); diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ShadeInterpolation.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ShadeInterpolation.kt new file mode 100644 index 000000000000..0ee2bfea55c5 --- /dev/null +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ShadeInterpolation.kt @@ -0,0 +1,37 @@ +package com.android.systemui.animation + +import android.util.MathUtils + +object ShadeInterpolation { + + /** + * Interpolate alpha for notification background scrim during shade expansion. + * @param fraction Shade expansion fraction + */ + @JvmStatic + fun getNotificationScrimAlpha(fraction: Float): Float { + val mappedFraction = MathUtils.constrainedMap(0f, 1f, 0f, 0.5f, fraction) + return interpolateEaseInOut(mappedFraction) + } + + /** + * Interpolate alpha for shade content during shade expansion. + * @param fraction Shade expansion fraction + */ + @JvmStatic + fun getContentAlpha(fraction: Float): Float { + val mappedFraction = MathUtils.constrainedMap(0f, 1f, 0.3f, 1f, fraction) + return interpolateEaseInOut(mappedFraction) + } + + private fun interpolateEaseInOut(fraction: Float): Float { + val mappedFraction = fraction * 1.2f - 0.2f + return if (mappedFraction <= 0) { + 0f + } else { + val oneMinusFrac = 1f - mappedFraction + (1f - 0.5f * (1f - Math.cos((3.14159f * oneMinusFrac * oneMinusFrac).toDouble()))) + .toFloat() + } + } +}
\ No newline at end of file diff --git a/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt b/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt index e026012f9de8..1844288796cc 100644 --- a/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt +++ b/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt @@ -249,6 +249,9 @@ public class ColorScheme(@ColorInt seed: Int, val darkTheme: Boolean) { val population = populationByColor[entry.key]!! val cam = camByColor[entry.key]!! val hue = cam.hue.roundToInt() % 360 + if (cam.chroma <= MIN_CHROMA) { + continue + } huePopulation[hue] = huePopulation[hue] + population } diff --git a/packages/SystemUI/plugin/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/plugin/src/com/android/systemui/flags/Flags.java index d5b9243ebe86..3761d42ae98c 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/flags/Flags.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/flags/Flags.java @@ -16,8 +16,114 @@ package com.android.systemui.flags; +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; + /** * List of {@link Flag} objects for use in SystemUI. + * + * Flag Ids are integers. + * Ids must be unique. This is enforced in a unit test. + * Ids need not be sequential. Flags can "claim" a chunk of ids for flags in related featurs with + * a comment. This is purely for organizational purposes. + * + * On public release builds, flags will always return their default value. There is no way to + * change their value on release builds. + * + * See {@link FeatureFlagManager} for instructions on flipping the flags via adb. */ public class Flags { + public static final BooleanFlag TEAMFOOD = new BooleanFlag(1, false); + + /***************************************/ + // 100 - notification + public static final BooleanFlag NEW_NOTIFICATION_PIPELINE = + new BooleanFlag(100, true); + + public static final BooleanFlag NEW_NOTIFICATION_PIPELINE_RENDERING = + new BooleanFlag(101, false); + + public static final BooleanFlag NOTIFICATION_UPDATES = + new BooleanFlag(102, true); + + + /***************************************/ + // 200 - keyguard/lockscreen + public static final BooleanFlag KEYGUARD_LAYOUT = + new BooleanFlag(200, true); + + public static final BooleanFlag LOCKSCREEN_ANIMATIONS = + new BooleanFlag(201, true); + + public static final BooleanFlag NEW_UNLOCK_SWIPE_ANIMATION = + new BooleanFlag(202, true); + + /***************************************/ + // 300 - power menu + public static final BooleanFlag POWER_MENU_LITE = + new BooleanFlag(300, true); + + /***************************************/ + // 400 - smartspace + public static final BooleanFlag SMARTSPACE_DEDUPING = + new BooleanFlag(400, true); + + public static final BooleanFlag SMARTSPACE_SHARED_ELEMENT_TRANSITION_ENABLED = + new BooleanFlag(401, false); + + /***************************************/ + // 500 - quick settings + public static final BooleanFlag NEW_USER_SWITCHER = + new BooleanFlag(500, true); + + /***************************************/ + // 600- status bar + public static final BooleanFlag COMBINED_STATUS_BAR_SIGNAL_ICONS = + new BooleanFlag(501, false); + + /***************************************/ + // 700 - dialer/calls + public static final BooleanFlag ONGOING_CALL_STATUS_BAR_CHIP = + new BooleanFlag(600, true); + + public static final BooleanFlag ONGOING_CALL_IN_IMMERSIVE = + new BooleanFlag(601, true); + + public static final BooleanFlag ONGOING_CALL_IN_IMMERSIVE_CHIP_TAP = + new BooleanFlag(602, true); + + // Pay no attention to the reflection behind the curtain. + // ========================== Curtain ========================== + // | | + // | . . . . . . . . . . . . . . . . . . . | + private static Map<Integer, Flag<?>> sFlagMap; + static Map<Integer, Flag<?>> collectFlags() { + if (sFlagMap != null) { + return sFlagMap; + } + Map<Integer, Flag<?>> flags = new HashMap<>(); + + Field[] fields = Flags.class.getFields(); + + for (Field field : fields) { + Class<?> t = field.getType(); + if (Flag.class.isAssignableFrom(t)) { + try { + Flag<?> flag = (Flag<?>) field.get(null); + flags.put(flag.getId(), flag); + } catch (IllegalAccessException e) { + // no-op + } + } + } + + sFlagMap = flags; + + return sFlagMap; + } + // | . . . . . . . . . . . . . . . . . . . | + // | | + // \_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/ + } diff --git a/packages/SystemUI/proguard.flags b/packages/SystemUI/proguard.flags index 4adb54686a89..61147281da6f 100644 --- a/packages/SystemUI/proguard.flags +++ b/packages/SystemUI/proguard.flags @@ -37,9 +37,6 @@ -keep class com.android.systemui.fragments.FragmentService$FragmentCreator { *; } --keep class com.android.systemui.util.InjectionInflationController$ViewInstanceCreator { - *; -} -keep class androidx.core.app.CoreComponentFactory -keep public class * extends com.android.systemui.SystemUI { diff --git a/packages/SystemUI/res/anim/fp_to_unlock.xml b/packages/SystemUI/res-keyguard/drawable/fp_to_unlock.xml index a5f75b6726c8..b93ccc6ac106 100644 --- a/packages/SystemUI/res/anim/fp_to_unlock.xml +++ b/packages/SystemUI/res-keyguard/drawable/fp_to_unlock.xml @@ -19,15 +19,15 @@ <group android:name="_R_G"> <group android:name="_R_G_L_1_G_N_7_T_0" android:translateX="-27" android:translateY="-17.5"> <group android:name="_R_G_L_1_G" android:translateX="30.75" android:translateY="25.75"> - <path android:name="_R_G_L_1_G_D_0_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:pathData=" M27.52 38.98 C26.49,39.95 25.29,40.73 23.98,41.29 C23.17,41.65 22.31,41.91 21.41,42.07 C20.74,42.19 20.05,42.25 19.34,42.25 C18.44,42.25 17.56,42.15 16.72,41.96 C15.93,41.77 15.16,41.51 14.43,41.18 C13.23,40.63 12.13,39.88 11.16,38.98 " /> - <path android:name="_R_G_L_1_G_D_1_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:pathData=" M8.64 34.07 C7.89,31.97 7.89,29.85 7.89,29.85 C7.89,24.05 12.81,19.34 19.34,19.34 C25.87,19.34 30.8,24.05 30.8,29.85 C30.8,29.85 30.8,30.16 30.8,30.16 C30.8,32.32 29.04,34.07 26.89,34.07 C25.28,34.07 23.86,33.1 23.27,31.61 C23.27,31.61 21.96,28.34 21.96,28.34 C21.37,26.85 19.93,25.89 18.34,25.89 C16.18,25.89 14.43,27.64 14.43,29.8 C14.43,31.42 14.87,32.99 15.68,34.36 C16.22,35.26 16.93,36.08 17.77,36.75 C17.77,36.75 18.52,37.34 18.52,37.34 " /> - <path android:name="_R_G_L_1_G_D_2_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:pathData=" M6.25 19.34 C7.48,17.3 9.46,15.58 11.9,14.42 C12.93,13.94 14.03,13.55 15.2,13.27 C16.51,12.96 17.9,12.8 19.34,12.8 C20.77,12.8 22.14,12.96 23.45,13.26 C24.9,13.6 26.26,14.12 27.48,14.78 C29.6,15.92 31.32,17.5 32.43,19.34 " /> - <path android:name="_R_G_L_1_G_D_3_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:pathData=" M9.52 8.7 C10.98,7.91 12.58,7.28 14.28,6.86 C15.89,6.46 17.58,6.25 19.34,6.25 C21.06,6.25 22.72,6.45 24.3,6.83 C26.04,7.25 27.67,7.89 29.16,8.7 " /> + <path android:name="_R_G_L_1_G_D_0_P_0" android:strokeColor="#FF000000" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:pathData=" M27.52 38.98 C26.49,39.95 25.29,40.73 23.98,41.29 C23.17,41.65 22.31,41.91 21.41,42.07 C20.74,42.19 20.05,42.25 19.34,42.25 C18.44,42.25 17.56,42.15 16.72,41.96 C15.93,41.77 15.16,41.51 14.43,41.18 C13.23,40.63 12.13,39.88 11.16,38.98 " /> + <path android:name="_R_G_L_1_G_D_1_P_0" android:strokeColor="#FF000000" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:pathData=" M8.64 34.07 C7.89,31.97 7.89,29.85 7.89,29.85 C7.89,24.05 12.81,19.34 19.34,19.34 C25.87,19.34 30.8,24.05 30.8,29.85 C30.8,29.85 30.8,30.16 30.8,30.16 C30.8,32.32 29.04,34.07 26.89,34.07 C25.28,34.07 23.86,33.1 23.27,31.61 C23.27,31.61 21.96,28.34 21.96,28.34 C21.37,26.85 19.93,25.89 18.34,25.89 C16.18,25.89 14.43,27.64 14.43,29.8 C14.43,31.42 14.87,32.99 15.68,34.36 C16.22,35.26 16.93,36.08 17.77,36.75 C17.77,36.75 18.52,37.34 18.52,37.34 " /> + <path android:name="_R_G_L_1_G_D_2_P_0" android:strokeColor="#FF000000" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:pathData=" M6.25 19.34 C7.48,17.3 9.46,15.58 11.9,14.42 C12.93,13.94 14.03,13.55 15.2,13.27 C16.51,12.96 17.9,12.8 19.34,12.8 C20.77,12.8 22.14,12.96 23.45,13.26 C24.9,13.6 26.26,14.12 27.48,14.78 C29.6,15.92 31.32,17.5 32.43,19.34 " /> + <path android:name="_R_G_L_1_G_D_3_P_0" android:strokeColor="#FF000000" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:pathData=" M9.52 8.7 C10.98,7.91 12.58,7.28 14.28,6.86 C15.89,6.46 17.58,6.25 19.34,6.25 C21.06,6.25 22.72,6.45 24.3,6.83 C26.04,7.25 27.67,7.89 29.16,8.7 " /> </group> </group> <group android:name="_R_G_L_0_G_N_7_T_0" android:translateX="-27" android:translateY="-17.5"> <group android:name="_R_G_L_0_G" android:translateX="47.357" android:translateY="53.25" android:pivotX="2.75" android:pivotY="2.75" android:scaleX="1.41866" android:scaleY="1.41866"> - <path android:name="_R_G_L_0_G_D_0_P_0" android:fillColor="#b7f29f" android:fillAlpha="0" android:fillType="nonZero" android:pathData=" M2.75 5.25 C4.13,5.25 5.25,4.13 5.25,2.75 C5.25,1.37 4.13,0.25 2.75,0.25 C1.37,0.25 0.25,1.37 0.25,2.75 C0.25,4.13 1.37,5.25 2.75,5.25c " /> + <path android:name="_R_G_L_0_G_D_0_P_0" android:fillColor="#FF000000" android:fillAlpha="0" android:fillType="nonZero" android:pathData=" M2.75 5.25 C4.13,5.25 5.25,4.13 5.25,2.75 C5.25,1.37 4.13,0.25 2.75,0.25 C1.37,0.25 0.25,1.37 0.25,2.75 C0.25,4.13 1.37,5.25 2.75,5.25c " /> </group> </group> </group> diff --git a/packages/SystemUI/res-keyguard/drawable/ic_fingerprint.xml b/packages/SystemUI/res-keyguard/drawable/ic_fingerprint.xml new file mode 100644 index 000000000000..2063d21bb5d6 --- /dev/null +++ b/packages/SystemUI/res-keyguard/drawable/ic_fingerprint.xml @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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 + --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="65dp" + android:width="46dp" + android:viewportHeight="65" + android:viewportWidth="46"> + <group android:name="_R_G_L_0_G" android:translateX="3.75" android:translateY="8.25"> + <path + android:strokeColor="#FF000000" + android:strokeLineCap="round" + android:strokeLineJoin="round" + android:strokeWidth="2.5" + android:pathData="M27.52 38.98 C26.49,39.95 25.29,40.73 23.98,41.29 C23.17,41.65 22.31,41.91 21.41,42.07 C20.74,42.19 20.05,42.25 19.34,42.25 C18.44,42.25 17.56,42.15 16.72,41.96 C15.93,41.77 15.16,41.51 14.43,41.18 C13.23,40.63 12.13,39.88 11.16,38.98 " /> + <path + android:strokeColor="#FF000000" + android:strokeLineCap="round" + android:strokeLineJoin="round" + android:strokeWidth="2.5" + android:pathData="M8.64 34.07 C7.89,31.97 7.89,29.85 7.89,29.85 C7.89,24.05 12.81,19.34 19.34,19.34 C25.87,19.34 30.8,24.05 30.8,29.85 C30.8,29.85 30.8,30.16 30.8,30.16 C30.8,32.32 29.04,34.07 26.89,34.07 C25.28,34.07 23.86,33.1 23.27,31.61 C23.27,31.61 21.96,28.34 21.96,28.34 C21.37,26.85 19.93,25.89 18.34,25.89 C16.18,25.89 14.43,27.64 14.43,29.8 C14.43,31.42 14.87,32.99 15.68,34.36 C16.22,35.26 16.93,36.08 17.77,36.75 C17.77,36.75 18.52,37.34 18.52,37.34 " /> + <path + android:strokeColor="#FF000000" + android:strokeLineCap="round" + android:strokeLineJoin="round" + android:strokeWidth="2.5" + android:pathData="M6.25 19.34 C7.48,17.3 9.46,15.58 11.9,14.42 C12.93,13.94 14.03,13.55 15.2,13.27 C16.51,12.96 17.9,12.8 19.34,12.8 C20.77,12.8 22.14,12.96 23.45,13.26 C24.9,13.6 26.26,14.12 27.48,14.78 C29.6,15.92 31.32,17.5 32.43,19.34 " /> + <path + android:strokeColor="#FF000000" + android:strokeLineCap="round" + android:strokeLineJoin="round" + android:strokeWidth="2.5" + android:pathData="M9.52 8.7 C10.98,7.91 12.58,7.28 14.28,6.86 C15.89,6.46 17.58,6.25 19.34,6.25 C21.06,6.25 22.72,6.45 24.3,6.83 C26.04,7.25 27.67,7.89 29.16,8.7 " /> + </group> +</vector>
\ No newline at end of file diff --git a/packages/SystemUI/res-keyguard/drawable/ic_lock.xml b/packages/SystemUI/res-keyguard/drawable/ic_lock.xml new file mode 100644 index 000000000000..14a8d0bdf8e8 --- /dev/null +++ b/packages/SystemUI/res-keyguard/drawable/ic_lock.xml @@ -0,0 +1,95 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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 + --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="65dp" + android:width="46dp" + android:viewportHeight="65" + android:viewportWidth="46"> + <group android:name="_R_G"> + <group android:name="_R_G_L_2_G_N_10_N_11_T_0" + android:translateX="-27.5" + android:translateY="-17.5"> + <group android:name="_R_G_L_2_G_N_10_T_1" + android:translateX="50.25" + android:translateY="61"> + <group android:name="_R_G_L_2_G_N_10_T_0" + android:translateX="-13.75" + android:translateY="-7.5"> + <group android:name="_R_G_L_2_G" + android:translateX="-0.375" + android:translateY="-22.375"> + <path android:name="_R_G_L_2_G_D_0_P_0" + android:strokeColor="#FF000000" + android:strokeLineCap="round" + android:strokeLineJoin="round" + android:strokeWidth="2" + android:strokeAlpha="1" + android:pathData=" M4.75 15 C4.75,15 23.25,15 23.25,15 C24.35,15 25.25,15.9 25.25,17 C25.25,17 25.25,33 25.25,33 C25.25,34.1 24.35,35 23.25,35 C23.25,35 4.75,35 4.75,35 C3.65,35 2.75,34.1 2.75,33 C2.75,33 2.75,17 2.75,17 C2.75,15.9 3.65,15 4.75,15c "/> + </group> + </group> + </group> + </group> + <group android:name="_R_G_L_1_G_N_10_N_11_T_0" + android:translateX="-27.5" + android:translateY="-17.5"> + <group android:name="_R_G_L_1_G_N_10_T_1" + android:translateX="50.25" + android:translateY="61"> + <group android:name="_R_G_L_1_G_N_10_T_0" + android:translateX="-13.75" + android:translateY="-7.5"> + <group android:name="_R_G_L_1_G" + android:translateX="5" + android:translateY="-22.5"> + <path android:name="_R_G_L_1_G_D_0_P_0" + android:strokeColor="#FF000000" + android:strokeLineCap="round" + android:strokeLineJoin="round" + android:strokeWidth="2" + android:strokeAlpha="1" + android:pathData=" M2.5 15 C2.5,15 2.5,8.61 2.5,8.61 C2.5,5.24 5.3,2.5 8.75,2.5 C12.2,2.5 15,5.24 15,8.61 C15,8.61 15,15 15,15 "/> + </group> + </group> + </group> + </group> + <group android:name="_R_G_L_0_G_N_10_N_11_T_0" + android:translateX="-27.5" + android:translateY="-17.5"> + <group android:name="_R_G_L_0_G_N_10_T_1" + android:translateX="50.25" + android:translateY="61"> + <group android:name="_R_G_L_0_G_N_10_T_0" + android:translateX="-13.75" + android:translateY="-7.5"> + <group android:name="_R_G_L_0_G" + android:translateX="11" + android:translateY="-0.25" + android:pivotX="2.75" + android:pivotY="2.75" + android:scaleX="1" + android:scaleY="1"> + <path android:name="_R_G_L_0_G_D_0_P_0" + android:fillColor="#FF000000" + android:fillAlpha="1" + android:fillType="nonZero" + android:pathData=" M2.75 5.25 C4.13,5.25 5.25,4.13 5.25,2.75 C5.25,1.37 4.13,0.25 2.75,0.25 C1.37,0.25 0.25,1.37 0.25,2.75 C0.25,4.13 1.37,5.25 2.75,5.25c "/> + </group> + </group> + </group> + </group> + </group> +</vector> diff --git a/packages/SystemUI/res-keyguard/drawable/ic_lock_aod.xml b/packages/SystemUI/res-keyguard/drawable/ic_lock_aod.xml new file mode 100644 index 000000000000..cdae306cfc26 --- /dev/null +++ b/packages/SystemUI/res-keyguard/drawable/ic_lock_aod.xml @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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 + --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="65dp" + android:width="46dp" + android:viewportHeight="65" + android:viewportWidth="46"> + <group android:name="_R_G_L_2_G" android:translateX="23" android:translateY="32.125"> + <path + android:fillColor="#FF000000" + android:fillAlpha="1" + android:fillType="nonZero" + android:pathData=" M0 6.13 C0.97,6.13 1.75,5.34 1.75,4.38 C1.75,3.41 0.97,2.63 0,2.63 C-0.97,2.63 -1.75,3.41 -1.75,4.38 C-1.75,5.34 -0.97,6.13 0,6.13c " /> + <path + android:strokeColor="#FF000000" + android:strokeLineCap="round" + android:strokeLineJoin="round" + android:strokeWidth="1.5" + android:pathData=" M7.88 -0.62 C7.88,-0.62 7.88,9.38 7.88,9.38 C7.88,10.48 6.98,11.38 5.88,11.38 C5.88,11.38 -5.87,11.38 -5.87,11.38 C-6.98,11.38 -7.87,10.48 -7.87,9.38 C-7.87,9.38 -7.87,-0.62 -7.87,-0.62 C-7.87,-1.73 -6.98,-2.62 -5.87,-2.62 C-5.87,-2.62 5.88,-2.62 5.88,-2.62 C6.98,-2.62 7.88,-1.73 7.88,-0.62c " /> + <path + android:strokeColor="#FF000000" + android:strokeLineCap="round" + android:strokeLineJoin="round" + android:strokeWidth="1.5" + android:pathData=" M4.38 -2.62 C4.38,-2.62 4.38,-7.1 4.38,-7.1 C4.38,-9.46 2.42,-11.37 0,-11.37 C-2.42,-11.37 -4.37,-9.46 -4.37,-7.1 C-4.37,-7.1 -4.37,-2.62 -4.37,-2.62 " /> + </group> +</vector>
\ No newline at end of file diff --git a/packages/SystemUI/res-keyguard/drawable/ic_unlocked.xml b/packages/SystemUI/res-keyguard/drawable/ic_unlocked.xml new file mode 100644 index 000000000000..54242781cd73 --- /dev/null +++ b/packages/SystemUI/res-keyguard/drawable/ic_unlocked.xml @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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 + --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="65dp" + android:width="46dp" + android:viewportHeight="65" + android:viewportWidth="46"> + <group android:translateX="8.625" + android:translateY="13.625"> + <path + android:strokeColor="#FF000000" + android:strokeLineCap="round" + android:strokeLineJoin="round" + android:strokeWidth="2.5" + android:pathData="M4.75 15 C4.75,15 23.25,15 23.25,15 C24.35,15 25.25,15.9 25.25,17 C25.25,17 25.25,33 25.25,33 C25.25,34.1 24.35,35 23.25,35 C23.25,35 4.75,35 4.75,35 C3.65,35 2.75,34.1 2.75,33 C2.75,33 2.75,17 2.75,17 C2.75,15.9 3.65,15 4.75,15c "/> + </group> + <group android:translateX="14" + android:translateY="13.5"> + <path + android:strokeColor="#FF000000" + android:strokeLineCap="round" + android:strokeLineJoin="round" + android:strokeWidth="2.5" + android:pathData="M27.19 14.81 C27.19,14.81 27.19,8.3 27.19,8.3 C27.19,4.92 24.44,2.88 21.19,2.75 C17.74,2.62 15,4.74 15,8.11 C15,8.11 15,15 15,15 "/> + </group> + <group android:translateX="20" + android:translateY="35.75"> + <path + android:fillColor="#FF000000" + android:fillAlpha="1" + android:fillType="nonZero" + android:pathData=" M2.75 5.25 C4.13,5.25 5.25,4.13 5.25,2.75 C5.25,1.37 4.13,0.25 2.75,0.25 C1.37,0.25 0.25,1.37 0.25,2.75 C0.25,4.13 1.37,5.25 2.75,5.25c "/> + </group> +</vector> diff --git a/packages/SystemUI/res-keyguard/drawable/lock_aod_to_ls.xml b/packages/SystemUI/res-keyguard/drawable/lock_aod_to_ls.xml new file mode 100644 index 000000000000..d35f69589c39 --- /dev/null +++ b/packages/SystemUI/res-keyguard/drawable/lock_aod_to_ls.xml @@ -0,0 +1,151 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- 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. +--> +<animated-vector xmlns:aapt="http://schemas.android.com/aapt" + xmlns:android="http://schemas.android.com/apk/res/android"> + <aapt:attr name="android:drawable"> + <vector android:height="65dp" + android:width="46dp" + android:viewportHeight="65" + android:viewportWidth="46"> + <group android:name="_R_G"> + <group android:name="_R_G_L_2_G" + android:translateX="23" + android:translateY="32.125"> + <path android:name="_R_G_L_2_G_D_0_P_0" + android:fillColor="#FF000000" + android:fillAlpha="1" + android:fillType="nonZero" + android:pathData=" M0 6.13 C0.97,6.13 1.75,5.34 1.75,4.38 C1.75,3.41 0.97,2.63 0,2.63 C-0.97,2.63 -1.75,3.41 -1.75,4.38 C-1.75,5.34 -0.97,6.13 0,6.13c "/> + </group> + <group android:name="_R_G_L_1_G" + android:translateX="23" + android:translateY="32.125"> + <path android:name="_R_G_L_1_G_D_0_P_0" + android:strokeColor="#FF000000" + android:strokeLineCap="round" + android:strokeLineJoin="round" + android:strokeWidth="1.5" + android:strokeAlpha="1" + android:pathData=" M7.88 -0.62 C7.88,-0.62 7.88,9.38 7.88,9.38 C7.88,10.48 6.98,11.38 5.88,11.38 C5.88,11.38 -5.87,11.38 -5.87,11.38 C-6.98,11.38 -7.87,10.48 -7.87,9.38 C-7.87,9.38 -7.87,-0.62 -7.87,-0.62 C-7.87,-1.73 -6.98,-2.62 -5.87,-2.62 C-5.87,-2.62 5.88,-2.62 5.88,-2.62 C6.98,-2.62 7.88,-1.73 7.88,-0.62c "/> + </group> + <group android:name="_R_G_L_0_G" + android:translateX="23" + android:translateY="32.125"> + <path android:name="_R_G_L_0_G_D_0_P_0" + android:strokeColor="#FF000000" + android:strokeLineCap="round" + android:strokeLineJoin="round" + android:strokeWidth="1.5" + android:strokeAlpha="1" + android:pathData=" M4.38 -2.62 C4.38,-2.62 4.38,-7.1 4.38,-7.1 C4.38,-9.46 2.42,-11.37 0,-11.37 C-2.42,-11.37 -4.37,-9.46 -4.37,-7.1 C-4.37,-7.1 -4.37,-2.62 -4.37,-2.62 "/> + </group> + </group> + <group android:name="time_group"/> + </vector> + </aapt:attr> + <target android:name="_R_G_L_2_G_D_0_P_0"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator android:propertyName="pathData" + android:duration="333" + android:startOffset="0" + android:valueFrom="M0 6.13 C0.97,6.13 1.75,5.34 1.75,4.38 C1.75,3.41 0.97,2.63 0,2.63 C-0.97,2.63 -1.75,3.41 -1.75,4.38 C-1.75,5.34 -0.97,6.13 0,6.13c " + android:valueTo="M-0.09 8.63 C1.2,8.63 2.25,7.57 2.25,6.28 C2.25,4.99 1.2,3.94 -0.09,3.94 C-1.39,3.94 -2.44,4.99 -2.44,6.28 C-2.44,7.57 -1.39,8.63 -0.09,8.63c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.372,0 0.203,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="_R_G_L_1_G_D_0_P_0"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator android:propertyName="strokeWidth" + android:duration="333" + android:startOffset="0" + android:valueFrom="1.5" + android:valueTo="2" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.307,0 0.386,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="_R_G_L_1_G_D_0_P_0"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator android:propertyName="pathData" + android:duration="333" + android:startOffset="0" + android:valueFrom="M7.88 -0.62 C7.88,-0.62 7.88,9.38 7.88,9.38 C7.88,10.48 6.98,11.38 5.88,11.38 C5.88,11.38 -5.87,11.38 -5.87,11.38 C-6.98,11.38 -7.87,10.48 -7.87,9.38 C-7.87,9.38 -7.87,-0.62 -7.87,-0.62 C-7.87,-1.73 -6.98,-2.62 -5.87,-2.62 C-5.87,-2.62 5.88,-2.62 5.88,-2.62 C6.98,-2.62 7.88,-1.73 7.88,-0.62c " + android:valueTo="M11.25 -0.64 C11.25,-0.64 11.25,13.64 11.25,13.64 C11.25,15.22 9.97,16.5 8.39,16.5 C8.39,16.5 -8.39,16.5 -8.39,16.5 C-9.97,16.5 -11.25,15.22 -11.25,13.64 C-11.25,13.64 -11.25,-0.64 -11.25,-0.64 C-11.25,-2.22 -9.97,-3.5 -8.39,-3.5 C-8.39,-3.5 8.39,-3.5 8.39,-3.5 C9.97,-3.5 11.25,-2.22 11.25,-0.64c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.372,0 0.203,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="_R_G_L_0_G_D_0_P_0"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator android:propertyName="strokeWidth" + android:duration="333" + android:startOffset="0" + android:valueFrom="1.5" + android:valueTo="2" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.307,0 0.386,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="_R_G_L_0_G_D_0_P_0"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator android:propertyName="pathData" + android:duration="333" + android:startOffset="0" + android:valueFrom="M4.38 -2.62 C4.38,-2.62 4.38,-7.1 4.38,-7.1 C4.38,-9.46 2.42,-11.37 0,-11.37 C-2.42,-11.37 -4.37,-9.46 -4.37,-7.1 C-4.37,-7.1 -4.37,-2.62 -4.37,-2.62 " + android:valueTo="M5.88 -3.87 C5.88,-3.87 5.88,-10.2 5.88,-10.2 C5.88,-13.54 3.08,-16.25 -0.37,-16.25 C-3.83,-16.25 -6.62,-13.54 -6.62,-10.2 C-6.62,-10.2 -6.62,-3.87 -6.62,-3.87 " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.372,0 0.203,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="time_group"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator android:propertyName="translateX" + android:duration="517" + android:startOffset="0" + android:valueFrom="0" + android:valueTo="1" + android:valueType="floatType"/> + </set> + </aapt:attr> + </target> +</animated-vector> diff --git a/packages/SystemUI/res-keyguard/drawable/lock_ls_to_aod.xml b/packages/SystemUI/res-keyguard/drawable/lock_ls_to_aod.xml new file mode 100644 index 000000000000..8a728ee7b46a --- /dev/null +++ b/packages/SystemUI/res-keyguard/drawable/lock_ls_to_aod.xml @@ -0,0 +1,151 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- 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. +--> +<animated-vector xmlns:aapt="http://schemas.android.com/aapt" + xmlns:android="http://schemas.android.com/apk/res/android"> + <aapt:attr name="android:drawable"> + <vector android:height="65dp" + android:width="46dp" + android:viewportHeight="65" + android:viewportWidth="46"> + <group android:name="_R_G"> + <group android:name="_R_G_L_2_G" + android:translateX="23" + android:translateY="32.125"> + <path android:name="_R_G_L_2_G_D_0_P_0" + android:fillColor="#FF000000" + android:fillAlpha="1" + android:fillType="nonZero" + android:pathData=" M-0.09 8.63 C1.2,8.63 2.25,7.57 2.25,6.28 C2.25,4.99 1.2,3.94 -0.09,3.94 C-1.39,3.94 -2.44,4.99 -2.44,6.28 C-2.44,7.57 -1.39,8.63 -0.09,8.63c "/> + </group> + <group android:name="_R_G_L_1_G" + android:translateX="23" + android:translateY="32.125"> + <path android:name="_R_G_L_1_G_D_0_P_0" + android:strokeColor="#FF000000" + android:strokeLineCap="round" + android:strokeLineJoin="round" + android:strokeWidth="2" + android:strokeAlpha="1" + android:pathData=" M11.25 -0.64 C11.25,-0.64 11.25,13.64 11.25,13.64 C11.25,15.22 9.97,16.5 8.39,16.5 C8.39,16.5 -8.39,16.5 -8.39,16.5 C-9.97,16.5 -11.25,15.22 -11.25,13.64 C-11.25,13.64 -11.25,-0.64 -11.25,-0.64 C-11.25,-2.22 -9.97,-3.5 -8.39,-3.5 C-8.39,-3.5 8.39,-3.5 8.39,-3.5 C9.97,-3.5 11.25,-2.22 11.25,-0.64c "/> + </group> + <group android:name="_R_G_L_0_G" + android:translateX="23" + android:translateY="32.125"> + <path android:name="_R_G_L_0_G_D_0_P_0" + android:strokeColor="#FF000000" + android:strokeLineCap="round" + android:strokeLineJoin="round" + android:strokeWidth="2" + android:strokeAlpha="1" + android:pathData=" M5.88 -3.87 C5.88,-3.87 5.88,-10.2 5.88,-10.2 C5.88,-13.54 3.08,-16.25 -0.37,-16.25 C-3.83,-16.25 -6.62,-13.54 -6.62,-10.2 C-6.62,-10.2 -6.62,-3.87 -6.62,-3.87 "/> + </group> + </group> + <group android:name="time_group"/> + </vector> + </aapt:attr> + <target android:name="_R_G_L_2_G_D_0_P_0"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator android:propertyName="pathData" + android:duration="333" + android:startOffset="0" + android:valueFrom="M-0.09 8.63 C1.2,8.63 2.25,7.57 2.25,6.28 C2.25,4.99 1.2,3.94 -0.09,3.94 C-1.39,3.94 -2.44,4.99 -2.44,6.28 C-2.44,7.57 -1.39,8.63 -0.09,8.63c " + android:valueTo="M0 6.13 C0.97,6.13 1.75,5.34 1.75,4.38 C1.75,3.41 0.97,2.63 0,2.63 C-0.97,2.63 -1.75,3.41 -1.75,4.38 C-1.75,5.34 -0.97,6.13 0,6.13c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.431,0 0.133,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="_R_G_L_1_G_D_0_P_0"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator android:propertyName="strokeWidth" + android:duration="333" + android:startOffset="0" + android:valueFrom="2" + android:valueTo="1.5" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.38,0 0.274,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="_R_G_L_1_G_D_0_P_0"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator android:propertyName="pathData" + android:duration="333" + android:startOffset="0" + android:valueFrom="M11.25 -0.64 C11.25,-0.64 11.25,13.64 11.25,13.64 C11.25,15.22 9.97,16.5 8.39,16.5 C8.39,16.5 -8.39,16.5 -8.39,16.5 C-9.97,16.5 -11.25,15.22 -11.25,13.64 C-11.25,13.64 -11.25,-0.64 -11.25,-0.64 C-11.25,-2.22 -9.97,-3.5 -8.39,-3.5 C-8.39,-3.5 8.39,-3.5 8.39,-3.5 C9.97,-3.5 11.25,-2.22 11.25,-0.64c " + android:valueTo="M7.88 -0.62 C7.88,-0.62 7.88,9.38 7.88,9.38 C7.88,10.48 6.98,11.38 5.88,11.38 C5.88,11.38 -5.87,11.38 -5.87,11.38 C-6.98,11.38 -7.87,10.48 -7.87,9.38 C-7.87,9.38 -7.87,-0.62 -7.87,-0.62 C-7.87,-1.73 -6.98,-2.62 -5.87,-2.62 C-5.87,-2.62 5.88,-2.62 5.88,-2.62 C6.98,-2.62 7.88,-1.73 7.88,-0.62c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.431,0 0.133,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="_R_G_L_0_G_D_0_P_0"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator android:propertyName="strokeWidth" + android:duration="333" + android:startOffset="0" + android:valueFrom="2" + android:valueTo="1.5" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.38,0 0.274,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="_R_G_L_0_G_D_0_P_0"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator android:propertyName="pathData" + android:duration="333" + android:startOffset="0" + android:valueFrom="M5.88 -3.87 C5.88,-3.87 5.88,-10.2 5.88,-10.2 C5.88,-13.54 3.08,-16.25 -0.37,-16.25 C-3.83,-16.25 -6.62,-13.54 -6.62,-10.2 C-6.62,-10.2 -6.62,-3.87 -6.62,-3.87 " + android:valueTo="M4.38 -2.62 C4.38,-2.62 4.38,-7.1 4.38,-7.1 C4.38,-9.46 2.42,-11.37 0,-11.37 C-2.42,-11.37 -4.37,-9.46 -4.37,-7.1 C-4.37,-7.1 -4.37,-2.62 -4.37,-2.62 " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.431,0 0.133,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="time_group"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator android:propertyName="translateX" + android:duration="517" + android:startOffset="0" + android:valueFrom="0" + android:valueTo="1" + android:valueType="floatType"/> + </set> + </aapt:attr> + </target> +</animated-vector> diff --git a/packages/SystemUI/res/anim/lock_to_unlock.xml b/packages/SystemUI/res-keyguard/drawable/lock_to_unlock.xml index 76f7a05866d9..ab7e9d9e582b 100644 --- a/packages/SystemUI/res/anim/lock_to_unlock.xml +++ b/packages/SystemUI/res-keyguard/drawable/lock_to_unlock.xml @@ -21,7 +21,7 @@ <group android:name="_R_G_L_2_G_N_10_T_1" android:translateX="50.25" android:translateY="61"> <group android:name="_R_G_L_2_G_N_10_T_0" android:translateX="-13.75" android:translateY="-7.5"> <group android:name="_R_G_L_2_G" android:translateX="-0.375" android:translateY="-22.375"> - <path android:name="_R_G_L_2_G_D_0_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:pathData=" M4.75 15 C4.75,15 23.25,15 23.25,15 C24.35,15 25.25,15.9 25.25,17 C25.25,17 25.25,33 25.25,33 C25.25,34.1 24.35,35 23.25,35 C23.25,35 4.75,35 4.75,35 C3.65,35 2.75,34.1 2.75,33 C2.75,33 2.75,17 2.75,17 C2.75,15.9 3.65,15 4.75,15c " /> + <path android:name="_R_G_L_2_G_D_0_P_0" android:strokeColor="#FF000000" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:pathData=" M4.75 15 C4.75,15 23.25,15 23.25,15 C24.35,15 25.25,15.9 25.25,17 C25.25,17 25.25,33 25.25,33 C25.25,34.1 24.35,35 23.25,35 C23.25,35 4.75,35 4.75,35 C3.65,35 2.75,34.1 2.75,33 C2.75,33 2.75,17 2.75,17 C2.75,15.9 3.65,15 4.75,15c " /> </group> </group> </group> @@ -30,7 +30,7 @@ <group android:name="_R_G_L_1_G_N_10_T_1" android:translateX="50.25" android:translateY="61"> <group android:name="_R_G_L_1_G_N_10_T_0" android:translateX="-13.75" android:translateY="-7.5"> <group android:name="_R_G_L_1_G" android:translateX="5" android:translateY="-22.5"> - <path android:name="_R_G_L_1_G_D_0_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:pathData=" M2.5 15 C2.5,15 2.5,8.61 2.5,8.61 C2.5,5.24 5.3,2.5 8.75,2.5 C12.2,2.5 15,5.24 15,8.61 C15,8.61 15,15 15,15 " /> + <path android:name="_R_G_L_1_G_D_0_P_0" android:strokeColor="#FF000000" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:pathData=" M2.5 15 C2.5,15 2.5,8.61 2.5,8.61 C2.5,5.24 5.3,2.5 8.75,2.5 C12.2,2.5 15,5.24 15,8.61 C15,8.61 15,15 15,15 " /> </group> </group> </group> @@ -39,7 +39,7 @@ <group android:name="_R_G_L_0_G_N_10_T_1" android:translateX="50.25" android:translateY="61"> <group android:name="_R_G_L_0_G_N_10_T_0" android:translateX="-13.75" android:translateY="-7.5"> <group android:name="_R_G_L_0_G" android:translateX="11" android:translateY="-0.25" android:pivotX="2.75" android:pivotY="2.75" android:scaleX="1" android:scaleY="1"> - <path android:name="_R_G_L_0_G_D_0_P_0" android:fillColor="#b7f29f" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M2.75 5.25 C4.13,5.25 5.25,4.13 5.25,2.75 C5.25,1.37 4.13,0.25 2.75,0.25 C1.37,0.25 0.25,1.37 0.25,2.75 C0.25,4.13 1.37,5.25 2.75,5.25c " /> + <path android:name="_R_G_L_0_G_D_0_P_0" android:fillColor="#FF000000" android:fillAlpha="1" android:fillType="nonZero" android:pathData=" M2.75 5.25 C4.13,5.25 5.25,4.13 5.25,2.75 C5.25,1.37 4.13,0.25 2.75,0.25 C1.37,0.25 0.25,1.37 0.25,2.75 C0.25,4.13 1.37,5.25 2.75,5.25c " /> </group> </group> </group> diff --git a/packages/SystemUI/res-keyguard/drawable/super_lock_icon.xml b/packages/SystemUI/res-keyguard/drawable/super_lock_icon.xml new file mode 100644 index 000000000000..7f0f68f4fc06 --- /dev/null +++ b/packages/SystemUI/res-keyguard/drawable/super_lock_icon.xml @@ -0,0 +1,82 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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 + --> +<animated-selector + xmlns:android="http://schemas.android.com/apk/res/android"> + <!-- + State corresponds with the following icons: + state_first => lock icon + state_middle => fingerprint icon + state_last => unlocked icon + + state_single + = true => AOD + = false => LS + --> + + <item + android:id="@+id/locked" + android:drawable="@drawable/ic_lock" + android:state_first="true" + android:state_single="false"/> + + <item + android:id="@+id/locked_fp" + android:state_middle="true" + android:state_single="false" + android:drawable="@drawable/ic_fingerprint" /> + + <item + android:id="@+id/unlocked" + android:state_last="true" + android:state_single="false" + android:drawable="@drawable/ic_unlocked" /> + + <item + android:id="@+id/locked_aod" + android:state_first="true" + android:state_single="true" + android:drawable="@drawable/ic_lock_aod" /> + + <item + android:id="@+id/no_icon" + android:drawable="@color/transparent" /> + + <transition + android:fromId="@id/locked" + android:toId="@id/unlocked" + android:drawable="@drawable/lock_to_unlock" /> + + <transition + android:fromId="@id/locked_fp" + android:toId="@id/unlocked" + android:drawable="@drawable/fp_to_unlock" /> + + <transition + android:fromId="@id/unlocked" + android:toId="@id/locked_fp" + android:drawable="@drawable/unlock_to_fp" /> + + <transition + android:fromId="@id/locked_aod" + android:toId="@id/locked" + android:drawable="@drawable/lock_aod_to_ls" /> + + <transition + android:fromId="@id/locked" + android:toId="@id/locked_aod" + android:drawable="@drawable/lock_ls_to_aod" /> +</animated-selector> diff --git a/packages/SystemUI/res-keyguard/drawable/unlock_to_fp.xml b/packages/SystemUI/res-keyguard/drawable/unlock_to_fp.xml new file mode 100644 index 000000000000..620c71a73121 --- /dev/null +++ b/packages/SystemUI/res-keyguard/drawable/unlock_to_fp.xml @@ -0,0 +1,298 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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 + --> +<animated-vector xmlns:aapt="http://schemas.android.com/aapt" + xmlns:android="http://schemas.android.com/apk/res/android"> + <aapt:attr name="android:drawable"> + <vector android:height="65dp" + android:width="46dp" + android:viewportHeight="65" + android:viewportWidth="46"> + <group android:name="_R_G"> + <group android:name="_R_G_L_1_G" + android:translateX="3.75" + android:translateY="8.25"> + <path android:name="_R_G_L_1_G_D_0_P_0" + android:strokeColor="#FF000000" + android:strokeLineCap="round" + android:strokeLineJoin="round" + android:strokeWidth="2" + android:strokeAlpha="1" + android:pathData=" M30.64 30.14 C30.64,30.14 30.64,38.14 30.64,38.14 C30.64,38.77 30.36,39.32 29.91,39.69 C29.57,39.97 29.12,40.14 28.64,40.14 C28.64,40.14 10.14,40.14 10.14,40.14 C9.04,40.14 8.14,39.25 8.14,38.14 C8.14,38.14 8.14,30.14 8.14,30.14 "/> + <path android:name="_R_G_L_1_G_D_1_P_0" + android:strokeColor="#FF000000" + android:strokeLineCap="round" + android:strokeLineJoin="round" + android:strokeWidth="2" + android:strokeAlpha="0" + android:pathData=" M19.42 31.53 C18.15,31.52 18.11,30.33 18.11,30.33 C18.11,29.59 18.66,28.98 19.4,28.98 C20.13,28.98 20.69,29.59 20.69,30.33 C20.69,30.33 20.69,30.37 20.69,30.37 C20.69,30.64 20.49,30.87 20.25,30.87 C20.07,30.87 19.91,30.74 19.84,30.55 C19.84,30.55 19.69,30.14 19.69,30.14 C19.63,29.94 19.46,29.82 19.28,29.82 C19.04,29.82 18.61,30.02 18.61,30.29 C18.61,30.43 18.6,30.75 18.76,31.03 C18.87,31.21 19.21,31.77 19.96,31.41 C20.69,31.01 20.69,30.34 20.69,30.34 "/> + <path android:name="_R_G_L_1_G_D_2_P_0" + android:strokeColor="#FF000000" + android:strokeLineCap="round" + android:strokeLineJoin="round" + android:strokeWidth="2" + android:strokeAlpha="1" + android:pathData=" M8.14 30.22 C8.14,30.22 8.14,22.22 8.14,22.22 C8.14,21.71 8.33,21.25 8.64,20.9 C9,20.48 9.54,20.22 10.14,20.22 C10.14,20.22 28.64,20.22 28.64,20.22 C29.75,20.22 30.64,21.11 30.64,22.22 C30.64,22.22 30.64,30.14 30.64,30.14 "/> + <path android:name="_R_G_L_1_G_D_3_P_0" + android:strokeColor="#FF000000" + android:strokeLineCap="round" + android:strokeLineJoin="round" + android:strokeWidth="2" + android:strokeAlpha="1" + android:pathData=" M37.91 20.05 C37.91,20.05 37.89,14.16 37.89,14.16 C37.89,10.79 35.15,8.05 31.86,8.03 C28.46,8.01 25.61,10.77 25.61,14.15 C25.61,14.15 25.62,20.04 25.62,20.04 "/> + </group> + <group android:name="_R_G_L_0_G" + android:translateX="20.357" + android:translateY="35.75" + android:pivotX="2.75" + android:pivotY="2.75" + android:scaleX="1" + android:scaleY="1"> + <path android:name="_R_G_L_0_G_D_0_P_0" + android:fillColor="#FF000000" + android:fillAlpha="1" + android:fillType="nonZero" + android:pathData=" M2.75 5.25 C4.13,5.25 5.25,4.13 5.25,2.75 C5.25,1.37 4.13,0.25 2.75,0.25 C1.37,0.25 0.25,1.37 0.25,2.75 C0.25,4.13 1.37,5.25 2.75,5.25c "/> + </group> + </group> + <group android:name="time_group"/> + </vector> + </aapt:attr> + <target android:name="_R_G_L_1_G_D_0_P_0"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator android:propertyName="pathData" + android:duration="183" + android:startOffset="0" + android:valueFrom="M30.64 30.14 C30.64,30.14 30.64,38.14 30.64,38.14 C30.64,38.77 30.36,39.32 29.91,39.69 C29.57,39.97 29.12,40.14 28.64,40.14 C28.64,40.14 10.14,40.14 10.14,40.14 C9.04,40.14 8.14,39.25 8.14,38.14 C8.14,38.14 8.14,30.14 8.14,30.14 " + android:valueTo="M30.64 30.14 C30.64,30.14 30.64,38.14 30.64,38.14 C30.64,38.77 30.36,39.32 29.91,39.69 C29.57,39.97 29.12,40.14 28.64,40.14 C28.64,40.14 10.14,40.14 10.14,40.14 C9.04,40.14 8.14,39.25 8.14,38.14 C8.14,38.14 8.14,30.14 8.14,30.14 " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.15,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" + android:duration="133" + android:startOffset="183" + android:valueFrom="M30.64 30.14 C30.64,30.14 30.64,38.14 30.64,38.14 C30.64,38.77 30.36,39.32 29.91,39.69 C29.57,39.97 29.12,40.14 28.64,40.14 C28.64,40.14 10.14,40.14 10.14,40.14 C9.04,40.14 8.14,39.25 8.14,38.14 C8.14,38.14 8.14,30.14 8.14,30.14 " + android:valueTo="M27.52 38.98 C26.49,39.95 25.29,40.73 23.98,41.29 C23.17,41.65 22.31,41.91 21.41,42.07 C20.74,42.19 20.05,42.25 19.34,42.25 C18.44,42.25 17.56,42.15 16.72,41.96 C15.93,41.77 15.16,41.51 14.43,41.18 C13.23,40.63 12.13,39.88 11.16,38.98 " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.15,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="_R_G_L_1_G_D_1_P_0"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator android:propertyName="strokeAlpha" + android:duration="183" + android:startOffset="0" + android:valueFrom="0" + android:valueTo="0" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="strokeAlpha" + android:duration="33" + android:startOffset="183" + android:valueFrom="0" + android:valueTo="1" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="_R_G_L_1_G_D_1_P_0"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator android:propertyName="pathData" + android:duration="183" + android:startOffset="0" + android:valueFrom="M19.42 31.53 C18.15,31.52 18.11,30.33 18.11,30.33 C18.11,29.59 18.66,28.98 19.4,28.98 C20.13,28.98 20.69,29.59 20.69,30.33 C20.69,30.33 20.69,30.37 20.69,30.37 C20.69,30.64 20.49,30.87 20.25,30.87 C20.07,30.87 19.91,30.74 19.84,30.55 C19.84,30.55 19.69,30.14 19.69,30.14 C19.63,29.94 19.46,29.82 19.28,29.82 C19.04,29.82 18.61,30.02 18.61,30.29 C18.61,30.43 18.6,30.75 18.76,31.03 C18.87,31.21 19.21,31.77 19.96,31.41 C20.69,31.01 20.69,30.34 20.69,30.34 " + android:valueTo="M19.42 31.53 C18.15,31.52 18.11,30.33 18.11,30.33 C18.11,29.59 18.66,28.98 19.4,28.98 C20.13,28.98 20.69,29.59 20.69,30.33 C20.69,30.33 20.69,30.37 20.69,30.37 C20.69,30.64 20.49,30.87 20.25,30.87 C20.07,30.87 19.91,30.74 19.84,30.55 C19.84,30.55 19.69,30.14 19.69,30.14 C19.63,29.94 19.46,29.82 19.28,29.82 C19.04,29.82 18.61,30.02 18.61,30.29 C18.61,30.43 18.6,30.75 18.76,31.03 C18.87,31.21 19.21,31.77 19.96,31.41 C20.69,31.01 20.69,30.34 20.69,30.34 " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.15,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" + android:duration="133" + android:startOffset="183" + android:valueFrom="M19.42 31.53 C18.15,31.52 18.11,30.33 18.11,30.33 C18.11,29.59 18.66,28.98 19.4,28.98 C20.13,28.98 20.69,29.59 20.69,30.33 C20.69,30.33 20.69,30.37 20.69,30.37 C20.69,30.64 20.49,30.87 20.25,30.87 C20.07,30.87 19.91,30.74 19.84,30.55 C19.84,30.55 19.69,30.14 19.69,30.14 C19.63,29.94 19.46,29.82 19.28,29.82 C19.04,29.82 18.61,30.02 18.61,30.29 C18.61,30.43 18.6,30.75 18.76,31.03 C18.87,31.21 19.21,31.77 19.96,31.41 C20.69,31.01 20.69,30.34 20.69,30.34 " + android:valueTo="M8.64 34.07 C7.89,31.97 7.89,29.85 7.89,29.85 C7.89,24.05 12.81,19.34 19.34,19.34 C25.87,19.34 30.8,24.05 30.8,29.85 C30.8,29.85 30.8,30.16 30.8,30.16 C30.8,32.32 29.04,34.07 26.89,34.07 C25.28,34.07 23.86,33.1 23.27,31.61 C23.27,31.61 21.96,28.34 21.96,28.34 C21.37,26.85 19.93,25.89 18.34,25.89 C16.18,25.89 14.43,27.64 14.43,29.8 C14.43,31.42 14.87,32.99 15.68,34.36 C16.22,35.26 16.93,36.08 17.77,36.75 C17.77,36.75 18.52,37.34 18.52,37.34 " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.15,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="_R_G_L_1_G_D_2_P_0"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator android:propertyName="pathData" + android:duration="183" + android:startOffset="0" + android:valueFrom="M8.14 30.22 C8.14,30.22 8.14,22.22 8.14,22.22 C8.14,21.71 8.33,21.25 8.64,20.9 C9,20.48 9.54,20.22 10.14,20.22 C10.14,20.22 28.64,20.22 28.64,20.22 C29.75,20.22 30.64,21.11 30.64,22.22 C30.64,22.22 30.64,30.14 30.64,30.14 " + android:valueTo="M8.14 30.22 C8.14,30.22 8.14,22.22 8.14,22.22 C8.14,21.71 8.33,21.25 8.64,20.9 C9,20.48 9.54,20.22 10.14,20.22 C10.14,20.22 28.64,20.22 28.64,20.22 C29.75,20.22 30.64,21.11 30.64,22.22 C30.64,22.22 30.64,30.14 30.64,30.14 " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.15,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" + android:duration="133" + android:startOffset="183" + android:valueFrom="M8.14 30.22 C8.14,30.22 8.14,22.22 8.14,22.22 C8.14,21.71 8.33,21.25 8.64,20.9 C9,20.48 9.54,20.22 10.14,20.22 C10.14,20.22 28.64,20.22 28.64,20.22 C29.75,20.22 30.64,21.11 30.64,22.22 C30.64,22.22 30.64,30.14 30.64,30.14 " + android:valueTo="M6.25 19.34 C7.48,17.3 9.46,15.58 11.9,14.42 C12.93,13.94 14.03,13.55 15.2,13.27 C16.51,12.96 17.9,12.8 19.34,12.8 C20.77,12.8 22.14,12.96 23.45,13.26 C24.9,13.6 26.26,14.12 27.48,14.78 C29.6,15.92 31.32,17.5 32.43,19.34 " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.15,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="_R_G_L_1_G_D_3_P_0"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator android:propertyName="pathData" + android:duration="150" + android:startOffset="0" + android:valueFrom="M37.91 20.05 C37.91,20.05 37.89,14.16 37.89,14.16 C37.89,10.79 35.15,8.05 31.86,8.03 C28.46,8.01 25.61,10.77 25.61,14.15 C25.61,14.15 25.62,20.04 25.62,20.04 " + android:valueTo="M13.12 20.04 C13.12,20.04 13.11,14.15 13.11,14.15 C13.11,10.77 15.91,8.04 19.36,8.04 C22.81,8.04 25.61,10.77 25.61,14.15 C25.61,14.15 25.62,20.04 25.62,20.04 " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.261,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" + android:duration="33" + android:startOffset="150" + android:valueFrom="M13.12 20.04 C13.12,20.04 13.11,14.15 13.11,14.15 C13.11,10.77 15.91,8.04 19.36,8.04 C22.81,8.04 25.61,10.77 25.61,14.15 C25.61,14.15 25.62,20.04 25.62,20.04 " + android:valueTo="M13.12 20.04 C13.12,20.04 13.11,14.15 13.11,14.15 C13.11,10.77 15.91,8.04 19.36,8.04 C22.81,8.04 25.61,10.77 25.61,14.15 C25.61,14.15 25.62,20.04 25.62,20.04 " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.123,0 0.261,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" + android:duration="133" + android:startOffset="183" + android:valueFrom="M13.12 20.04 C13.12,20.04 13.11,14.15 13.11,14.15 C13.11,10.77 15.91,8.04 19.36,8.04 C22.81,8.04 25.61,10.77 25.61,14.15 C25.61,14.15 25.62,20.04 25.62,20.04 " + android:valueTo="M9.52 8.7 C10.98,7.91 12.58,7.28 14.28,6.86 C15.89,6.46 17.58,6.25 19.34,6.25 C21.06,6.25 22.72,6.45 24.3,6.83 C26.04,7.25 27.67,7.89 29.16,8.7 " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.123,0 0.15,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="_R_G_L_0_G_D_0_P_0"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator android:propertyName="fillAlpha" + android:duration="200" + android:startOffset="0" + android:valueFrom="1" + android:valueTo="1" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="fillAlpha" + android:duration="17" + android:startOffset="200" + android:valueFrom="1" + android:valueTo="0" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="_R_G_L_0_G"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator android:propertyName="scaleX" + android:duration="183" + android:startOffset="0" + android:valueFrom="1" + android:valueTo="1" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.596,0 0.018,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleY" + android:duration="183" + android:startOffset="0" + android:valueFrom="1" + android:valueTo="1" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.596,0 0.018,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleX" + android:duration="67" + android:startOffset="183" + android:valueFrom="1" + android:valueTo="1.4186600000000003" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.596,0 0.018,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleY" + android:duration="67" + android:startOffset="183" + android:valueFrom="1" + android:valueTo="1.4186600000000003" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.596,0 0.018,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="time_group"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator android:propertyName="translateX" + android:duration="433" + android:startOffset="0" + android:valueFrom="0" + android:valueTo="1" + android:valueType="floatType"/> + </set> + </aapt:attr> + </target> +</animated-vector> diff --git a/packages/SystemUI/res-product/values-te/strings.xml b/packages/SystemUI/res-product/values-te/strings.xml index 1773f9087e0e..511e09532c14 100644 --- a/packages/SystemUI/res-product/values-te/strings.xml +++ b/packages/SystemUI/res-product/values-te/strings.xml @@ -38,8 +38,8 @@ <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="3280816298678433681">"మీరు ఫోన్ను అన్లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పు ప్రయత్నాలు చేశారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> ప్రయత్నాలలో విఫలమైతే, కార్యాలయ ప్రొఫైల్ తీసివేయబడుతుంది, దీని వలన ప్రొఫైల్ డేటా మొత్తం తొలగించబడుతుంది."</string> <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4417100487251371559">"మీరు టాబ్లెట్ను అన్లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> సార్లు తప్పు ప్రయత్నాలు చేశారు. కార్యాలయ ప్రొఫైల్ తీసివేయబడుతుంది, దీని వలన ప్రొఫైల్ డేటా మొత్తం తొలగించబడుతుంది."</string> <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"మీరు ఫోన్ను అన్లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> సార్లు తప్పు ప్రయత్నాలు చేశారు. కార్యాలయ ప్రొఫైల్ తీసివేయబడుతుంది, దీని వలన ప్రొఫైల్ డేటా మొత్తం తొలగించబడుతుంది."</string> - <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"మీరు మీ అన్లాక్ నమూనాను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> ప్రయత్నాలలో విఫలమైతే, మీరు ఇమెయిల్ ఖాతాను ఉపయోగించి మీ టాబ్లెట్ను అన్లాక్ చేయాల్సి వస్తుంది.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string> - <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"మీరు మీ అన్లాక్ నమూనాను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> ప్రయత్నాలలో విఫలమైతే, మీరు ఇమెయిల్ ఖాతాను ఉపయోగించి మీ ఫోన్ను అన్లాక్ చేయాల్సి వస్తుంది.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string> + <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"మీరు మీ అన్లాక్ నమూనాను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> ప్రయత్నాలలో విఫలమైతే, మీరు ఈమెయిల్ ఖాతాను ఉపయోగించి మీ టాబ్లెట్ను అన్లాక్ చేయాల్సి వస్తుంది.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string> + <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"మీరు మీ అన్లాక్ నమూనాను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> ప్రయత్నాలలో విఫలమైతే, మీరు ఈమెయిల్ ఖాతాను ఉపయోగించి మీ ఫోన్ను అన్లాక్ చేయాల్సి వస్తుంది.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string> <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"మరిన్ని ఆప్షన్ల కోసం మీ ఫోన్ను అన్లాక్ చేయండి"</string> <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"మరిన్ని ఆప్షన్ల కోసం మీ టాబ్లెట్ను అన్లాక్ చేయండి"</string> <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"మరిన్ని ఆప్షన్ల కోసం మీ పరికరాన్ని అన్లాక్ చేయండి"</string> diff --git a/packages/SystemUI/res/drawable/stat_sys_managed_profile_status.xml b/packages/SystemUI/res/drawable/stat_sys_managed_profile_status.xml index 3761a40ddbaa..c415ecd4f0a8 100644 --- a/packages/SystemUI/res/drawable/stat_sys_managed_profile_status.xml +++ b/packages/SystemUI/res/drawable/stat_sys_managed_profile_status.xml @@ -21,7 +21,4 @@ <path android:fillColor="@android:color/white" android:pathData="M20,6h-4V4c0-1.1-0.9-2-2-2h-4C8.9,2,8,2.9,8,4v2H4C2.9,6,2,6.9,2,8l0,11c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V8 C22,6.9,21.1,6,20,6z M10,4h4v2h-4V4z M20,19H4V8h16V19z" /> - <path - android:fillColor="@android:color/white" - android:pathData="M 12 12 C 12.8284271247 12 13.5 12.6715728753 13.5 13.5 C 13.5 14.3284271247 12.8284271247 15 12 15 C 11.1715728753 15 10.5 14.3284271247 10.5 13.5 C 10.5 12.6715728753 11.1715728753 12 12 12 Z" /> </vector>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml index c1d7308be5a8..79ac737ba304 100644 --- a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml +++ b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml @@ -323,6 +323,46 @@ </FrameLayout> </LinearLayout> + <LinearLayout + android:id="@+id/wifi_scan_notify_layout" + style="@style/InternetDialog.Network" + android:orientation="vertical" + android:layout_height="wrap_content" + android:paddingBottom="4dp" + android:clickable="false" + android:focusable="false"> + + <LinearLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:minWidth="56dp" + android:gravity="start|top" + android:orientation="horizontal" + android:paddingEnd="12dp" + android:paddingTop="16dp" + android:paddingBottom="4dp"> + <ImageView + android:src="@drawable/ic_info_outline" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:tint="?android:attr/textColorTertiary"/> + </LinearLayout> + + <LinearLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="vertical"> + <TextView + android:id="@+id/wifi_scan_notify_text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:paddingTop="16dp" + android:paddingBottom="8dp" + android:textColor="?android:attr/textColorSecondary" + android:clickable="true"/> + </LinearLayout> + </LinearLayout> + <FrameLayout android:id="@+id/done_layout" android:layout_width="67dp" diff --git a/packages/SystemUI/res/layout/rounded_corners_bottom.xml b/packages/SystemUI/res/layout/rounded_corners_bottom.xml index 720e47b1908c..f91ab6f4980a 100644 --- a/packages/SystemUI/res/layout/rounded_corners_bottom.xml +++ b/packages/SystemUI/res/layout/rounded_corners_bottom.xml @@ -31,8 +31,7 @@ android:id="@+id/privacy_dot_left_container" android:layout_height="@dimen/status_bar_height" android:layout_width="wrap_content" - android:layout_marginTop="@dimen/status_bar_padding_top" - android:layout_marginLeft="0dp" + android:paddingTop="@dimen/status_bar_padding_top" android:layout_gravity="left|bottom" android:visibility="invisible" > <ImageView @@ -51,12 +50,12 @@ android:tint="#ff000000" android:layout_gravity="right|bottom" android:src="@drawable/rounded_corner_bottom"/> + <FrameLayout android:id="@+id/privacy_dot_right_container" android:layout_height="@dimen/status_bar_height" android:layout_width="wrap_content" - android:layout_marginTop="@dimen/status_bar_padding_top" - android:layout_marginRight="0dp" + android:paddingTop="@dimen/status_bar_padding_top" android:layout_gravity="right|bottom" android:visibility="invisible" > <ImageView diff --git a/packages/SystemUI/res/layout/rounded_corners_top.xml b/packages/SystemUI/res/layout/rounded_corners_top.xml index 6abe406e0ea6..819a9a4e9b02 100644 --- a/packages/SystemUI/res/layout/rounded_corners_top.xml +++ b/packages/SystemUI/res/layout/rounded_corners_top.xml @@ -29,10 +29,9 @@ <FrameLayout android:id="@+id/privacy_dot_left_container" - android:layout_height="@*android:dimen/status_bar_height_portrait" + android:layout_height="@dimen/status_bar_height" android:layout_width="wrap_content" - android:layout_marginTop="@dimen/status_bar_padding_top" - android:layout_marginLeft="0dp" + android:paddingTop="@dimen/status_bar_padding_top" android:layout_gravity="left|top" android:visibility="invisible" > <ImageView @@ -54,10 +53,9 @@ <FrameLayout android:id="@+id/privacy_dot_right_container" - android:layout_height="@*android:dimen/status_bar_height_portrait" + android:layout_height="@dimen/status_bar_height" android:layout_width="wrap_content" - android:layout_marginTop="@dimen/status_bar_padding_top" - android:layout_marginRight="0dp" + android:paddingTop="@dimen/status_bar_padding_top" android:layout_gravity="right|top" android:visibility="invisible" > <ImageView @@ -67,8 +65,6 @@ android:layout_gravity="center_vertical|left" android:src="@drawable/system_animation_ongoing_dot" android:visibility="visible" /> - </FrameLayout> - </com.android.systemui.RegionInterceptingFrameLayout> diff --git a/packages/SystemUI/res/layout/super_notification_shade.xml b/packages/SystemUI/res/layout/super_notification_shade.xml index e02a1767a96c..b28cb2f6f483 100644 --- a/packages/SystemUI/res/layout/super_notification_shade.xml +++ b/packages/SystemUI/res/layout/super_notification_shade.xml @@ -81,6 +81,7 @@ <!-- Keyguard messages --> <LinearLayout + android:id="@+id/keyguard_message_area_container" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index 522fcb299f96..0873a4f9c001 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Hervat"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Instellings"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> deur <xliff:g id="ARTIST_NAME">%2$s</xliff:g> speel tans vanaf <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> van <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Speel"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Maak <xliff:g id="APP_LABEL">%1$s</xliff:g> oop"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Speel <xliff:g id="SONG_NAME">%1$s</xliff:g> deur <xliff:g id="ARTIST_NAME">%2$s</xliff:g> vanaf <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-fi sal vir nou nie outomaties koppel nie"</string> <string name="see_all_networks" msgid="3773666844913168122">"Sien alles"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Ontkoppel Ethernet om netwerke te wissel"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Om toestelervaring te verbeter, kan programme en dienste steeds enige tyd na wi‑fi-netwerke soek, selfs wanneer wi‑fi af is. Jy kan dit in Wi-fi-opsporing-instellings verander. "<annotation id="link">"Verander"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Kies gebruiker"</string> </resources> diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index 432c557dc150..579b5d278588 100644 --- a/packages/SystemUI/res/values-am/strings.xml +++ b/packages/SystemUI/res/values-am/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"ከቆመበት ቀጥል"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"ቅንብሮች"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> በ<xliff:g id="ARTIST_NAME">%2$s</xliff:g> ከ<xliff:g id="APP_LABEL">%3$s</xliff:g> እየተጫወተ ነው"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> ከ<xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"አጫውት"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> ክፈት"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="SONG_NAME">%1$s</xliff:g> በ<xliff:g id="ARTIST_NAME">%2$s</xliff:g> ከ<xliff:g id="APP_LABEL">%3$s</xliff:g> ያጫውቱ"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wifi ለአሁን በራስ-ሰር አይገናኝም"</string> <string name="see_all_networks" msgid="3773666844913168122">"ሁሉንም ይመልከቱ"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"አውታረ መረቦችን ለመቀየር፣ የኢተርኔት ግንኙነት ያቋርጡ"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"የመሣሪያ ተሞክሮን ለማሻሻል፣ መተግበሪያዎች እና አገልግሎቶች አሁንም በማንኛውም ጊዜ የWi-Fi አውታረ መረቦችን መቃኘት ይችላሉ፣ Wi-Fi ጠፍቶ ቢሆንም እንኳ። ይህንን በ Wi‑Fi ቅኝት ቅንብሮች ውስጥ መቀየር ይችላሉ። "<annotation id="link">"ቀይር"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"ተጠቃሚን ይምረጡ"</string> </resources> diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index 2728c980ad73..5875d2b9ebb0 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -1114,6 +1114,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"استئناف التشغيل"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"الإعدادات"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"يتم تشغيل <xliff:g id="SONG_NAME">%1$s</xliff:g> للفنان <xliff:g id="ARTIST_NAME">%2$s</xliff:g> من تطبيق <xliff:g id="APP_LABEL">%3$s</xliff:g>."</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> من إجمالي <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"تشغيل"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"فتح <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"تشغيل <xliff:g id="SONG_NAME">%1$s</xliff:g> للفنان <xliff:g id="ARTIST_NAME">%2$s</xliff:g> من تطبيق <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -1202,5 +1203,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"لن يتم الاتصال بشبكة Wi-Fi تلقائيًا في الوقت الحالي."</string> <string name="see_all_networks" msgid="3773666844913168122">"عرض الكل"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"للتبديل بين الشبكات، يجب فصل إيثرنت."</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"لتحسين تجربتك على الجهاز، يظل بإمكان التطبيقات والخدمات البحث عن شبكات Wi‑Fi في أي وقت، حتى عند إيقاف شبكة Wi‑Fi. وبإمكانك تغيير هذا الخيار في إعدادات البحث عن شبكات Wi-Fi. "<annotation id="link">"تغيير"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"اختيار المستخدم"</string> </resources> diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml index e8158f12ee5a..d6d2900b8d1c 100644 --- a/packages/SystemUI/res/values-as/strings.xml +++ b/packages/SystemUI/res/values-as/strings.xml @@ -24,19 +24,19 @@ <string name="status_bar_no_notifications_title" msgid="7812479124981107507">"কোনো জাননী নাই"</string> <string name="status_bar_ongoing_events_title" msgid="3986169317496615446">"চলিত"</string> <string name="status_bar_latest_events_title" msgid="202755896454005436">"জাননীসমূহ"</string> - <string name="battery_low_title" msgid="6891106956328275225">"বেটাৰি অতি সোনকালে শেষ হ\'ব পাৰে"</string> + <string name="battery_low_title" msgid="6891106956328275225">"বেটাৰী অতি সোনকালে শেষ হ\'ব পাৰে"</string> <string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> বাকী আছে"</string> <string name="battery_low_percent_format_hybrid" msgid="3985614339605686167">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> অৱশিষ্ট আছে, আপোনাৰ ব্যৱহাৰক ভিত্তি কৰি প্ৰায় <xliff:g id="TIME">%2$s</xliff:g> বাকী আছে"</string> <string name="battery_low_percent_format_hybrid_short" msgid="5917433188456218857">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> অৱশিষ্ট আছে, প্ৰায় <xliff:g id="TIME">%2$s</xliff:g> বাকী"</string> - <string name="battery_low_percent_format_saver_started" msgid="4968468824040940688">"<xliff:g id="PERCENTAGE">%s</xliff:g> বাকী আছে। বেটাৰি সঞ্চয়কাৰী অন হৈ আছে।"</string> + <string name="battery_low_percent_format_saver_started" msgid="4968468824040940688">"<xliff:g id="PERCENTAGE">%s</xliff:g> বাকী আছে। বেটাৰী সঞ্চয়কাৰী অন হৈ আছে।"</string> <string name="invalid_charger" msgid="4370074072117767416">"ইউএছবি জৰিয়তে চ্চাৰ্জ কৰিব নোৱাৰি। আপোনাৰ ডিভাইচৰ লগত পোৱা চ্চাৰ্জাৰটো ব্যৱহাৰ কৰক।"</string> <string name="invalid_charger_title" msgid="938685362320735167">"ইউএছবি জৰিয়তে চ্চাৰ্জ কৰিব নোৱাৰি"</string> <string name="invalid_charger_text" msgid="2339310107232691577">"আপোনাৰ ডিভাইচৰ লগত পোৱা চ্চাৰ্জাৰটো ব্যৱহাৰ কৰক।"</string> <string name="battery_low_why" msgid="2056750982959359863">"ছেটিং"</string> - <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"বেটাৰি সঞ্চয়কাৰী অন কৰেনে?"</string> + <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"বেটাৰী সঞ্চয়কাৰী অন কৰেনে?"</string> <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"বেটাৰী সঞ্চয়কাৰীৰ বিষয়ে"</string> <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"অন কৰক"</string> - <string name="battery_saver_start_action" msgid="4553256017945469937">"বেটাৰি সঞ্চয়কাৰী অন কৰক"</string> + <string name="battery_saver_start_action" msgid="4553256017945469937">"বেটাৰী সঞ্চয়কাৰী অন কৰক"</string> <string name="status_bar_settings_settings_button" msgid="534331565185171556">"ছেটিং"</string> <string name="status_bar_settings_wifi_button" msgid="7243072479837270946">"ৱাই-ফাই"</string> <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"স্বয়ং-ঘূৰ্ণন স্ক্ৰীন"</string> @@ -193,11 +193,11 @@ <string name="accessibility_compatibility_zoom_example" msgid="2617218726091234073">"স্ক্ৰীনৰ আকাৰ ডাঙৰ কৰিবলৈ জুম কৰক।"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ব্লুটুথ সংযোগ হ’ল।"</string> <string name="accessibility_bluetooth_disconnected" msgid="7195823280221275929">"ব্লুটুথ সংযোগ বিচ্ছিন্ন কৰা হ’ল।"</string> - <string name="accessibility_no_battery" msgid="3789287732041910804">"বেটাৰি শেষ"</string> - <string name="accessibility_battery_one_bar" msgid="8868347318237585329">"বেটাৰিৰ এডাল দণ্ড।"</string> - <string name="accessibility_battery_two_bars" msgid="7895789999668425551">"বেটাৰিৰ দুডাল দণ্ড।"</string> - <string name="accessibility_battery_three_bars" msgid="118341923832368291">"বেটাৰিৰ তিনিডাল দণ্ড।"</string> - <string name="accessibility_battery_full" msgid="1480463938961288494">"বেটাৰি পূৰাকৈ চ্চাৰ্জ হৈছে।"</string> + <string name="accessibility_no_battery" msgid="3789287732041910804">"বেটাৰী শেষ"</string> + <string name="accessibility_battery_one_bar" msgid="8868347318237585329">"বেটাৰীৰ এডাল দণ্ড।"</string> + <string name="accessibility_battery_two_bars" msgid="7895789999668425551">"বেটাৰীৰ দুডাল দণ্ড।"</string> + <string name="accessibility_battery_three_bars" msgid="118341923832368291">"বেটাৰীৰ তিনিডাল দণ্ড।"</string> + <string name="accessibility_battery_full" msgid="1480463938961288494">"বেটাৰী পূৰাকৈ চাৰ্জ হৈছে।"</string> <string name="accessibility_battery_unknown" msgid="1807789554617976440">"বেটাৰীৰ চাৰ্জৰ শতাংশ অজ্ঞাত।"</string> <string name="accessibility_wifi_name" msgid="4863440268606851734">"<xliff:g id="WIFI">%s</xliff:g>ৰ লগত সংযোগ কৰা হ’ল।"</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>ৰ লগত সংযোগ কৰা হ’ল।"</string> @@ -229,10 +229,10 @@ <string name="accessibility_airplane_mode" msgid="1899529214045998505">"এয়াৰপ্লে’ন ম’ড।"</string> <string name="accessibility_vpn_on" msgid="8037549696057288731">"ভিপিএন অন অৱস্থাত আছে।"</string> <string name="accessibility_no_sims" msgid="5711270400476534667">"কোনো ছিম কাৰ্ড নাই"</string> - <string name="accessibility_battery_details" msgid="6184390274150865789">"বেটাৰিৰ বিৱৰণসমূহ খোলক"</string> - <string name="accessibility_battery_level" msgid="5143715405241138822">"<xliff:g id="NUMBER">%d</xliff:g> শতাংশ বেটাৰি।"</string> + <string name="accessibility_battery_details" msgid="6184390274150865789">"বেটাৰীৰ বিৱৰণসমূহ খোলক"</string> + <string name="accessibility_battery_level" msgid="5143715405241138822">"<xliff:g id="NUMBER">%d</xliff:g> শতাংশ বেটাৰী।"</string> <string name="accessibility_battery_level_with_estimate" msgid="4843119982547599452">"আপোনাৰ ব্যৱহাৰৰ ওপৰত ভিত্তি কৰি বেটাৰী <xliff:g id="PERCENTAGE">%1$s</xliff:g> শতাংশ, প্ৰায় <xliff:g id="TIME">%2$s</xliff:g> বাকী আছে"</string> - <string name="accessibility_battery_level_charging" msgid="8892191177774027364">"বেটাৰি চাৰ্জ হৈ আছে, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> শতাংশ।"</string> + <string name="accessibility_battery_level_charging" msgid="8892191177774027364">"বেটাৰী চাৰ্জ হৈ আছে, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> শতাংশ।"</string> <string name="accessibility_settings_button" msgid="2197034218538913880">"ছিষ্টেমৰ ছেটিং৷"</string> <string name="accessibility_notifications_button" msgid="3960913924189228831">"জাননীসমূহ।"</string> <string name="accessibility_overflow_action" msgid="8555835828182509104">"সকলো জাননীবোৰ চাওক"</string> @@ -258,7 +258,7 @@ <string name="accessibility_quick_settings_wifi_changed_off" msgid="2230487165558877262">"ৱাই-ফাই অফ কৰা হ’ল।"</string> <string name="accessibility_quick_settings_wifi_changed_on" msgid="1490362586009027611">"ৱাই-ফাই অন কৰা হ’ল।"</string> <string name="accessibility_quick_settings_mobile" msgid="1817825313718492906">"ম’বাইল <xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="TYPE">%2$s</xliff:g>. <xliff:g id="NETWORK">%3$s</xliff:g>."</string> - <string name="accessibility_quick_settings_battery" msgid="533594896310663853">"বেটাৰি <xliff:g id="STATE">%s</xliff:g>।"</string> + <string name="accessibility_quick_settings_battery" msgid="533594896310663853">"বেটাৰী <xliff:g id="STATE">%s</xliff:g>।"</string> <string name="accessibility_quick_settings_airplane_off" msgid="1275658769368793228">"এয়াৰপ্লেইন ম\'ড অফ হৈ আছে৷"</string> <string name="accessibility_quick_settings_airplane_on" msgid="8106176561295294255">"এয়াৰপ্লেইন ম\'ড অন হৈ আছে৷"</string> <string name="accessibility_quick_settings_airplane_changed_off" msgid="8880183481476943754">"এয়াৰপ্লেইন ম\'ড অফ কৰা হ’ল।"</string> @@ -338,7 +338,7 @@ <string name="quick_settings_bluetooth_multiple_devices_label" msgid="6595808498429809855">"ব্লুটুথ (<xliff:g id="NUMBER">%d</xliff:g>টা ডিভাইচ)"</string> <string name="quick_settings_bluetooth_off_label" msgid="6375098046500790870">"ব্লুটুথ বন্ধ অৱস্থাত আছে"</string> <string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"কোনো যোৰা লগোৱা ডিভাইচ উপলব্ধ নহয়।"</string> - <string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"বেটাৰি <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string> + <string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"বেটাৰী <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string> <string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"অডিঅ’"</string> <string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"হেডছেট"</string> <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"ইনপুট"</string> @@ -391,7 +391,7 @@ <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> - <string name="quick_settings_connected_battery_level" msgid="1322075669498906959">"সংযুক্ত, বেটাৰি <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> + <string name="quick_settings_connected_battery_level" msgid="1322075669498906959">"সংযুক্ত, বেটাৰী <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> <string name="quick_settings_connecting" msgid="2381969772953268809">"সংযোগ কৰি থকা হৈছে..."</string> <string name="quick_settings_tethering_label" msgid="5257299852322475780">"টেডাৰ কৰি থকা হৈছে"</string> <string name="quick_settings_hotspot_label" msgid="1199196300038363424">"হটস্পট"</string> @@ -504,9 +504,9 @@ <string name="user_remove_user_title" msgid="9124124694835811874">"ব্যৱহাৰকাৰীক আঁতৰাবনে?"</string> <string name="user_remove_user_message" msgid="6702834122128031833">"এই ব্যৱহাৰকাৰীৰ সকলো এপ্ আৰু ডেটা মচা হ\'ব।"</string> <string name="user_remove_user_remove" msgid="8387386066949061256">"আঁতৰাওক"</string> - <string name="battery_saver_notification_title" msgid="8419266546034372562">"বেটাৰি সঞ্চয়কাৰী অন হৈ আছে"</string> + <string name="battery_saver_notification_title" msgid="8419266546034372562">"বেটাৰী সঞ্চয়কাৰী অন হৈ আছে"</string> <string name="battery_saver_notification_text" msgid="2617841636449016951">"কাৰ্যদক্ষতা আৰু নেপথ্য ডেটা হ্ৰাস কৰে"</string> - <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"বেটাৰি সঞ্চয়কাৰী অফ কৰক"</string> + <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"বেটাৰী সঞ্চয়কাৰী অফ কৰক"</string> <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>এ আপোনাৰ স্ক্ৰীনত দৃশ্যমান হোৱা অথবা ৰেকর্ডিং অথবা কাষ্টিঙৰ সময়ত আপোনাৰ ডিভাইচত প্লে\' কৰা সকলো তথ্যলৈ এক্সেছ পাব। এইটোত পাছৱর্ড, পৰিশোধৰ সবিশেষ, ফট\', বার্তাসমূহ আৰু আপুনি প্লে\' কৰা অডিঅ\'ৰ দৰে তথ্য অন্তর্ভুক্ত হয়।"</string> <string name="media_projection_dialog_service_text" msgid="958000992162214611">"এই সুবিধাটো প্ৰদান কৰা সেৱাটোৱে আপোনাৰ স্ক্ৰীনত দৃশ্যমান হোৱা অথবা ৰেকর্ডিং অথবা কাষ্টিংৰ সময়ত আপোনাৰ ডিভাইচত প্লে\' কৰা সকলো তথ্যলৈ এক্সেছ পাব। এইটোত পাছৱর্ড, পৰিশোধৰ সবিশেষ, ফট\', বার্তাসমূহ আৰু আপুনি প্লে\' কৰা অডিঅ\'ৰ দৰে তথ্য অন্তর্ভুক্ত হয়।"</string> <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"ৰেকর্ডিং অথবা কাষ্টিং আৰম্ভ কৰিবনে?"</string> @@ -657,8 +657,8 @@ <string name="output_service_wifi" msgid="9003667810868222134">"ৱাই-ফাই"</string> <string name="output_service_bt_wifi" msgid="7186882540475524124">"ব্লুটুথ আৰু ৱাই-ফাই"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"System UI Tuner"</string> - <string name="show_battery_percentage" msgid="6235377891802910455">"সংযুক্ত বেটাৰিৰ কিমান শতাংশ বাকী আছে দেখুওৱাক"</string> - <string name="show_battery_percentage_summary" msgid="9053024758304102915">"চাৰ্জ হৈ নথকা অৱস্থাত বেটাৰি কিমান শতাংশ বাকী স্থিতি দণ্ডৰ ভিতৰত দেখুৱাওক"</string> + <string name="show_battery_percentage" msgid="6235377891802910455">"সংযুক্ত বেটাৰীৰ কিমান শতাংশ বাকী আছে দেখুওৱাক"</string> + <string name="show_battery_percentage_summary" msgid="9053024758304102915">"চাৰ্জ হৈ নথকা অৱস্থাত বেটাৰী কিমান শতাংশ বাকী স্থিতি দণ্ডৰ ভিতৰত দেখুৱাওক"</string> <string name="quick_settings" msgid="6211774484997470203">"ক্ষিপ্ৰ ছেটিং"</string> <string name="status_bar" msgid="4357390266055077437">"স্থিতি দণ্ড"</string> <string name="overview" msgid="3522318590458536816">"অৱলোকন"</string> @@ -696,7 +696,7 @@ <string name="remove_from_settings_prompt" msgid="551565437265615426">"ছেটিঙৰ পৰা System UI Tuner আঁতৰাই ইয়াৰ সুবিধাসমূহ ব্যৱহাৰ কৰাটো বন্ধ কৰিবনে?"</string> <string name="activity_not_found" msgid="8711661533828200293">"আপোনাৰ ডিভাইচত এপ্লিকেশ্বনটো ইনষ্টল কৰা হোৱা নাই"</string> <string name="clock_seconds" msgid="8709189470828542071">"ঘড়ীৰ ছেকেণ্ড দেখুৱাওক"</string> - <string name="clock_seconds_desc" msgid="2415312788902144817">"স্থিতি দণ্ডত ঘড়ীৰ ছেকেণ্ড দেখুৱাওক। এই কার্যই বেটাৰিৰ অৱস্থাত প্ৰভাৱ পেলাব পাৰে।"</string> + <string name="clock_seconds_desc" msgid="2415312788902144817">"স্থিতি দণ্ডত ঘড়ীৰ ছেকেণ্ড দেখুৱাওক। এই কার্যই বেটাৰীৰ জীৱনকালত প্ৰভাৱ পেলাব পাৰে।"</string> <string name="qs_rearrange" msgid="484816665478662911">"ক্ষিপ্ৰ ছেটিং পুনৰ সজাওক"</string> <string name="show_brightness" msgid="6700267491672470007">"দ্ৰুত ছেটিঙত উজ্জ্বলতা দেখুৱাওক"</string> <string name="experimental" msgid="3549865454812314826">"পৰীক্ষামূলক"</string> @@ -802,8 +802,8 @@ <item quantity="one"> %d মিনিট</item> <item quantity="other"> %d মিনিট</item> </plurals> - <string name="battery_panel_title" msgid="5931157246673665963">"বেটাৰিৰ ব্যৱহাৰ"</string> - <string name="battery_detail_charging_summary" msgid="8821202155297559706">"চ্চাৰ্জ কৰি থকাৰ সময়ত বেটাৰি সঞ্চয়কাৰী উপলব্ধ নহয়।"</string> + <string name="battery_panel_title" msgid="5931157246673665963">"বেটাৰীৰ ব্যৱহাৰ"</string> + <string name="battery_detail_charging_summary" msgid="8821202155297559706">"চাৰ্জ কৰি থকাৰ সময়ত বেটাৰী সঞ্চয়কাৰী উপলব্ধ নহয়।"</string> <string name="battery_detail_switch_title" msgid="6940976502957380405">"বেটাৰী সঞ্চয়কাৰী"</string> <string name="battery_detail_switch_summary" msgid="3668748557848025990">"কাৰ্যদক্ষতা আৰু নেপথ্য ডেটা হ্ৰাস কৰে"</string> <string name="keyboard_key_button_template" msgid="8005673627272051429">"<xliff:g id="NAME">%1$s</xliff:g> বুটাম"</string> @@ -853,7 +853,7 @@ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"অসুবিধা নিদিব"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"ভলিউম বুটামসমূহৰ শ্বৰ্টকাট"</string> <string name="volume_up_silent" msgid="1035180298885717790">"ভলিউম বঢ়োৱা বুটাম ব্যৱহাৰ কৰি অসুবিধা নিদিব নিষ্ক্ৰিয় কৰক"</string> - <string name="battery" msgid="769686279459897127">"বেটাৰি"</string> + <string name="battery" msgid="769686279459897127">"বেটাৰী"</string> <string name="clock" msgid="8978017607326790204">"ঘড়ী"</string> <string name="headset" msgid="4485892374984466437">"হেডছেট"</string> <string name="accessibility_long_click_tile" msgid="210472753156768705">"ছেটিং খোলক"</string> @@ -962,7 +962,7 @@ <string name="tuner_menu" msgid="363690665924769420">"মেনু"</string> <string name="tuner_app" msgid="6949280415826686972">"<xliff:g id="APP">%1$s</xliff:g> এপ্"</string> <string name="notification_channel_alerts" msgid="3385787053375150046">"সতৰ্কবার্তাসমূহ"</string> - <string name="notification_channel_battery" msgid="9219995638046695106">"বেটাৰি"</string> + <string name="notification_channel_battery" msgid="9219995638046695106">"বেটাৰী"</string> <string name="notification_channel_screenshot" msgid="7665814998932211997">"স্ক্ৰীণশ্বটসমূহ"</string> <string name="notification_channel_general" msgid="4384774889645929705">"সাধাৰণ বার্তাসমূহ"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"ষ্ট\'ৰেজ"</string> @@ -986,7 +986,7 @@ <string name="qs_dnd_keep" msgid="3829697305432866434">"Keep"</string> <string name="qs_dnd_replace" msgid="7712119051407052689">"সলনি কৰক"</string> <string name="running_foreground_services_title" msgid="5137313173431186685">"নেপথ্যত চলি থকা এপসমূহ"</string> - <string name="running_foreground_services_msg" msgid="3009459259222695385">"বেটাৰি আৰু ডেটাৰ ব্যৱহাৰৰ বিষয়ে বিশদভাৱে জানিবলৈ টিপক"</string> + <string name="running_foreground_services_msg" msgid="3009459259222695385">"বেটাৰী আৰু ডেটাৰ ব্যৱহাৰৰ বিষয়ে সবিশেষ জানিবলৈ টিপক"</string> <string name="mobile_data_disable_title" msgid="5366476131671617790">"ম’বাইল ডেটা অফ কৰিবনে?"</string> <string name="mobile_data_disable_message" msgid="8604966027899770415">"আপুনি <xliff:g id="CARRIER">%s</xliff:g>ৰ জৰিয়তে ডেটা সংযোগ বা ইণ্টাৰনেট সংযোগ নাপাব। কেৱল ৱাই-ফাইৰ যোগেৰে ইণ্টাৰনেট উপলব্ধ হ\'ব।"</string> <string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"আপোনাৰ বাহক"</string> @@ -997,11 +997,11 @@ <string name="slice_permission_checkbox" msgid="4242888137592298523">"<xliff:g id="APP">%1$s</xliff:g>ক যিকোনো এপৰ অংশ দেখুওৱাবলৈ অনুমতি দিয়ক"</string> <string name="slice_permission_allow" msgid="6340449521277951123">"অনুমতি দিয়ক"</string> <string name="slice_permission_deny" msgid="6870256451658176895">"অস্বীকাৰ কৰক"</string> - <string name="auto_saver_title" msgid="6873691178754086596">"বেটাৰি সঞ্চয়কাৰীৰ সময়সূচী সক্ৰিয় কৰিবলৈ টিপক"</string> - <string name="auto_saver_text" msgid="3214960308353838764">"বেটাৰি শেষ হোৱাৰ সম্ভাৱনা থাকিলে অন কৰক"</string> + <string name="auto_saver_title" msgid="6873691178754086596">"বেটাৰী সঞ্চয়কাৰীৰ সময়সূচী সক্ৰিয় কৰিবলৈ টিপক"</string> + <string name="auto_saver_text" msgid="3214960308353838764">"বেটাৰী শেষ হোৱাৰ সম্ভাৱনা থাকিলে অন কৰক"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"নালাগে, ধন্যবাদ"</string> - <string name="auto_saver_enabled_title" msgid="4294726198280286333">"বেটাৰি সঞ্চয়কাৰীৰ সময়সূচী অন কৰা অৱস্থাত আছে"</string> - <string name="auto_saver_enabled_text" msgid="7889491183116752719">"বেটাৰি চ্চাৰ্জৰ স্তৰ <xliff:g id="PERCENTAGE">%d</xliff:g>%%তকৈ কম হোৱাৰ লগে লগে বেটাৰি সঞ্চয়কাৰী স্বয়ংক্ৰিয়ভাৱে অন হ’ব।"</string> + <string name="auto_saver_enabled_title" msgid="4294726198280286333">"বেটাৰী সঞ্চয়কাৰীৰ সময়সূচী অন কৰা অৱস্থাত আছে"</string> + <string name="auto_saver_enabled_text" msgid="7889491183116752719">"বেটাৰী চাৰ্জৰ স্তৰ <xliff:g id="PERCENTAGE">%d</xliff:g>%%তকৈ কম হোৱাৰ লগে লগে বেটাৰী সঞ্চয়কাৰী স্বয়ংক্ৰিয়ভাৱে অন হ’ব।"</string> <string name="open_saver_setting_action" msgid="2111461909782935190">"ছেটিং"</string> <string name="auto_saver_okay_action" msgid="7815925750741935386">"বুজি পালোঁ"</string> <string name="heap_dump_tile_name" msgid="2464189856478823046">"SysUI হীপ ডাম্প কৰক"</string> @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"পুনৰ আৰম্ভ কৰক"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"ছেটিং"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g>ত <xliff:g id="ARTIST_NAME">%2$s</xliff:g>ৰ <xliff:g id="SONG_NAME">%1$s</xliff:g> গীতটো প্লে’ হৈ আছে"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g>ৰ <xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"প্লে’ কৰক"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> খোলক"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="APP_LABEL">%3$s</xliff:g>ত <xliff:g id="ARTIST_NAME">%2$s</xliff:g>ৰ <xliff:g id="SONG_NAME">%1$s</xliff:g> গীতটো প্লে’ কৰক"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"এতিয়া ৱাই-ফাই স্বয়ংক্ৰিয়ভাৱে সংযুক্ত নহ’ব"</string> <string name="see_all_networks" msgid="3773666844913168122">"আটাইবোৰ চাওক"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"নেটৱৰ্ক সলনি কৰিবলৈ ইথাৰনেটৰ পৰা সংযোগ বিচ্ছিন্ন কৰক"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"ডিভাইচ ব্যৱহাৰৰ অভিজ্ঞতা উন্নত কৰিবলৈ ৱাই-ফাই অফ থকা অৱস্থাতো এপ্ আৰু সেৱাসমূহে ৱাই-ফাই নেটৱৰ্কবোৰ স্কেন কৰিব পাৰে। আপুনি ৱাই-ফাই স্কেনিঙৰ ছেটিঙত এইটো সলনি কৰিব পাৰে। "<annotation id="link">"সলনি কৰক"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"ব্যৱহাৰকাৰী বাছনি কৰক"</string> </resources> diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml index 02032883f9f0..a23283437a7f 100644 --- a/packages/SystemUI/res/values-az/strings.xml +++ b/packages/SystemUI/res/values-az/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Davam edin"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Ayarlar"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> tərəfindən <xliff:g id="SONG_NAME">%1$s</xliff:g> <xliff:g id="APP_LABEL">%3$s</xliff:g> tətbiqindən oxudulur"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g>/<xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Oxudun"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> tətbiqini açın"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> tərəfindən <xliff:g id="SONG_NAME">%1$s</xliff:g> mahnısını <xliff:g id="APP_LABEL">%3$s</xliff:g> tətbiqindən oxudun"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi hələlik avtomatik qoşulmayacaq"</string> <string name="see_all_networks" msgid="3773666844913168122">"Hamısına baxın"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Şəbəkəni dəyişmək üçün etherneti ayırın"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Cihaz təcrübəsini yaxşılaşdırmaq üçün Wi-Fi deaktiv olduqda belə, tətbiqlər və xidmətlər Wi-Fi şəbəkəsini axtara biləcək. Bunu Wi-Fi axtarışı ayarlarında dəyişə bilərsiniz. "<annotation id="link">"Dəyişin"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"İstifadəçi seçin"</string> </resources> diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml index 60dee9e31fd8..caab5543aded 100644 --- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml +++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml @@ -1096,6 +1096,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Nastavi"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Podešavanja"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> izvođača <xliff:g id="ARTIST_NAME">%2$s</xliff:g> se pušta iz aplikacije <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> od <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Pusti"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Otvorite <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Pustite <xliff:g id="SONG_NAME">%1$s</xliff:g> izvođača <xliff:g id="ARTIST_NAME">%2$s</xliff:g> iz aplikacije <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -1184,5 +1185,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"WiFi trenutno ne može da se automatski poveže"</string> <string name="see_all_networks" msgid="3773666844913168122">"Pogledajte sve"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Da biste promenili mrežu, prekinite eternet vezu"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Radi boljeg doživljaja uređaja, aplikacije i usluge i dalje mogu da traže WiFi mreže u bilo kom trenutku, čak i kada je WiFi isključen. To možete da promenite u podešavanjima WiFi skeniranja. "<annotation id="link">"Promenite"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Izaberite korisnika"</string> </resources> diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml index f234be4b020a..d327b4deb4e2 100644 --- a/packages/SystemUI/res/values-be/strings.xml +++ b/packages/SystemUI/res/values-be/strings.xml @@ -1102,6 +1102,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Узнавіць"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Налады"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"У праграме \"<xliff:g id="APP_LABEL">%3$s</xliff:g>\" прайграецца кампазіцыя \"<xliff:g id="SONG_NAME">%1$s</xliff:g>\", выканаўца – <xliff:g id="ARTIST_NAME">%2$s</xliff:g>"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> з <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Прайграць"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Адкрыйце праграму \"<xliff:g id="APP_LABEL">%1$s</xliff:g>\""</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Прайграйце кампазіцыю \"<xliff:g id="SONG_NAME">%1$s</xliff:g>\" (выканаўца – <xliff:g id="ARTIST_NAME">%2$s</xliff:g>) з дапамогай праграмы \"<xliff:g id="APP_LABEL">%3$s</xliff:g>\""</string> @@ -1190,5 +1191,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Аўтаматычнае падключэнне да Wi-Fi адсутнічае"</string> <string name="see_all_networks" msgid="3773666844913168122">"Паказаць усе"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Каб падключыцца да сетак, выключыце Ethernet"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Каб палепшыць працу прылады, вы можаце дазволіць праграмам і сэрвісам шукаць сеткі Wi-Fi, нават калі Wi‑Fi выключаны. Змяніць гэты рэжым можна ў наладах пошуку сетак Wi-Fi. "<annotation id="link">"Змяніць"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Выбар карыстальніка"</string> </resources> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index 170a565419d3..42b80f4aceae 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Възобновяване"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Настройки"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> на <xliff:g id="ARTIST_NAME">%2$s</xliff:g> се възпроизвежда от <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> от <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Google Play"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Отваряне на <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Пускане на <xliff:g id="SONG_NAME">%1$s</xliff:g> на <xliff:g id="ARTIST_NAME">%2$s</xliff:g> от <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Засега Wi-Fi няма да се свързва автоматично"</string> <string name="see_all_networks" msgid="3773666844913168122">"Вижте всички"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"За да превключите мрежите, прекъснете връзката с Ethernet"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"С цел подобряване на практическата работа с устройството приложенията и услугите пак могат да сканират за Wi‑Fi мрежи по всяко време дори когато функцията за Wi‑Fi e изключена. Можете да промените съответното поведение от настройките за сканиране за Wi‑Fi. "<annotation id="link">"Промяна"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Избор на потребител"</string> </resources> diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml index f4b1935bfe7d..5b8c662213af 100644 --- a/packages/SystemUI/res/values-bn/strings.xml +++ b/packages/SystemUI/res/values-bn/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"আবার চালু করুন"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"সেটিংস"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g>-এর <xliff:g id="SONG_NAME">%1$s</xliff:g> গানটি <xliff:g id="APP_LABEL">%3$s</xliff:g> অ্যাপে চলছে"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g>টির মধ্যে <xliff:g id="ELAPSED_TIME">%1$s</xliff:g>টি"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"চালান"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> অ্যাপ খুলুন"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g>-এর <xliff:g id="SONG_NAME">%1$s</xliff:g> গানটি <xliff:g id="APP_LABEL">%3$s</xliff:g> অ্যাপে চালান"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"এখন ওয়াই-ফাই নিজে থেকে কানেক্ট হবে না"</string> <string name="see_all_networks" msgid="3773666844913168122">"সবকটি দেখুন"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"নেটওয়ার্ক বদলাতে ইথারনেট ডিসকানেক্ট করুন"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"ডিভাইস সংক্রান্ত অভিজ্ঞতা আরও ভাল করতে, অ্যাপ ও পরিষেবা যেকোনও সময় আপনার ওয়াই-ফাই নেটওয়ার্ক স্ক্যান করতে পারবে, এমনকি ডিভাইসের ওয়াই-ফাই বন্ধ করা থাকলেও। ওয়াই-ফাই স্ক্যানিং সেটিংস থেকে আপনি এটি পরিবর্তন করতে পারবেন। "<annotation id="link">"পরিবর্তন করুন"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"ব্যবহারকারী বেছে নিন"</string> </resources> diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml index 4f5db012b0e9..19e868f5e6ea 100644 --- a/packages/SystemUI/res/values-bs/strings.xml +++ b/packages/SystemUI/res/values-bs/strings.xml @@ -1096,6 +1096,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Nastavi"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Postavke"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Pjesma <xliff:g id="SONG_NAME">%1$s</xliff:g> izvođača <xliff:g id="ARTIST_NAME">%2$s</xliff:g> se reproducira pomoću aplikacije <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> od <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Pokrenite"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Otvorite aplikaciju <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Reproducirajte pjesmu <xliff:g id="SONG_NAME">%1$s</xliff:g> izvođača <xliff:g id="ARTIST_NAME">%2$s</xliff:g> pomoću aplikacije <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -1184,5 +1185,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"WiFi se trenutno ne može automatski povezati"</string> <string name="see_all_networks" msgid="3773666844913168122">"Prikaži sve"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Da promijenite mrežu, isključite ethernet"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Radi poboljšanja iskustva s uređajem aplikacije i usluge i dalje mogu bilo kada skenirati WiFi mreže, čak i kada je WiFi isključen. Ovo možete promijeniti u Postavkama skeniranja WiFi mreže. "<annotation id="link">"Promijeni"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Odaberite korisnika"</string> </resources> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index ace47913916e..f31a72dad3a3 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Reprèn"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Configuració"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> (<xliff:g id="ARTIST_NAME">%2$s</xliff:g>) s\'està reproduint des de l\'aplicació <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> de <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Reprodueix"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Obre <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Reprodueix <xliff:g id="SONG_NAME">%1$s</xliff:g> (<xliff:g id="ARTIST_NAME">%2$s</xliff:g>) des de l\'aplicació <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Per ara la Wi‑Fi no es connectarà automàticament"</string> <string name="see_all_networks" msgid="3773666844913168122">"Mostra-ho tot"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Per canviar de xarxa, desconnecta la connexió Ethernet"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Per millorar l\'experiència del dispositiu, les aplicacions i els serveis poden cercar xarxes Wi‑Fi en qualsevol moment, fins i tot quan la Wi‑Fi estigui desactivada. Pots canviar aquesta opció a la configuració de cerca de xarxes Wi‑Fi. "<annotation id="link">"Canvia-la"</annotation>"."</string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Selecciona un usuari"</string> </resources> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index f4c055d18959..05e4b1ec0207 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -716,7 +716,7 @@ <string name="tuner_full_importance_settings" msgid="1388025816553459059">"Rozšířené ovládací prvky oznámení"</string> <string name="tuner_full_importance_settings_on" msgid="917981436602311547">"Zapnuto"</string> <string name="tuner_full_importance_settings_off" msgid="5580102038749680829">"Vypnuto"</string> - <string name="power_notification_controls_description" msgid="1334963837572708952">"Rozšířené ovládací prvky oznámení umožňují nastavit úroveň důležitosti oznámení aplikace od 0 do 5. \n\n"<b>"Úroveň 5"</b>" \n– Zobrazit na začátku seznamu oznámení \n– Povolit vyrušení na celou obrazovku \n– Vždy zobrazit náhled \n\n"<b>"Úroveň 4"</b>" \n– Zabránit vyrušení na celou obrazovku \n– Vždy zobrazit náhled \n\n"<b>"Úroveň 3"</b>" \n– Zabránit vyrušení na celou obrazovku \n– Nikdy nezobrazovat náhled \n\n"<b>"Úroveň 2"</b>" \n– Zabránit vyrušení na celou obrazovku \n– Nikdy nezobrazovat náhled \n– Nikdy nevydávat žádný zvukový signál ani nevibrovat \n\n"<b>"Úroveň 1"</b>" \n– Zabránit vyrušení na celou obrazovku \n– Nikdy nezobrazovat náhled \n– Nikdy nevydávat zvukový signál ani nevibrovat \n– Skrýt z obrazovky uzamčení a stavového řádku \n– Zobrazovat na konci seznamu oznámení \n\n"<b>";Úroveň 0"</b>" \n– Blokovat všechna oznámení z aplikace"</string> + <string name="power_notification_controls_description" msgid="1334963837572708952">"Rozšířené ovládací prvky oznámení umožňují nastavit úroveň důležitosti oznámení aplikace od 0 do 5. \n\n"<b>"Úroveň 5"</b>" \n– Zobrazit na začátku seznamu oznámení \n– Povolit vyrušení na celou obrazovku \n– Vždy zobrazit náhled \n\n"<b>"Úroveň 4"</b>" \n– Zabránit vyrušení na celou obrazovku \n– Vždy zobrazit náhled \n\n"<b>"Úroveň 3"</b>" \n– Zabránit vyrušení na celou obrazovku \n– Nikdy nezobrazovat náhled \n\n"<b>"Úroveň 2"</b>" \n– Zabránit vyrušení na celou obrazovku \n– Nikdy nezobrazovat náhled \n– Nikdy nevydávat žádný zvukový signál ani nevibrovat \n\n"<b>"Úroveň 1"</b>" \n– Zabránit vyrušení na celou obrazovku \n– Nikdy nezobrazovat náhled \n– Nikdy nevydávat zvukový signál ani nevibrovat \n– Skrýt na obrazovce uzamčení a stavového řádku \n– Zobrazovat na konci seznamu oznámení \n\n"<b>";Úroveň 0"</b>" \n– Blokovat všechna oznámení z aplikace"</string> <string name="notification_header_default_channel" msgid="225454696914642444">"Oznámení"</string> <string name="notification_channel_disabled" msgid="928065923928416337">"Tato oznámení již nebudete dostávat"</string> <string name="notification_channel_minimized" msgid="6892672757877552959">"Tato oznámení budou minimalizována"</string> @@ -1102,6 +1102,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Pokračovat"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Nastavení"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Skladba <xliff:g id="SONG_NAME">%1$s</xliff:g> od interpreta <xliff:g id="ARTIST_NAME">%2$s</xliff:g> hrajte z aplikace <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> z <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Přehrát"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Otevřít aplikaci <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Přehrát skladbu <xliff:g id="SONG_NAME">%1$s</xliff:g> od interpreta <xliff:g id="ARTIST_NAME">%2$s</xliff:g> z aplikace <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -1190,5 +1191,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi se prozatím nebude připojovat automaticky"</string> <string name="see_all_networks" msgid="3773666844913168122">"Zobrazit vše"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Pokud chcete přepnout sítě, odpojte ethernet"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Za účelem lepšího fungování zařízení mohou aplikace a služby vyhledávat sítě Wi-Fi, i když je připojení Wi-Fi vypnuté. Toto chování můžete změnit v nastavení vyhledávání Wi-Fi. "<annotation id="link">"Změnit"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Zvolte uživatele"</string> </resources> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index 3a6030e6b7fb..8145ffa2de46 100644 --- a/packages/SystemUI/res/values-da/strings.xml +++ b/packages/SystemUI/res/values-da/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Genoptag"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Indstillinger"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> af <xliff:g id="ARTIST_NAME">%2$s</xliff:g> afspilles via <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> af <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Afspil"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Åbn <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Afspil <xliff:g id="SONG_NAME">%1$s</xliff:g> af <xliff:g id="ARTIST_NAME">%2$s</xliff:g> via <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Ingen automatisk forbindelse til Wi-Fi i øjeblikket"</string> <string name="see_all_networks" msgid="3773666844913168122">"Se alle"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Afbryd ethernetforbindelsen for at skifte netværk"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"For at forbedre brugeroplevelsen på enheden kan apps og tjenester stadig til enhver tid scanne efter Wi‑Fi-netværk, også selvom Wi‑Fi er deaktiveret. Du kan ændre dette i indstillingerne for Wi-Fi-scanning. "<annotation id="link">"Skift indstilling"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Vælg bruger"</string> </resources> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index be501ca32eb1..fc36c84914f8 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Fortsetzen"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Einstellungen"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> von <xliff:g id="ARTIST_NAME">%2$s</xliff:g> wird gerade über <xliff:g id="APP_LABEL">%3$s</xliff:g> wiedergegeben"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> von <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Wiedergeben"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> öffnen"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="SONG_NAME">%1$s</xliff:g> von <xliff:g id="ARTIST_NAME">%2$s</xliff:g> über <xliff:g id="APP_LABEL">%3$s</xliff:g> wiedergeben"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Zurzeit wird keine automatische WLAN-Verbindung hergestellt"</string> <string name="see_all_networks" msgid="3773666844913168122">"Alle ansehen"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Trenne das Ethernetkabel, um das Netzwerk zu wechseln"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Zur Verbesserung der Gerätenutzung können Apps und Dienste weiter nach WLANs suchen, auch wenn die WLAN-Funktion deaktiviert ist. Dies lässt sich in den Einstellungen für die WLAN-Suche ändern. "<annotation id="link">"Ändern"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Nutzer auswählen"</string> </resources> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index 145c72d3d83c..a93fec5d25f6 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Συνέχιση"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Ρυθμίσεις"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Γίνεται αναπαραγωγή του <xliff:g id="SONG_NAME">%1$s</xliff:g> από <xliff:g id="ARTIST_NAME">%2$s</xliff:g> στην εφαρμογή <xliff:g id="APP_LABEL">%3$s</xliff:g>."</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> από <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Play"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Άνοιγμα της εφαρμογής <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Αναπαραγωγή του <xliff:g id="SONG_NAME">%1$s</xliff:g> από <xliff:g id="ARTIST_NAME">%2$s</xliff:g> στην εφαρμογή <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Δεν θα γίνεται προς το παρόν αυτόματη σύνδεση Wi-Fi."</string> <string name="see_all_networks" msgid="3773666844913168122">"Εμφάνιση όλων"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Για εναλλαγή δικτύων, αποσυνδέστε το ethernet"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Για βελτίωση της εμπειρίας στη συσκευή, οι εφαρμογές και οι υπηρεσίες μπορούν ακόμα να εκτελούν σάρωση για δίκτυα Wi‑Fi ανά πάσα στιγμή, ακόμα και όταν το Wi‑Fi είναι απενεργοποιημένο. Μπορείτε να αλλάξετε αυτήν τη ρύθμιση στις ρυθμίσεις της Σάρωσης Wi‑Fi. "<annotation id="link">"Αλλαγή"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Επιλογή χρήστη"</string> </resources> diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml index 590033a632dc..2f4a17d07b62 100644 --- a/packages/SystemUI/res/values-en-rAU/strings.xml +++ b/packages/SystemUI/res/values-en-rAU/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Resume"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Settings"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> by <xliff:g id="ARTIST_NAME">%2$s</xliff:g> is playing from <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> of <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Play"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Open <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Play <xliff:g id="SONG_NAME">%1$s</xliff:g> by <xliff:g id="ARTIST_NAME">%2$s</xliff:g> from <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi‑Fi won’t auto-connect for now"</string> <string name="see_all_networks" msgid="3773666844913168122">"See all"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"To switch networks, disconnect Ethernet"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"To improve device experience, apps and services can still scan for Wi‑Fi networks at any time, even when Wi‑Fi is off. You can change this in Wi‑Fi scanning settings. "<annotation id="link">"Change"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Select user"</string> </resources> diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml index ca7099fcc4cd..e1ab43a00da4 100644 --- a/packages/SystemUI/res/values-en-rCA/strings.xml +++ b/packages/SystemUI/res/values-en-rCA/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Resume"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Settings"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> by <xliff:g id="ARTIST_NAME">%2$s</xliff:g> is playing from <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> of <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Play"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Open <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Play <xliff:g id="SONG_NAME">%1$s</xliff:g> by <xliff:g id="ARTIST_NAME">%2$s</xliff:g> from <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi‑Fi won’t auto-connect for now"</string> <string name="see_all_networks" msgid="3773666844913168122">"See all"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"To switch networks, disconnect Ethernet"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"To improve device experience, apps and services can still scan for Wi‑Fi networks at any time, even when Wi‑Fi is off. You can change this in Wi‑Fi scanning settings. "<annotation id="link">"Change"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Select user"</string> </resources> diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml index 590033a632dc..2f4a17d07b62 100644 --- a/packages/SystemUI/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/res/values-en-rGB/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Resume"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Settings"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> by <xliff:g id="ARTIST_NAME">%2$s</xliff:g> is playing from <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> of <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Play"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Open <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Play <xliff:g id="SONG_NAME">%1$s</xliff:g> by <xliff:g id="ARTIST_NAME">%2$s</xliff:g> from <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi‑Fi won’t auto-connect for now"</string> <string name="see_all_networks" msgid="3773666844913168122">"See all"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"To switch networks, disconnect Ethernet"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"To improve device experience, apps and services can still scan for Wi‑Fi networks at any time, even when Wi‑Fi is off. You can change this in Wi‑Fi scanning settings. "<annotation id="link">"Change"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Select user"</string> </resources> diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml index 590033a632dc..2f4a17d07b62 100644 --- a/packages/SystemUI/res/values-en-rIN/strings.xml +++ b/packages/SystemUI/res/values-en-rIN/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Resume"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Settings"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> by <xliff:g id="ARTIST_NAME">%2$s</xliff:g> is playing from <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> of <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Play"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Open <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Play <xliff:g id="SONG_NAME">%1$s</xliff:g> by <xliff:g id="ARTIST_NAME">%2$s</xliff:g> from <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi‑Fi won’t auto-connect for now"</string> <string name="see_all_networks" msgid="3773666844913168122">"See all"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"To switch networks, disconnect Ethernet"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"To improve device experience, apps and services can still scan for Wi‑Fi networks at any time, even when Wi‑Fi is off. You can change this in Wi‑Fi scanning settings. "<annotation id="link">"Change"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Select user"</string> </resources> diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml index 1a26024323af..7ddbdd69850b 100644 --- a/packages/SystemUI/res/values-en-rXC/strings.xml +++ b/packages/SystemUI/res/values-en-rXC/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Resume"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Settings"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> by <xliff:g id="ARTIST_NAME">%2$s</xliff:g> is playing from <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> of <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Play"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Open <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Play <xliff:g id="SONG_NAME">%1$s</xliff:g> by <xliff:g id="ARTIST_NAME">%2$s</xliff:g> from <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi‑Fi won’t auto-connect for now"</string> <string name="see_all_networks" msgid="3773666844913168122">"See all"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"To switch networks, disconnect ethernet"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"To improve device experience, apps and services can still scan for Wi‑Fi networks at any time, even when Wi‑Fi is off. You can change this in Wi‑Fi scanning settings. "<annotation id="link">"Change"</annotation>""</string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Select user"</string> </resources> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index bfe22c20c69d..95cd9ba1b13d 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Reanudar"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Configuración"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Se está reproduciendo <xliff:g id="SONG_NAME">%1$s</xliff:g>, de <xliff:g id="ARTIST_NAME">%2$s</xliff:g>, en <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> de <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Reproducir"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Abre <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Reproduce <xliff:g id="SONG_NAME">%1$s</xliff:g>, de <xliff:g id="ARTIST_NAME">%2$s</xliff:g>, en <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Por ahora, el Wi-Fi no se conectará automáticamente"</string> <string name="see_all_networks" msgid="3773666844913168122">"Ver todo"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para cambiar de red, desconéctate de Ethernet"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Para mejorar la experiencia con el dispositivo, las apps y los servicios pueden seguir buscando redes Wi-Fi en cualquier momento, incluso cuando la conexión Wi-Fi esté desactivada. Puedes cambiar este parámetro en la configuración de búsqueda de Wi-Fi. "<annotation id="link">"Cambiar"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Seleccionar usuario"</string> </resources> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index 762c1bed1580..15af90396cba 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -663,8 +663,8 @@ <string name="status_bar" msgid="4357390266055077437">"Barra de estado"</string> <string name="overview" msgid="3522318590458536816">"Aplicaciones recientes"</string> <string name="demo_mode" msgid="263484519766901593">"Modo de demostración de UI del sistema"</string> - <string name="enable_demo_mode" msgid="3180345364745966431">"Habilitar modo de demostración"</string> - <string name="show_demo_mode" msgid="3677956462273059726">"Mostrar modo de demostración"</string> + <string name="enable_demo_mode" msgid="3180345364745966431">"Habilitar modo demo"</string> + <string name="show_demo_mode" msgid="3677956462273059726">"Mostrar modo demo"</string> <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string> <string name="status_bar_alarm" msgid="87160847643623352">"Alarma"</string> <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string> @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Reanudar"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Ajustes"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Se está reproduciendo <xliff:g id="SONG_NAME">%1$s</xliff:g> de <xliff:g id="ARTIST_NAME">%2$s</xliff:g> en <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> de <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Reproducir"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Abrir <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Poner <xliff:g id="SONG_NAME">%1$s</xliff:g> de <xliff:g id="ARTIST_NAME">%2$s</xliff:g> en <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Por ahora no se conectará automáticamente a redes Wi-Fi"</string> <string name="see_all_networks" msgid="3773666844913168122">"Ver todo"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para cambiar de red, desconecta el cable Ethernet"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Para mejorar la experiencia con el dispositivo, las aplicaciones y los servicios podrán buscar redes Wi-Fi en cualquier momento, aunque la conexión Wi-Fi esté desactivada. Puedes cambiarlo en los ajustes de búsqueda de redes Wi-Fi. "<annotation id="link">"Cambiar"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Seleccionar usuario"</string> </resources> diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml index 04874d21f35d..39d29cc4fc98 100644 --- a/packages/SystemUI/res/values-et/strings.xml +++ b/packages/SystemUI/res/values-et/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Jätka"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Seaded"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> esitajalt <xliff:g id="ARTIST_NAME">%2$s</xliff:g> esitatakse rakenduses <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g>/<xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Esitamine"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Rakenduse <xliff:g id="APP_LABEL">%1$s</xliff:g> avamine"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Esita lugu <xliff:g id="SONG_NAME">%1$s</xliff:g> esitajalt <xliff:g id="ARTIST_NAME">%2$s</xliff:g> rakenduses <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"WiFi-ühendust ei looda praegu automaatselt"</string> <string name="see_all_networks" msgid="3773666844913168122">"Kuva kõik"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Võrkude vahetamiseks katkestage Etherneti-ühendus"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Seadme kasutuskogemuse parandamiseks võivad rakendused ja teenused siiski alati otsida WiFi-võrke isegi siis, kui WiFi on väljas. Seda saab muuta WiFi-skannimise seadetes. "<annotation id="link">"Muuda"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Kasutaja valimine"</string> </resources> diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml index 5c6fc3b0591d..bacf6efa74cd 100644 --- a/packages/SystemUI/res/values-eu/strings.xml +++ b/packages/SystemUI/res/values-eu/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Berrekin"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Ezarpenak"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> (<xliff:g id="ARTIST_NAME">%2$s</xliff:g>) ari da erreproduzitzen <xliff:g id="APP_LABEL">%3$s</xliff:g> bidez"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g>/<xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Erreproduzitu"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Ireki <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Erreproduzitu <xliff:g id="SONG_NAME">%1$s</xliff:g> (<xliff:g id="ARTIST_NAME">%2$s</xliff:g>) <xliff:g id="APP_LABEL">%3$s</xliff:g> bidez"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Oraingoz ez da automatikoki konektatuko wifira"</string> <string name="see_all_networks" msgid="3773666844913168122">"Ikusi guztiak"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Sarea aldatzeko, deskonektatu Ethernet-a"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Gailuaren funtzionamendua hobetzeko, aplikazioek eta zerbitzuek wifi-sareak bilatzen jarraituko dute, baita wifi-konexioa desaktibatuta dagoenean ere. Aukera hori aldatzeko, joan wifi-sareen bilaketaren ezarpenetara. "<annotation id="link">"Aldatu"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Hautatu erabiltzaile bat"</string> </resources> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index ae8fab633bce..9a9c20f2eb5d 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"ازسرگیری"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"تنظیمات"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> از <xliff:g id="ARTIST_NAME">%2$s</xliff:g> ازطریق <xliff:g id="APP_LABEL">%3$s</xliff:g> پخش میشود"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> از <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"پخش"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"باز کردن <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="SONG_NAME">%1$s</xliff:g> از <xliff:g id="ARTIST_NAME">%2$s</xliff:g> را ازطریق <xliff:g id="APP_LABEL">%3$s</xliff:g> پخش کنید"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"فعلاً Wi-Fi بهطور خودکار متصل نمیشود"</string> <string name="see_all_networks" msgid="3773666844913168122">"مشاهده همه"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"برای تغییر شبکه، اترنت را قطع کنید"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"برای بهبود تجربه استفاده از دستگاه، برنامهها و سرویسها همچنان میتوانند در هر زمانی شبکههای Wi-Fi را اسکن کنند؛ حتی وقتی که Wi-Fi خاموش باشد. میتوانید این مورد را در تنظیمات اسکن کردن Wi‑Fi تغییر دهید. "<annotation id="link">"تغییر"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"انتخاب کاربر"</string> </resources> diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index 9bd16bdfef60..ca0f4525a40d 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Jatka"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Asetukset"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g> soittaa nyt tätä: <xliff:g id="SONG_NAME">%1$s</xliff:g> (<xliff:g id="ARTIST_NAME">%2$s</xliff:g>)"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g>/<xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Toista"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Avaa <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Soita <xliff:g id="SONG_NAME">%1$s</xliff:g> (<xliff:g id="ARTIST_NAME">%2$s</xliff:g>) sovelluksessa <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi ei toistaiseksi yhdistä automaattisesti"</string> <string name="see_all_networks" msgid="3773666844913168122">"Näytä kaikki"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Irrota Ethernet-johto, jos haluat vaihtaa verkkoa"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Laitteen käyttökokemuksen parantamiseksi sovellukset ja palvelut voivat hakea Wi-Fi-verkkoja myös silloin, kun Wi-Fi on pois päältä. Voit muuttaa asetusta Wi-Fi-haun asetuksissa. "<annotation id="link">"Muuta"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Valitse käyttäjä"</string> </resources> diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml index d8b312fc6468..ef4f86dc4b71 100644 --- a/packages/SystemUI/res/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Reprendre"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Paramètres"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> par <xliff:g id="ARTIST_NAME">%2$s</xliff:g> est en cours de lecteur à partir de <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> de <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Faire jouer"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Ouvrez <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Lecture de <xliff:g id="SONG_NAME">%1$s</xliff:g> par <xliff:g id="ARTIST_NAME">%2$s</xliff:g> à partir de <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Connexion automatique au Wi-Fi impossible pour le moment"</string> <string name="see_all_networks" msgid="3773666844913168122">"Tout afficher"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Pour changer de réseau, débranchez le câble Ethernet"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Pour améliorer l\'expérience de l\'appareil, les applications et les services peuvent quand même rechercher des réseaux Wi-Fi en tout temps, même lorsque le Wi-Fi est désactivé. Vous pouvez modifier vos préférences dans les paramètres de recherche de réseaux Wi-Fi. "<annotation id="link">"Modifier"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Sélect. utilisateur"</string> </resources> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index e897a699f9c1..3d6dd559855a 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -895,7 +895,7 @@ <string name="right_icon" msgid="1103955040645237425">"Icône droite"</string> <string name="drag_to_add_tiles" msgid="8933270127508303672">"Faites glisser les blocs pour les ajouter"</string> <string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Faites glisser les blocs pour les réorganiser"</string> - <string name="drag_to_remove_tiles" msgid="4682194717573850385">"Faites glisser les icônes ici pour les supprimer."</string> + <string name="drag_to_remove_tiles" msgid="4682194717573850385">"Faites glisser les blocs ici pour les supprimer"</string> <string name="drag_to_remove_disabled" msgid="933046987838658850">"Au minimum <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> tuiles sont nécessaires"</string> <string name="qs_edit" msgid="5583565172803472437">"Modifier"</string> <string name="tuner_time" msgid="2450785840990529997">"Heure"</string> @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Reprendre"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Paramètres"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> par <xliff:g id="ARTIST_NAME">%2$s</xliff:g> est en cours de lecture depuis <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> sur <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Lire"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Ouvre <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Mets <xliff:g id="SONG_NAME">%1$s</xliff:g> par <xliff:g id="ARTIST_NAME">%2$s</xliff:g> depuis <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Connexion automatique au Wi-Fi désactivée pour le moment"</string> <string name="see_all_networks" msgid="3773666844913168122">"Tout afficher"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Pour changer de réseau, déconnectez l\'Ethernet"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Pour améliorer l\'expérience sur l\'appareil, les applis et les services peuvent continuer de rechercher les réseaux Wi-Fi, même si le Wi-Fi est désactivé. Vous pouvez modifier cela dans les paramètres de recherche Wi-Fi. "<annotation id="link">"Modifier"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Choisir utilisateur"</string> </resources> diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml index 328ac9c00140..8570e9a6b52b 100644 --- a/packages/SystemUI/res/values-gl/strings.xml +++ b/packages/SystemUI/res/values-gl/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Retomar"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Configuración"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Estase reproducindo <xliff:g id="SONG_NAME">%1$s</xliff:g>, de <xliff:g id="ARTIST_NAME">%2$s</xliff:g>, en <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> de <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Reproducir"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Abre <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Reproduce <xliff:g id="SONG_NAME">%1$s</xliff:g>, de <xliff:g id="ARTIST_NAME">%2$s</xliff:g>, en <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"De momento, a wifi non se conectará automaticamente"</string> <string name="see_all_networks" msgid="3773666844913168122">"Ver todo"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para cambiar de rede, desconecta a Ethernet"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Para mellorar a experiencia que ofrece o dispositivo, as aplicacións e os servizos poden seguir buscando redes wifi en calquera momento, aínda que esta conexión estea desactivada. Podes cambiar esta opción na configuración da función Busca de redes wifi. "<annotation id="link">"Cambiar"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Seleccionar usuario"</string> </resources> diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml index 3524d85464dc..95efbad63afe 100644 --- a/packages/SystemUI/res/values-gu/strings.xml +++ b/packages/SystemUI/res/values-gu/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"ફરી શરૂ કરો"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"સેટિંગ"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g> પર <xliff:g id="ARTIST_NAME">%2$s</xliff:g>નું <xliff:g id="SONG_NAME">%1$s</xliff:g> ગીત ચાલી રહ્યું છે"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g>માંથી <xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"ચલાવો"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> ખોલો"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="APP_LABEL">%3$s</xliff:g> પર <xliff:g id="ARTIST_NAME">%2$s</xliff:g>નું <xliff:g id="SONG_NAME">%1$s</xliff:g> ગીત ચલાવો"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"હમણાં પૂરતું વાઇ-ફાઇ ઑટોમૅટિક રીતે કનેક્ટ થશે નહીં"</string> <string name="see_all_networks" msgid="3773666844913168122">"બધા જુઓ"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"બીજા નેટવર્ક પર જવા માટે, ઇથરનેટ ડિસ્કનેક્ટ કરો"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"ડિવાઇસના અનુભવને બહેતર બનાવવા માટે, વાઇ-ફાઇ બંધ હોય ત્યારે પણ ઍપ અને સેવાઓ કોઈપણ સમયે વાઇ-ફાઇ નેટવર્ક સ્કૅન કરી શકે છે. તમે વાઇ-ફાઇ સ્કૅનિંગના સેટિંગમાં જઈને આને બદલી શકો છો. "<annotation id="link">"બદલો"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"વપરાશકર્તા પસંદ કરો"</string> </resources> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index 3aec1f4d4bca..2a6475566a69 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"फिर से शुरू करें"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"सेटिंग"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g> पर, <xliff:g id="ARTIST_NAME">%2$s</xliff:g> का <xliff:g id="SONG_NAME">%1$s</xliff:g> चल रहा है"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g> में से <xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"चलाएं"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> खोलें"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="APP_LABEL">%3$s</xliff:g> पर, <xliff:g id="ARTIST_NAME">%2$s</xliff:g> का <xliff:g id="SONG_NAME">%1$s</xliff:g> चलाएं"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"फ़िलहाल, वाई-फ़ाई अपने-आप कनेक्ट नहीं होगा"</string> <string name="see_all_networks" msgid="3773666844913168122">"सभी देखें"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"नेटवर्क बदलने के लिए, पहले ईथरनेट को डिसकनेक्ट करें"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"डिवाइस इस्तेमाल करने के अनुभव काे बेहतर बनाने के लिए, ऐप्लिकेशन और सेवाओं की मदद से, किसी भी समय वाई-फ़ाई नेटवर्क स्कैन किए जा सकते हैं. ऐसा वाई-फ़ाई बंद होने पर भी किया जा सकता है. वाई-फ़ाई स्कैनिंग की सेटिंग में जाकर, इसे बदला जा सकता है. "<annotation id="link">"बदलें"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"उपयोगकर्ता चुनें"</string> </resources> diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index 0b899030923e..3edd928b9488 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -1096,6 +1096,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Nastavi"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Postavke"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g>, <xliff:g id="ARTIST_NAME">%2$s</xliff:g> reproducira se putem aplikacije <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> od <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Reprodukcija"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Otvori <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Pustite <xliff:g id="SONG_NAME">%1$s</xliff:g>, <xliff:g id="ARTIST_NAME">%2$s</xliff:g> putem aplikacije <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -1184,5 +1185,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi se zasad neće automatski povezivati"</string> <string name="see_all_networks" msgid="3773666844913168122">"Prikaži sve"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Da biste se prebacili na drugu mrežu, odspojite Ethernet"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Da bi se poboljšao doživljaj uređaja, aplikacije i usluge i dalje mogu tražiti Wi-Fi mreže u bilo kojem trenutku, čak i kada je Wi-Fi isključen. To možete promijeniti u postavkama traženja Wi-Fija. "<annotation id="link">"Promijeni"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Odabir korisnika"</string> </resources> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index 573fa6e64a6a..34858083c04a 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Folytatás"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Beállítások"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> <xliff:g id="SONG_NAME">%1$s</xliff:g> című száma hallható itt: <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g>/<xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Játék"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> megnyitása"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> <xliff:g id="SONG_NAME">%1$s</xliff:g> című számának lejátszása innen: <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"A Wi-Fi-re történő csatlakozás jelenleg nem automatikus"</string> <string name="see_all_networks" msgid="3773666844913168122">"Megtekintés"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Hálózatváltáshoz válassza le az ethernetet"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Az eszközhasználati élmény javítása érdekében az alkalmazások és a szolgáltatások továbbra is bármikor kereshetnek Wi-Fi-hálózatokat, még akkor is, ha a Wi-Fi ki van kapcsolva. A funkciót a „Wi-Fi scanning settings” (Wi-Fi-keresési beállítások) részben módosíthatja. "<annotation id="link">"Módosítás"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Felhasználóválasztás"</string> </resources> diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml index c6be8c0ff3a4..fde4d32ad87b 100644 --- a/packages/SystemUI/res/values-hy/strings.xml +++ b/packages/SystemUI/res/values-hy/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Շարունակել"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Կարգավորումներ"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Այժմ նվագարկվում է <xliff:g id="SONG_NAME">%1$s</xliff:g> երգը <xliff:g id="ARTIST_NAME">%2$s</xliff:g>-ի կատարմամբ <xliff:g id="APP_LABEL">%3$s</xliff:g> հավելվածից"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g>՝ <xliff:g id="TOTAL_TIME">%2$s</xliff:g>-ից"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Նվագարկել"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Բացեք <xliff:g id="APP_LABEL">%1$s</xliff:g> հավելվածը"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Նվագարկել <xliff:g id="SONG_NAME">%1$s</xliff:g> երգը <xliff:g id="ARTIST_NAME">%2$s</xliff:g>-ի կատարմամբ <xliff:g id="APP_LABEL">%3$s</xliff:g> հավելվածից"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi-ն ավտոմատ չի միանա"</string> <string name="see_all_networks" msgid="3773666844913168122">"Տեսնել բոլորը"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Մի ցանցից մյուսին անցնելու համար անջատեք Ethernet-ը"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Սարքի աշխատանքը բարելավելու համար հավելվածներն ու ծառայությունները կորոնեն Wi‑Fi ցանցեր, նույնիսկ երբ Wi‑Fi-ն անջատված է։ Այս պարամետրը կարող եք փոխել Wi‑Fi ցանցերի որոնման կարգավորումներում։ "<annotation id="link">"Փոխել"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Ընտրեք օգտատեր"</string> </resources> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index 53c7e264b7bd..f3bf7dfc0448 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Lanjutkan"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Setelan"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> oleh <xliff:g id="ARTIST_NAME">%2$s</xliff:g> sedang diputar dari <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> dari <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Putar"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Buka <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Putar <xliff:g id="SONG_NAME">%1$s</xliff:g> oleh <xliff:g id="ARTIST_NAME">%2$s</xliff:g> dari <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi tidak akan otomatis terhubung untuk saat ini"</string> <string name="see_all_networks" msgid="3773666844913168122">"Lihat semua"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Untuk beralih jaringan, lepaskan kabel ethernet"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Agar pengalaman perangkat menjadi lebih baik, aplikasi dan layanan tetap dapat memindai jaringan Wi-Fi kapan saja, bahkan saat Wi-Fi nonaktif. Anda dapat mengubahnya di setelan pemindaian Wi-Fi. "<annotation id="link">"Ubah"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Pilih pengguna"</string> </resources> diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml index 76953ef56002..7cd5444f2a09 100644 --- a/packages/SystemUI/res/values-is/strings.xml +++ b/packages/SystemUI/res/values-is/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Halda áfram"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Stillingar"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> með <xliff:g id="ARTIST_NAME">%2$s</xliff:g> er í spilun á <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> af <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Spila"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Opna <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Spila <xliff:g id="SONG_NAME">%1$s</xliff:g> með <xliff:g id="ARTIST_NAME">%2$s</xliff:g> í <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi tengist ekki sjálfkrafa eins og er"</string> <string name="see_all_networks" msgid="3773666844913168122">"Sjá allt"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Aftengdu ethernet til að skipta um net"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Til að bæta tækjaupplifun geta forrit og þjónustur áfram leitað að WiFi-netum hvenær sem er, jafnvel þótt slökkt sé á WiFi. Hægt er að breyta þessu í stillingum WiFi-leitar. "<annotation id="link">"Breyta"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Velja notanda"</string> </resources> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index d2467b183c6b..496b2871eac4 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Riprendi"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Impostazioni"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> di <xliff:g id="ARTIST_NAME">%2$s</xliff:g> è in riproduzione da <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> di <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Riproduci"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Apri <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Riproduci <xliff:g id="SONG_NAME">%1$s</xliff:g> di <xliff:g id="ARTIST_NAME">%2$s</xliff:g> da <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Connessione automatica rete Wi-Fi non attiva al momento"</string> <string name="see_all_networks" msgid="3773666844913168122">"Mostra tutte"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Per cambiare rete, scollega il cavo Ethernet"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Per migliorare l\'esperienza con il dispositivo, le app e i servizi possono continuare a cercare reti Wi-Fi in qualsiasi momento, anche quando la connessione Wi-Fi non è attiva. Puoi modificare questa preferenza nelle impostazioni relative alla ricerca di reti Wi-Fi. "<annotation id="link">"Cambia"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Seleziona utente"</string> </resources> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index b4566e891312..ec9d32346493 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -1102,6 +1102,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"המשך"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"הגדרות"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> של <xliff:g id="ARTIST_NAME">%2$s</xliff:g> מופעל מ-<xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> מתוך <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"הפעלה"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"פתיחה של <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"הפעלת <xliff:g id="SONG_NAME">%1$s</xliff:g> של <xliff:g id="ARTIST_NAME">%2$s</xliff:g> מ-<xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -1190,5 +1191,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"ה-Wi-Fi לא יתחבר באופן אוטומטי בינתיים"</string> <string name="see_all_networks" msgid="3773666844913168122">"הצגת הכול"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"כדי לעבור בין רשתות, צריך לנתק את האתרנט"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"כדי לשפר את חוויית השימוש במכשיר, אפליקציות ושירותים יוכלו לחפש רשתות Wi-Fi בכל שלב, גם כאשר ה-Wi-Fi כבוי. אפשר לשנות זאת בהגדרות של חיפוש נקודות Wi-Fi. "<annotation id="link">"שינוי"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"בחירת משתמש"</string> </resources> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index 34f9c0ca89c7..dc8f668d494e 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"再開"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"設定"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g>(アーティスト名: <xliff:g id="ARTIST_NAME">%2$s</xliff:g>)が <xliff:g id="APP_LABEL">%3$s</xliff:g> で再生中"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g>/<xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"再生"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> を開く"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="SONG_NAME">%1$s</xliff:g>(アーティスト名: <xliff:g id="ARTIST_NAME">%2$s</xliff:g>)を <xliff:g id="APP_LABEL">%3$s</xliff:g> で再生"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi に自動接続しません"</string> <string name="see_all_networks" msgid="3773666844913168122">"すべて表示"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ネットワークを変更するにはイーサネット接続を解除してください"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"デバイスの機能向上のため、アプリやサービスは、Wi-Fi が OFF の場合でも、いつでも Wi-Fi ネットワークをスキャンできます。この設定は Wi-Fi スキャンの設定で変更できます。"<annotation id="link">"変更"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"ユーザーの選択"</string> </resources> diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml index bead5fea3c93..bcd7af2d7b98 100644 --- a/packages/SystemUI/res/values-ka/strings.xml +++ b/packages/SystemUI/res/values-ka/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"გაგრძელება"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"პარამეტრები"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g>, <xliff:g id="ARTIST_NAME">%2$s</xliff:g>, უკრავს <xliff:g id="APP_LABEL">%3$s</xliff:g>-დან"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g>-დან <xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"დაკვრა"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"გახსენით <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"დაუკარით <xliff:g id="SONG_NAME">%1$s</xliff:g>, <xliff:g id="ARTIST_NAME">%2$s</xliff:g>, <xliff:g id="APP_LABEL">%3$s</xliff:g>-დან"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi ინტერნეტს დროებით ავტომატურად არ დაუკავშირდება"</string> <string name="see_all_networks" msgid="3773666844913168122">"ყველას ნახვა"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ქსელების გადასართავად, გაწყვიტეთ Ethernet-თან კავშირი"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"მოწყობილობისგან მიღებული გამოცდილების გასაუმჯობესებლად, აპებსა და სერვისებს მაინც შეუძლია სკანირება Wi‑Fi ქსელების აღმოსაჩენად, ნებისმიერ დროს, მაშინაც კი, როცა Wi‑Fi გამორთულია. ამის შეცვლა Wi-Fi სკანირების პარამეტრებში შეგიძლიათ. "<annotation id="link">"შეცვლა"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"მომხმარებლის არჩევა"</string> </resources> diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml index 14e84565617f..6685dc370943 100644 --- a/packages/SystemUI/res/values-kk/strings.xml +++ b/packages/SystemUI/res/values-kk/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Жалғастыру"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Параметрлер"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g> қолданбасында <xliff:g id="ARTIST_NAME">%2$s</xliff:g> орындайтын \"<xliff:g id="SONG_NAME">%1$s</xliff:g>\" әні ойнатылуда."</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g>/<xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Ойнату"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> қолданбасын ашу"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="APP_LABEL">%3$s</xliff:g> қолданбасында <xliff:g id="ARTIST_NAME">%2$s</xliff:g> орындайтын \"<xliff:g id="SONG_NAME">%1$s</xliff:g>\" әнін ойнату"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Әзірше Wi-Fi автоматты түрде қосылмайды."</string> <string name="see_all_networks" msgid="3773666844913168122">"Барлығын көру"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Желілерді ауыстыру үшін ethernet кабелін ажыратыңыз."</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Құрылғы жұмысын жақсарту үшін қолданбалар мен қызметтер Wi-Fi байланысы өшірулі кезде де Wi-Fi желілерін іздейді. Оны Wi-Fi іздеу параметрлерінен өзгерте аласыз. "<annotation id="link">"Өзгерту"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Пайдаланушыны таңдау"</string> </resources> diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml index 9bcc41a7b8eb..70d10f99e48e 100644 --- a/packages/SystemUI/res/values-km/strings.xml +++ b/packages/SystemUI/res/values-km/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"បន្ត"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"ការកំណត់"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> ច្រៀងដោយ <xliff:g id="ARTIST_NAME">%2$s</xliff:g> កំពុងចាក់ពី <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> នៃ <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"ចាក់"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"បើក <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"ចាក់ <xliff:g id="SONG_NAME">%1$s</xliff:g> ច្រៀងដោយ <xliff:g id="ARTIST_NAME">%2$s</xliff:g> ពី <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi នឹងមិនភ្ជាប់ដោយស្វ័យប្រវត្តិក្នុងពេលនេះទេ"</string> <string name="see_all_networks" msgid="3773666844913168122">"មើលទាំងអស់"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ដើម្បីប្ដូរបណ្ដាញ សូមផ្ដាច់អ៊ីសឺរណិត"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"ដើម្បីធ្វើឱ្យបទពិសោធន៍ប្រើប្រាស់ឧបករណ៍ប្រសើរឡើង កម្មវិធី និងសេវាកម្មនៅតែអាចស្កេនរកបណ្ដាញ Wi‑Fi បានគ្រប់ពេល ទោះបីជានៅពេលដែលបិទ Wi‑Fi ក៏ដោយ។ អ្នកអាចប្ដូរវាបាននៅក្នុងការកំណត់ការស្កេន Wi‑Fi។ "<annotation id="link">"ប្ដូរ"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"ជ្រើសរើសអ្នកប្រើប្រាស់"</string> </resources> diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml index cad8abb00467..3a1e6a6739a1 100644 --- a/packages/SystemUI/res/values-kn/strings.xml +++ b/packages/SystemUI/res/values-kn/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"ಪುನರಾರಂಭಿಸಿ"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"ಸೆಟ್ಟಿಂಗ್ಗಳು"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> ಅವರ <xliff:g id="SONG_NAME">%1$s</xliff:g> ಹಾಡನ್ನು <xliff:g id="APP_LABEL">%3$s</xliff:g> ನಲ್ಲಿ ಪ್ಲೇ ಮಾಡಲಾಗುತ್ತಿದೆ"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g> ರಲ್ಲಿ <xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"ಪ್ಲೇ ಮಾಡಿ"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> ಅನ್ನು ತೆರೆಯಿರಿ"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> ಅವರ <xliff:g id="SONG_NAME">%1$s</xliff:g> ಹಾಡನ್ನು <xliff:g id="APP_LABEL">%3$s</xliff:g> ನಲ್ಲಿ ಪ್ಲೇ ಮಾಡಿ"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"ಸದ್ಯದ ಮಟ್ಟಿಗೆ ವೈ-ಫೈ ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಕನೆಕ್ಟ್ ಆಗುವುದಿಲ್ಲ"</string> <string name="see_all_networks" msgid="3773666844913168122">"ಎಲ್ಲವನ್ನೂ ನೋಡಿ"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ನೆಟ್ವರ್ಕ್ಗಳನ್ನು ಬದಲಿಸಲು, ಇಥರ್ನೆಟ್ ಅನ್ನು ಡಿಸ್ಕನೆಕ್ಟ್ ಮಾಡಿ"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"ವೈ-ಫೈ ಆಫ್ ಇದ್ದಾಗಲೂ ಸಹ, ಸಾಧನದ ಅನುಭವವನ್ನು ಸುಧಾರಿಸಲು, ಆ್ಯಪ್ಗಳು ಮತ್ತು ಸೇವೆಗಳು ಯಾವಾಗ ಬೇಕಾದರೂ ಸಹ ವೈ-ಫೈ ನೆಟ್ವರ್ಕ್ಗಳಿಗಾಗಿ ಸ್ಕ್ಯಾನ್ ಮಾಡಬಹುದು. ನೀವು ಇದನ್ನು ವೈ-ಫೈ ಸ್ಕ್ಯಾನಿಂಗ್ ಸೆಟ್ಟಿಂಗ್ಗಳಲ್ಲಿ ಬದಲಾಯಿಸಬಹುದು. "<annotation id="link">"ಬದಲಿಸಿ"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"ಬಳಕೆದಾರ ಆಯ್ಕೆಮಾಡಿ"</string> </resources> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index 6541cbfddbb3..4b705fbce07f 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"다시 시작"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"설정"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g>에서 <xliff:g id="ARTIST_NAME">%2$s</xliff:g>의 <xliff:g id="SONG_NAME">%1$s</xliff:g> 재생 중"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g>/<xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"재생"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> 열기"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="APP_LABEL">%3$s</xliff:g>에서 <xliff:g id="ARTIST_NAME">%2$s</xliff:g>의 <xliff:g id="SONG_NAME">%1$s</xliff:g> 재생"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"지금은 Wi-Fi가 자동으로 연결되지 않습니다."</string> <string name="see_all_networks" msgid="3773666844913168122">"모두 보기"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"네트워크를 전환하려면 이더넷을 연결 해제하세요."</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"기기 환경을 개선하기 위해 Wi‑Fi가 꺼져 있을 때도 앱과 서비스에서 Wi‑Fi 네트워크를 검색할 수 있습니다. 이 설정은 Wi‑Fi 검색 설정에서 변경할 수 있습니다. "<annotation id="link">"변경"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"사용자 선택"</string> </resources> diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml index 1c6f3bee6934..58114d88f015 100644 --- a/packages/SystemUI/res/values-ky/strings.xml +++ b/packages/SystemUI/res/values-ky/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Улантуу"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Жөндөөлөр"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> ыры (аткаруучу: <xliff:g id="ARTIST_NAME">%2$s</xliff:g>) <xliff:g id="APP_LABEL">%3$s</xliff:g> колдонмосунан ойнотулуп жатат"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g> ичинен <xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Ойнотуу"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> колдонмосун ачуу"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="SONG_NAME">%1$s</xliff:g> ырын (аткаруучу: <xliff:g id="ARTIST_NAME">%2$s</xliff:g>) <xliff:g id="APP_LABEL">%3$s</xliff:g> колдонмосунан ойнотуу"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi азырынча автоматтык түрдө туташпайт"</string> <string name="see_all_networks" msgid="3773666844913168122">"Баарын көрүү"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Башка тармактарга которулуу үчүн Ethernet кабелин ажыратыңыз"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Түзмөктүн колдонулушун жакшыртуу үчүн колдонмолор менен кызматтар Wi‑Fi өчүп турса да зымсыз тармактарды издей беришет. Аны Wi-Fi тармактарын издөө жөндөөлөрүнөн өзгөртө аласыз. "<annotation id="link">"Өзгөртүү"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Колдонуучуну тандоо"</string> </resources> diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml index dfe591625561..9ff47acbbcdc 100644 --- a/packages/SystemUI/res/values-lo/strings.xml +++ b/packages/SystemUI/res/values-lo/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"ສືບຕໍ່"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"ການຕັ້ງຄ່າ"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> ໂດຍ <xliff:g id="ARTIST_NAME">%2$s</xliff:g> ກຳລັງຫຼິ້ນຈາກ <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> ຈາກ <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"ຫຼິ້ນ"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"ເປີດ <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"ຫຼິ້ນ <xliff:g id="SONG_NAME">%1$s</xliff:g> ໂດຍ <xliff:g id="ARTIST_NAME">%2$s</xliff:g> ຈາກ <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi ຈະບໍ່ເຊື່ອມຕໍ່ອັດຕະໂນມັດສຳລັບຕອນນີ້"</string> <string name="see_all_networks" msgid="3773666844913168122">"ເບິ່ງທັງໝົດ"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ເພື່ອສະຫຼັບເຄືອຂ່າຍ, ໃຫ້ຕັດການເຊື່ອມຕໍ່ອີເທີເນັດກ່ອນ"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"ເພື່ອປັບປຸງປະສົບການອຸປະກອນ, ແອັບ ແລະ ບໍລິການຍັງຄົງສາມາດສະແກນຫາເຄືອຂ່າຍ Wi‑Fi ຕອນໃດກໍໄດ້, ເຖິງແມ່ນວ່າຈະປິດ Wi‑Fi ໄວ້ກໍຕາມ. ທ່ານສາມາດປ່ຽນສິ່ງນີ້ໄດ້ໃນການຕັ້ງຄ່າການສະແກນ Wi‑Fi. "<annotation id="link">"ປ່ຽນ"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"ເລືອກຜູ້ໃຊ້"</string> </resources> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index 57af3864216f..0161aafb8952 100644 --- a/packages/SystemUI/res/values-lt/strings.xml +++ b/packages/SystemUI/res/values-lt/strings.xml @@ -1102,6 +1102,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Tęsti"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Nustatymai"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> – „<xliff:g id="SONG_NAME">%1$s</xliff:g>“ leidžiama iš „<xliff:g id="APP_LABEL">%3$s</xliff:g>“"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> iš <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Leisti"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Atidaryti „<xliff:g id="APP_LABEL">%1$s</xliff:g>“"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Leisti <xliff:g id="ARTIST_NAME">%2$s</xliff:g> – „<xliff:g id="SONG_NAME">%1$s</xliff:g>“ iš „<xliff:g id="APP_LABEL">%3$s</xliff:g>“"</string> @@ -1190,5 +1191,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"„Wi-Fi“ šiuo metu nebus prijungtas automatiškai"</string> <string name="see_all_networks" msgid="3773666844913168122">"Žiūrėti viską"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Norėdami perjungti tinklus, atjunkite eternetą"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Kad pagerintų įrenginio funkcijas, programos ir paslaugos vis tiek gali bet kada nuskaityti ieškodamos „Wi‑Fi“ tinklų, net jei „Wi‑Fi“ išjungtas. Tai galite pakeisti „Wi-Fi“ nuskaitymo nustatymuose. "<annotation id="link">"Pakeisti"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Naudotojo pasirinkimas"</string> </resources> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index ced02b34b9b0..2ff48e34a0de 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -1096,6 +1096,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Atsākt"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Iestatījumi"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Tiek atskaņots fails “<xliff:g id="SONG_NAME">%1$s</xliff:g>” (izpildītājs: <xliff:g id="ARTIST_NAME">%2$s</xliff:g>) no lietotnes <xliff:g id="APP_LABEL">%3$s</xliff:g>."</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> no <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Atskaņot"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Atveriet lietotni <xliff:g id="APP_LABEL">%1$s</xliff:g>."</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Atskaņojiet failu “<xliff:g id="SONG_NAME">%1$s</xliff:g>” (izpildītājs: <xliff:g id="ARTIST_NAME">%2$s</xliff:g>) no lietotnes <xliff:g id="APP_LABEL">%3$s</xliff:g>."</string> @@ -1184,5 +1185,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi savienojums īslaicīgi netiks izveidots automātiski."</string> <string name="see_all_networks" msgid="3773666844913168122">"Visu tīklu skatīšana"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Lai pārslēgtu tīklus, atvienojiet tīkla Ethernet vadu."</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Lai uzlabotu ierīces lietošanas iespējas, lietotnes un pakalpojumi joprojām varēs meklēt Wi‑Fi tīklus jebkurā laikā, pat ja Wi‑Fi būs izslēgts. Varat to mainīt Wi‑Fi meklēšanas iestatījumos. "<annotation id="link">"Mainīt"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Lietotāja atlase"</string> </resources> diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml index 7b54b631ff33..6c495a719af2 100644 --- a/packages/SystemUI/res/values-mk/strings.xml +++ b/packages/SystemUI/res/values-mk/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Продолжи"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Поставки"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> од <xliff:g id="ARTIST_NAME">%2$s</xliff:g> е пуштено на <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> од <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Пушти"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Отворете <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Пуштете <xliff:g id="SONG_NAME">%1$s</xliff:g> од <xliff:g id="ARTIST_NAME">%2$s</xliff:g> на <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi нема да се поврзува автоматски засега"</string> <string name="see_all_networks" msgid="3773666844913168122">"Прикажи ги сите"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"За промена на мрежата, прекинете ја врската со етернетот"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"За да се подобри доживувањето на уредот, апликациите и услугите може сѐ уште да скенираат за Wi‑Fi мрежи во секое време, дури и кога Wi‑Fi е исклучено. Може да го промените ова во поставките за „Скенирање за Wi-Fi“. "<annotation id="link">"Промени"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Изберете корисник"</string> </resources> diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml index 6e924aa32ee0..db338ef4e634 100644 --- a/packages/SystemUI/res/values-ml/strings.xml +++ b/packages/SystemUI/res/values-ml/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"പുനരാരംഭിക്കുക"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"ക്രമീകരണം"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> എന്ന ആർട്ടിസ്റ്റിന്റെ <xliff:g id="SONG_NAME">%1$s</xliff:g> എന്ന ഗാനം <xliff:g id="APP_LABEL">%3$s</xliff:g> ആപ്പിൽ പ്ലേ ചെയ്യുന്നു"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g>-ൽ <xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"പ്ലേ ചെയ്യുക"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> തുറക്കുക"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> എന്ന ആർട്ടിസ്റ്റിന്റെ <xliff:g id="SONG_NAME">%1$s</xliff:g> എന്ന ഗാനം <xliff:g id="APP_LABEL">%3$s</xliff:g> ആപ്പിൽ പ്ലേ ചെയ്യുക"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"വൈഫൈ ഇപ്പോൾ സ്വയമേവ കണക്റ്റ് ചെയ്യില്ല"</string> <string name="see_all_networks" msgid="3773666844913168122">"എല്ലാം കാണുക"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"മറ്റ് നെറ്റ്വർക്കുകളിലേക്ക് മാറാൻ, ഇതർനെറ്റ് വിച്ഛേദിക്കുക"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"ഉപകരണ അനുഭവം മെച്ചപ്പെടുത്താൻ, വൈഫൈ ഓഫാക്കിയിരിക്കുമ്പോൾ പോലും ആപ്പുകൾക്കും സേവനങ്ങൾക്കും വൈഫൈ നെറ്റ്വർക്കുകൾ കണ്ടെത്താൻ ഏത് സമയത്തും സ്കാൻ ചെയ്യാനാകും. നിങ്ങൾക്ക് ഇത് വൈഫൈ സ്കാനിംഗ് ക്രമീകരണത്തിൽ മാറ്റാം. "<annotation id="link">"മാറ്റുക"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"ഉപയോക്താവിനെ തിരഞ്ഞെടുക്കൂ"</string> </resources> diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml index 55126596f655..b34b75b7e2e3 100644 --- a/packages/SystemUI/res/values-mn/strings.xml +++ b/packages/SystemUI/res/values-mn/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Үргэлжлүүлэх"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Тохиргоо"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g> дээр тоглуулж буй <xliff:g id="ARTIST_NAME">%2$s</xliff:g>-н <xliff:g id="SONG_NAME">%1$s</xliff:g>"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g>-н <xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Тоглуулах"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g>-г нээх"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g>-н <xliff:g id="SONG_NAME">%1$s</xliff:g>-г <xliff:g id="APP_LABEL">%3$s</xliff:g> дээр тоглуулах"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi-г одоогоор автоматаар холбохгүй"</string> <string name="see_all_networks" msgid="3773666844913168122">"Бүгдийг харах"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Сүлжээг сэлгэхийн тулд этернэтийг салгана уу"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Төхөөрөмжийн туршлагыг сайжруулахын тулд аппууд болон үйлчилгээнүүд нь Wi-Fi сүлжээг хүссэн үедээ буюу Wi-Fi-г унтраалттай байсан ч скан хийх боломжтой хэвээр байна. Та үүнийг Wi-Fi скан хийх тохиргоонд өөрчлөх боломжтой. "<annotation id="link">"Өөрчлөх"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Хэрэглэгч сонгох"</string> </resources> diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml index 2864f326c8c8..674290d8e7ec 100644 --- a/packages/SystemUI/res/values-mr/strings.xml +++ b/packages/SystemUI/res/values-mr/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"पुन्हा सुरू करा"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"सेटिंग्ज"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g> मध्ये <xliff:g id="ARTIST_NAME">%2$s</xliff:g> चे <xliff:g id="SONG_NAME">%1$s</xliff:g> प्ले होत आहे"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g> पैकी <xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"प्ले करणे"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> उघडा"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="APP_LABEL">%3$s</xliff:g> मध्ये <xliff:g id="ARTIST_NAME">%2$s</xliff:g> चे <xliff:g id="SONG_NAME">%1$s</xliff:g> प्ले करा"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"सध्या वाय-फाय ऑटो-कनेक्ट होणार नाही"</string> <string name="see_all_networks" msgid="3773666844913168122">"सर्व पहा"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"नेटवर्क स्विच करण्यासाठी, इथरनेट केबल डिस्कनेक्ट करा"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"डिव्हाइसच्या अनुभवामध्ये सुधारणा करण्यासाठी, वाय-फाय बंद असले तरीही ॲप्स आणि सेवा या कधीही वाय-फाय नेटवर्क स्कॅन करू शकतात. तुम्ही हे वाय-फाय स्कॅनिंग सेटिंग्जमध्ये बदलू शकता. "<annotation id="link">"बदला"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"वापरकर्ता निवडा"</string> </resources> diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml index 96c7f893c9df..f3490407de17 100644 --- a/packages/SystemUI/res/values-ms/strings.xml +++ b/packages/SystemUI/res/values-ms/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Sambung semula"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Tetapan"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> oleh <xliff:g id="ARTIST_NAME">%2$s</xliff:g> dimainkan daripada <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> daripada <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Main"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Buka <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Mainkan <xliff:g id="SONG_NAME">%1$s</xliff:g> oleh <xliff:g id="ARTIST_NAME">%2$s</xliff:g> daripada <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi tidak akan disambungkan secara automatik buat masa ini"</string> <string name="see_all_networks" msgid="3773666844913168122">"Lihat semua"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Untuk menukar rangkaian, putuskan sambungan ethernet"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Untuk meningkatkan pengalaman peranti, apl dan perkhidmatan masih dapat melakukan imbasan untuk mengesan rangkaian Wi-Fi pada bila-bila masa, meskipun apabila Wi-Fi dimatikan. Anda boleh menukar tetapan ini dalam tetapan pengimbasan Wi-Fi. "<annotation id="link">"Tukar"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Pilih pengguna"</string> </resources> diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml index 1d521dcad5d6..b434294ac1d9 100644 --- a/packages/SystemUI/res/values-my/strings.xml +++ b/packages/SystemUI/res/values-my/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"ဆက်လုပ်ရန်"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"ဆက်တင်များ"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> ၏ <xliff:g id="SONG_NAME">%1$s</xliff:g> ကို <xliff:g id="APP_LABEL">%3$s</xliff:g> တွင် ဖွင့်ထားသည်"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g> အနက် <xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"ဖွင့်ခြင်း"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> ကို ဖွင့်ပါ"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> ၏ <xliff:g id="SONG_NAME">%1$s</xliff:g> ကို <xliff:g id="APP_LABEL">%3$s</xliff:g> တွင် ဖွင့်ပါ"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi က လောလောဆယ် အလိုအလျောက် ချိတ်ဆက်မည်မဟုတ်ပါ"</string> <string name="see_all_networks" msgid="3773666844913168122">"အားလုံးကြည့်ရန်"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ကွန်ရက်ပြောင်းရန် အီသာနက်ကို ချိတ်ဆက်မှုဖြုတ်ပါ"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"စက်ပစ္စည်းကို ပိုမိုကောင်းမွန်စွာ အသုံးပြုနိုင်ရန် Wi-Fi ပိတ်ထားသည့်တိုင် အက်ပ်နှင့် ဝန်ဆောင်မှုများက Wi-Fi ကွန်ရက်များကို အချိန်မရွေး စကင်ဖတ်နိုင်သည်။ ၎င်းကို Wi-Fi ရှာဖွေခြင်း ဆက်တင်များတွင် ပြောင်းနိုင်သည်။ "<annotation id="link">"ပြောင်းရန်"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"အသုံးပြုသူ ရွေးခြင်း"</string> </resources> diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index 32a37400deb7..c64eb1c7d3ea 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Gjenoppta"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Innstillinger"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> av <xliff:g id="ARTIST_NAME">%2$s</xliff:g> spilles av fra <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> av <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Spill av"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Åpne <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Spill av <xliff:g id="SONG_NAME">%1$s</xliff:g> av <xliff:g id="ARTIST_NAME">%2$s</xliff:g> fra <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi kobles ikke til automatisk inntil videre"</string> <string name="see_all_networks" msgid="3773666844913168122">"Se alle"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"For å bytte nettverk, koble fra Ethernet"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"For å forbedre brukeropplevelsen på enheten kan apper og tjenester søke etter Wi-Fi-nettverk når som helst – også når Wi-Fi er slått av. Du kan endre dette i innstillingene for Wi-Fi-skanning. "<annotation id="link">"Bytt"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Velg bruker"</string> </resources> diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml index 8b50929baa81..fad92262c772 100644 --- a/packages/SystemUI/res/values-ne/strings.xml +++ b/packages/SystemUI/res/values-ne/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"सुचारु गर्नुहोस्"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"सेटिङ"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> को <xliff:g id="SONG_NAME">%1$s</xliff:g> बोलको गीत <xliff:g id="APP_LABEL">%3$s</xliff:g> मा बज्दै छ"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g> मध्ये <xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"प्ले गर्नुहोस्"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> खोल्नुहोस्"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> को <xliff:g id="SONG_NAME">%1$s</xliff:g> बोलको गीत <xliff:g id="APP_LABEL">%3$s</xliff:g> मा बजाउनुहोस्"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"केही समयका लागि Wi-Fi स्वतः कनेक्ट हुँदैन"</string> <string name="see_all_networks" msgid="3773666844913168122">"सबै नेटवर्क हेर्नुहोस्"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"नेटवर्क बदल्न इथरनेट डिस्कनेक्ट गर्नुहोस्"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"डिभाइस प्रयोगको अनुभवमा गुणस्तर सुधार गर्न, एप तथा सेवाहरूले अझै पनि जुनसुकै बेला (Wi‑Fi अफ भएका बेलामा पनि) Wi‑Fi नेटवर्क खोज्न सक्छन्। तपाईं यसलाई Wi‑Fi स्क्यानिङका सेटिङमा गई परिवर्तन गर्न सक्नुहुन्छ। "<annotation id="link">"बदल्नुहोस्"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"प्रयोगकर्ता चयन गर्नु…"</string> </resources> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index 2c9b459f9b17..2dd2bb7fbd21 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Hervatten"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Instellingen"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> van <xliff:g id="ARTIST_NAME">%2$s</xliff:g> wordt afgespeeld via <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> van <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Afspelen"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> openen"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="SONG_NAME">%1$s</xliff:g> van <xliff:g id="ARTIST_NAME">%2$s</xliff:g> afspelen via <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wifi maakt momenteel niet automatisch verbinding"</string> <string name="see_all_networks" msgid="3773666844913168122">"Alles tonen"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Verbreek de ethernetverbinding om van netwerk te wisselen"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Apps en services kunnen nog steeds op elk moment scannen op wifi-netwerken, zelfs als wifi uitstaat, om de apparaatfunctionaliteit te verbeteren. Je kunt dit aanpassen in de instellingen voor wifi-scannen. "<annotation id="link">"Wijzigen"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Gebruiker selecteren"</string> </resources> diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml index a69c9a90e9d2..ee96b319be71 100644 --- a/packages/SystemUI/res/values-or/strings.xml +++ b/packages/SystemUI/res/values-or/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"ପୁଣି ଆରମ୍ଭ କରନ୍ତୁ"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"ସେଟିଂସ୍"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g>ରୁ <xliff:g id="ARTIST_NAME">%2$s</xliff:g>ଙ୍କ <xliff:g id="SONG_NAME">%1$s</xliff:g> ଚାଲୁଛି"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g>ରୁ <xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"ଚଲାନ୍ତୁ"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> ଖୋଲନ୍ତୁ"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="APP_LABEL">%3$s</xliff:g>ରୁ <xliff:g id="ARTIST_NAME">%2$s</xliff:g>ଙ୍କ <xliff:g id="SONG_NAME">%1$s</xliff:g> ଚଲାନ୍ତୁ"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"ବର୍ତ୍ତମାନ ପାଇଁ ୱାଇ-ଫାଇ ସ୍ୱତଃ-ସଂଯୋଗ ହେବ ନାହିଁ"</string> <string name="see_all_networks" msgid="3773666844913168122">"ସବୁ ଦେଖନ୍ତୁ"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ନେଟୱାର୍କ ସ୍ୱିଚ୍ କରିବାକୁ, ଇଥରନେଟ୍ ବିଚ୍ଛିନ୍ନ କରନ୍ତୁ"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"ଡିଭାଇସ ଅନୁଭୂତିକୁ ଉନ୍ନତ କରିବା ପାଇଁ, ୱାଇ-ଫାଇ ବନ୍ଦ ଥିଲେ ମଧ୍ୟ ଆପ ଓ ସେବାଗୁଡ଼ିକ ଏବେ ବି ଯେ କୌଣସି ସମୟରେ ୱାଇ-ଫାଇ ନେଟୱାର୍କ ପାଇଁ ସ୍କାନ କରିପାରିବ। ଆପଣ ଏହାକୁ ୱାଇ-ଫାଇ ସ୍କାନିଂ ସେଟିଂସରେ ପରିବର୍ତ୍ତନ କରିପାରିବେ। "<annotation id="link">"ପରିବର୍ତ୍ତନ କରନ୍ତୁ"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"ଉପଯୋଗକର୍ତ୍ତା ଚୟନ କର"</string> </resources> diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml index 72882633541a..80fae3d62206 100644 --- a/packages/SystemUI/res/values-pa/strings.xml +++ b/packages/SystemUI/res/values-pa/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"ਮੁੜ-ਚਾਲੂ ਕਰੋ"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"ਸੈਟਿੰਗਾਂ"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g> ਤੋਂ <xliff:g id="ARTIST_NAME">%2$s</xliff:g> ਦਾ <xliff:g id="SONG_NAME">%1$s</xliff:g> ਚੱਲ ਰਿਹਾ ਹੈ"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g> ਵਿੱਚੋਂ <xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"ਚਲਾਓ"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> ਖੋਲ੍ਹੋ"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="APP_LABEL">%3$s</xliff:g> ਤੋਂ <xliff:g id="ARTIST_NAME">%2$s</xliff:g> ਦਾ <xliff:g id="SONG_NAME">%1$s</xliff:g> ਚਲਾਓ"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"ਫ਼ਿਲਹਾਲ ਵਾਈ-ਫਾਈ ਸਵੈ-ਕਨੈਕਟ ਨਹੀਂ ਹੋਵੇਗਾ"</string> <string name="see_all_networks" msgid="3773666844913168122">"ਸਭ ਦੇਖੋ"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ਨੈੱਟਵਰਕਾਂ ਨੂੰ ਬਦਲਣ ਲਈ, ਈਥਰਨੈੱਟ ਨੂੰ ਡਿਸਕਨੈਕਟ ਕਰੋ"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"ਡੀਵਾਈਸ ਦੇ ਅਨੁਭਵ ਨੂੰ ਬਿਹਤਰ ਬਣਾਉਣ ਲਈ, ਐਪਾਂ ਅਤੇ ਸੇਵਾਵਾਂ ਕਿਸੇ ਵੀ ਸਮੇਂ ਵਾਈ-ਫਾਈ ਨੈੱਟਵਰਕਾਂ ਲਈ ਸਕੈਨ ਕਰ ਸਕਦੀਆਂ ਹਨ, ਭਾਵੇਂ ਵਾਈ-ਫਾਈ ਬੰਦ ਹੀ ਕਿਉਂ ਨਾ ਹੋਵੇ। ਤੁਸੀਂ ਇਸ ਨੂੰ ਵਾਈ‑ਫਾਈ ਸਕੈਨਿੰਗ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਜਾ ਕੇ ਬਦਲ ਸਕਦੇ ਹੋ। "<annotation id="link">"ਬਦਲੋ"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"ਵਰਤੋਂਕਾਰ ਚੁਣੋ"</string> </resources> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index b7fc15df8b55..7f8f47b187fa 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -1102,6 +1102,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Wznów"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Ustawienia"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Aplikacja <xliff:g id="APP_LABEL">%3$s</xliff:g> odtwarza utwór <xliff:g id="SONG_NAME">%1$s</xliff:g> (<xliff:g id="ARTIST_NAME">%2$s</xliff:g>)"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> z <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Odtwórz"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Otwórz aplikację <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Odtwórz utwór <xliff:g id="SONG_NAME">%1$s</xliff:g> (<xliff:g id="ARTIST_NAME">%2$s</xliff:g>) w aplikacji <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -1190,5 +1191,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi nie będzie na razie włączać się automatycznie"</string> <string name="see_all_networks" msgid="3773666844913168122">"Pokaż wszystko"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Aby przełączać sieci, odłącz Ethernet"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Aby zapewnić Ci większy komfort korzystania z urządzenia, aplikacje i usługi mogą nadal wyszukiwać sieci Wi-Fi w pobliżu nawet wtedy, gdy Wi-Fi jest wyłączone. Możesz to zmienić w ustawieniach skanowania Wi-Fi. "<annotation id="link">"Zmień"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Wybierz użytkownika"</string> </resources> diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml index ceb6ff58da96..41e5a77c5f85 100644 --- a/packages/SystemUI/res/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res/values-pt-rBR/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Retomar"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Configurações"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Tocando <xliff:g id="SONG_NAME">%1$s</xliff:g> de <xliff:g id="ARTIST_NAME">%2$s</xliff:g> no app <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> de <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Iniciar"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Abrir <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Tocar <xliff:g id="SONG_NAME">%1$s</xliff:g> de <xliff:g id="ARTIST_NAME">%2$s</xliff:g> no app <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"A conexão automática ao Wi-Fi ficará indisponível"</string> <string name="see_all_networks" msgid="3773666844913168122">"Ver tudo"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para mudar de rede, desconecte o cabo Ethernet"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Para melhorar a experiência no dispositivo, os apps e serviços ainda podem procurar redes Wi-Fi a qualquer momento, mesmo quando o Wi-Fi estiver desativado. Você pode mudar essa opção nas configurações de busca por Wi-Fi. "<annotation id="link">"Mudar"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Selecionar usuário"</string> </resources> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index a103e416c947..fa10607a4a23 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Retomar"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Definições"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> de <xliff:g id="ARTIST_NAME">%2$s</xliff:g> em reprodução a partir da app <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> de <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Reproduzir"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Abrir <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Reproduzir <xliff:g id="SONG_NAME">%1$s</xliff:g> de <xliff:g id="ARTIST_NAME">%2$s</xliff:g> a partir da app <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Por agora, o Wi-Fi não irá estabelecer lig. automaticamente"</string> <string name="see_all_networks" msgid="3773666844913168122">"Veja tudo"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para mudar de rede, desligue a Ethernet"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Para melhorar a experiência do dispositivo, as apps e os serviços podem continuar a procurar redes Wi-Fi em qualquer altura, mesmo quando o Wi-Fi está desativado. Pode alterar esta opção nas definições de procura de Wi-Fi. "<annotation id="link">"Alterar"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Selecione utilizador"</string> </resources> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index ceb6ff58da96..41e5a77c5f85 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Retomar"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Configurações"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Tocando <xliff:g id="SONG_NAME">%1$s</xliff:g> de <xliff:g id="ARTIST_NAME">%2$s</xliff:g> no app <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> de <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Iniciar"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Abrir <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Tocar <xliff:g id="SONG_NAME">%1$s</xliff:g> de <xliff:g id="ARTIST_NAME">%2$s</xliff:g> no app <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"A conexão automática ao Wi-Fi ficará indisponível"</string> <string name="see_all_networks" msgid="3773666844913168122">"Ver tudo"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para mudar de rede, desconecte o cabo Ethernet"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Para melhorar a experiência no dispositivo, os apps e serviços ainda podem procurar redes Wi-Fi a qualquer momento, mesmo quando o Wi-Fi estiver desativado. Você pode mudar essa opção nas configurações de busca por Wi-Fi. "<annotation id="link">"Mudar"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Selecionar usuário"</string> </resources> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index dba5b7db65c1..0a7ab9040d53 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -1096,6 +1096,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Reia"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Setări"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> de la <xliff:g id="ARTIST_NAME">%2$s</xliff:g> se redă în <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> din <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Redați"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Deschideți <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Redați <xliff:g id="SONG_NAME">%1$s</xliff:g> de la <xliff:g id="ARTIST_NAME">%2$s</xliff:g> în <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -1184,5 +1185,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Deocamdată, Wi-Fi nu se poate conecta automat"</string> <string name="see_all_networks" msgid="3773666844913168122">"Afișează-le pe toate"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Pentru a schimba rețeaua, deconectați ethernet"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Pentru a îmbunătăți experiența cu dispozitivul, aplicațiile și serviciile pot să caute în continuare rețele Wi‑Fi chiar și atunci când conexiunea Wi-Fi este dezactivată. Puteți să schimbați acest aspect din setările pentru căutarea de rețele Wi-Fi. "<annotation id="link">"Schimbați"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Alegeți utilizatorul"</string> </resources> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index 808cb54d5af2..77677613d7f2 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -1102,6 +1102,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Возобновить"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Настройки"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Воспроизводится медиафайл \"<xliff:g id="SONG_NAME">%1$s</xliff:g>\" (исполнитель: <xliff:g id="ARTIST_NAME">%2$s</xliff:g>) из приложения \"<xliff:g id="APP_LABEL">%3$s</xliff:g>\"."</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> из <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Воспроизведение"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Открыть приложение \"<xliff:g id="APP_LABEL">%1$s</xliff:g>\""</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Воспроизвести медиафайл \"<xliff:g id="SONG_NAME">%1$s</xliff:g>\" (исполнитель: <xliff:g id="ARTIST_NAME">%2$s</xliff:g>) из приложения \"<xliff:g id="APP_LABEL">%3$s</xliff:g>\""</string> @@ -1190,5 +1191,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Подключение по Wi-Fi не установится автоматически."</string> <string name="see_all_networks" msgid="3773666844913168122">"Показать все"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Чтобы переключиться между сетями, отключите кабель Ethernet."</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Чтобы улучшать работу устройства, приложения и сервисы могут искать беспроводные сети в любое время, даже если вы отключили Wi‑Fi. Чтобы запретить это, отключите поиск сетей Wi‑Fi. "<annotation id="link">"Открыть настройки"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Выберите профиль"</string> </resources> diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml index a81292ca95e5..a42544e908bb 100644 --- a/packages/SystemUI/res/values-si/strings.xml +++ b/packages/SystemUI/res/values-si/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"නැවත පටන් ගන්න"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"සැකසීම්"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g>ගේ <xliff:g id="SONG_NAME">%1$s</xliff:g> ගීතය <xliff:g id="APP_LABEL">%3$s</xliff:g> වෙතින් ධාවනය වෙමින් පවතී"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g>කින් <xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"වාදනය කරන්න"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> විවෘත කරන්න"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g>ගේ <xliff:g id="SONG_NAME">%1$s</xliff:g> <xliff:g id="APP_LABEL">%3$s</xliff:g> වෙතින් වාදනය කරන්න"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi දැනට ස්වයං-සබැඳි නොවනු ඇත"</string> <string name="see_all_networks" msgid="3773666844913168122">"සියල්ල බලන්න"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ජාල මාරු කිරීමට, ඊතර්නෙට් විසන්ධි කරන්න"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"උපාංග අත්දැකීම වැඩි දියුණු කිරිමට, Wi‑Fi ක්රියාවිරහිත විට පවා, ඕනෑම අවස්ථාවක Wi‑Fi ජාල සඳහා ස්කෑන් කිරීමට යෙදුම් සහ සේවාවලට හැකිය. ඔබට මෙය Wi‑Fi ස්කෑන් කිරීමේ සැකසීම් තුළ වෙනස් කළ හැකිය. "<annotation id="link">"වෙනස් කරන්න"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"පරිශීලක තෝරන්න"</string> </resources> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index a2cb0d6d8e08..8bb7b4a56637 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -1102,6 +1102,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Pokračovať"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Nastavenia"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> od interpreta <xliff:g id="ARTIST_NAME">%2$s</xliff:g> sa prehráva z aplikácie <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> z <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Prehrať"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Otvoriť <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Prehrať skladbu <xliff:g id="SONG_NAME">%1$s</xliff:g> od interpreta <xliff:g id="ARTIST_NAME">%2$s</xliff:g> z aplikácie <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -1190,5 +1191,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi‑Fi sa teraz automaticky nepripojí"</string> <string name="see_all_networks" msgid="3773666844913168122">"Zobraziť všetko"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Ak chcete prepnúť siete, odpojte ethernet"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Aplikácie a služby môžu kedykoľvek vyhľadávať siete Wi‑Fi (a to aj vtedy, keď je pripojenie Wi‑Fi vypnuté), čím zlepšujú prostredie v zariadení. Môžete to zmeniť v nastaveniach vyhľadávania sietí Wi‑Fi. "<annotation id="link">"Zmeniť"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Vyberte používateľa"</string> </resources> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index 5092c030ae0b..1e5c20ea9593 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -1102,6 +1102,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Nadaljuj"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Nastavitve"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Skladba <xliff:g id="SONG_NAME">%1$s</xliff:g> izvajalca <xliff:g id="ARTIST_NAME">%2$s</xliff:g> se predvaja iz aplikacije <xliff:g id="APP_LABEL">%3$s</xliff:g>."</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> od <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Predvajaj"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Odpri aplikacijo <xliff:g id="APP_LABEL">%1$s</xliff:g>."</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Predvajaj skladbo <xliff:g id="SONG_NAME">%1$s</xliff:g> izvajalca <xliff:g id="ARTIST_NAME">%2$s</xliff:g> iz aplikacije <xliff:g id="APP_LABEL">%3$s</xliff:g>."</string> @@ -1190,5 +1191,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Vmesnik Wi-Fi trenutno ne bo samodejno vzpostavil povezave."</string> <string name="see_all_networks" msgid="3773666844913168122">"Prikaz vseh omrežij"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Če želite preklopiti omrežje, prekinite ethernetno povezavo."</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Za izboljšano izkušnjo pri uporabi naprave lahko aplikacije in storitve kadar koli iščejo omrežja Wi‑Fi, tudi ko je Wi‑Fi izklopljen. To lahko spremenite v nastavitvah iskanja omrežij Wi-Fi. "<annotation id="link">"Spremeni"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Izberite uporabnika"</string> </resources> diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml index adb773d168ed..a8b0db18cb71 100644 --- a/packages/SystemUI/res/values-sq/strings.xml +++ b/packages/SystemUI/res/values-sq/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Vazhdo"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Cilësimet"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> nga <xliff:g id="ARTIST_NAME">%2$s</xliff:g> po luhet nga <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> nga <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Luaj"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Hap <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Luaj <xliff:g id="SONG_NAME">%1$s</xliff:g> nga <xliff:g id="ARTIST_NAME">%2$s</xliff:g> nga <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi nuk do të lidhet automatikisht për momentin"</string> <string name="see_all_networks" msgid="3773666844913168122">"Shiko të gjitha"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Për të ndërruar rrjetet, shkëput Ethernet-in"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Për të përmirësuar përvojën e pajisjes, aplikacionet dhe shërbimet mund të vazhdojnë të skanojnë për rrjete Wi-Fi në çdo kohë, edhe kur Wi-Fi është joaktiv. Mund ta ndryshosh këtë te cilësimet e skanimit të Wi-Fi. "<annotation id="link">"Ndrysho"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Zgjidh përdoruesin"</string> </resources> diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index a3f85c97801d..c2d665450caf 100644 --- a/packages/SystemUI/res/values-sr/strings.xml +++ b/packages/SystemUI/res/values-sr/strings.xml @@ -1096,6 +1096,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Настави"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Подешавања"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> извођача <xliff:g id="ARTIST_NAME">%2$s</xliff:g> се пушта из апликације <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> од <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Пусти"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Отворите <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Пустите <xliff:g id="SONG_NAME">%1$s</xliff:g> извођача <xliff:g id="ARTIST_NAME">%2$s</xliff:g> из апликације <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -1184,5 +1185,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"WiFi тренутно не може да се аутоматски повеже"</string> <string name="see_all_networks" msgid="3773666844913168122">"Погледајте све"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Да бисте променили мрежу, прекините етернет везу"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Ради бољег доживљаја уређаја, апликације и услуге и даље могу да траже WiFi мреже у било ком тренутку, чак и када је WiFi искључен. То можете да промените у подешавањима WiFi скенирања. "<annotation id="link">"Промените"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Изаберите корисника"</string> </resources> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index 6073c7d1a49d..7474e2f9310b 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Återuppta"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Inställningar"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> med <xliff:g id="ARTIST_NAME">%2$s</xliff:g> spelas upp från <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> av <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Spela upp"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Öppna <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Spela upp <xliff:g id="SONG_NAME">%1$s</xliff:g> med <xliff:g id="ARTIST_NAME">%2$s</xliff:g> från <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Du ansluts inte till wifi automatiskt för närvarande"</string> <string name="see_all_networks" msgid="3773666844913168122">"Visa alla"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Koppla bort Ethernet för att växla nätverk"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"I syfte att förbättra upplevelsen med enheten kan appar och tjänster fortfarande söka efter wifi-nätverk när som helst, även om wifi har inaktiverats. "<annotation id="link">"Ändra"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Välj användare"</string> </resources> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index 5856a61924b4..85fc39551127 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Endelea"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Mipangilio"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> ulioimbwa na <xliff:g id="ARTIST_NAME">%2$s</xliff:g> unacheza katika <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> kati ya <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Cheza"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Fungua <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Cheza <xliff:g id="SONG_NAME">%1$s</xliff:g> ulioimbwa na <xliff:g id="ARTIST_NAME">%2$s</xliff:g> katika <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi haitaunganishwa kiotomatiki kwa sasa"</string> <string name="see_all_networks" msgid="3773666844913168122">"Angalia yote"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Ili kubadili mitandao, tenganisha ethaneti"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Ili kuboresha hali ya matumizi ya kifaa, programu na huduma bado zinaweza kutafuta mitandao ya Wi‑Fi wakati wowote, hata wakati umezima Wi‑Fi. Unaweza kubadilisha mipangilio hii katika mipangilio ya kutafuta Wi-Fi. "<annotation id="link">"Badilisha"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Chagua mtumiaji"</string> </resources> diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml index 8daa24f4731a..413149ba5391 100644 --- a/packages/SystemUI/res/values-ta/strings.xml +++ b/packages/SystemUI/res/values-ta/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"தொடர்க"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"அமைப்புகள்"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> இன் <xliff:g id="SONG_NAME">%1$s</xliff:g> பாடல் <xliff:g id="APP_LABEL">%3$s</xliff:g> ஆப்ஸில் பிளேயாகிறது"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> / <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"இயக்குதல்"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> ஆப்ஸைத் திறங்கள்"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> இன் <xliff:g id="SONG_NAME">%1$s</xliff:g> பாடலை <xliff:g id="APP_LABEL">%3$s</xliff:g> ஆப்ஸில் பிளேசெய்"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"தற்போதைக்கு வைஃபை தானாக இணைக்கப்படாது"</string> <string name="see_all_networks" msgid="3773666844913168122">"அனைத்தையும் காட்டு"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"நெட்வொர்க்குகளை மாற்ற ஈதர்நெட் இணைப்பைத் துண்டிக்கவும்"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"சாதன அனுபவத்தை மேம்படுத்த, வைஃபை ஆஃப் செய்யப்பட்டிருந்தாலும்கூட எந்த நேரத்திலும் ஆப்ஸும் சேவைகளும் வைஃபை நெட்வொர்க்குகளைத் தேடலாம். வைஃபை ஸ்கேனிங் அமைப்புகளில் இதை மாற்றிக் கொள்ளலாம். "<annotation id="link">"மாற்று"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"பயனரைத் தேர்வுசெய்க"</string> </resources> diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml index cab7b1c80ef2..41f45d7a17c8 100644 --- a/packages/SystemUI/res/values-te/strings.xml +++ b/packages/SystemUI/res/values-te/strings.xml @@ -563,30 +563,30 @@ <string name="monitoring_description_ca_certificate" msgid="448923057059097497">"ఈ పరికరంలో ప్రమాణపత్ర అధికారం ఇన్స్టాల్ చేయబడింది. మీ సురక్షిత నెట్వర్క్ ట్రాఫిక్ పర్యవేక్షించబడవచ్చు లేదా సవరించబడవచ్చు."</string> <string name="monitoring_description_management_network_logging" msgid="216983105036994771">"మీ నిర్వాహకులు మీ పరికరంలోని ట్రాఫిక్ని పర్యవేక్షించగల నెట్వర్క్ లాగింగ్ని ఆన్ చేశారు."</string> <string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"మీ అడ్మిన్ నెట్వర్క్ లాగింగ్ను ఆన్ చేశారు, ఇది మీ వర్క్ ప్రొఫైల్లోని ట్రాఫిక్ను పర్యవేక్షిస్తుంది కానీ మీ వ్యక్తిగత ప్రొఫైల్లో కాదు."</string> - <string name="monitoring_description_named_vpn" msgid="5749932930634037027">"మీరు <xliff:g id="VPN_APP">%1$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు, ఇది ఇమెయిల్లు, యాప్లు మరియు వెబ్సైట్లతో సహా మీ నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string> - <string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"మీరు ఇమెయిల్లు, యాప్లు మరియు వెబ్సైట్లతో సహా మీ నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగల <xliff:g id="VPN_APP_0">%1$s</xliff:g> మరియు <xliff:g id="VPN_APP_1">%2$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు."</string> - <string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"మీ కార్యాలయ ప్రొఫైల్ ఇమెయిల్లు, యాప్లు మరియు వెబ్సైట్లతో సహా మీ నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగల <xliff:g id="VPN_APP">%1$s</xliff:g>కి కనెక్ట్ చేయబడింది."</string> - <string name="monitoring_description_personal_profile_named_vpn" msgid="8179722332380953673">"మీ వ్యక్తిగత ప్రొఫైల్ ఇమెయిల్లు, యాప్లు మరియు వెబ్సైట్లతో సహా మీ నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగల <xliff:g id="VPN_APP">%1$s</xliff:g>కి కనెక్ట్ చేయబడింది."</string> + <string name="monitoring_description_named_vpn" msgid="5749932930634037027">"మీరు <xliff:g id="VPN_APP">%1$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు, ఇది ఈమెయిళ్లు, యాప్లు మరియు వెబ్సైట్లతో సహా మీ నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string> + <string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"మీరు ఈమెయిళ్లు, యాప్లు మరియు వెబ్సైట్లతో సహా మీ నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగల <xliff:g id="VPN_APP_0">%1$s</xliff:g> మరియు <xliff:g id="VPN_APP_1">%2$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు."</string> + <string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"మీ కార్యాలయ ప్రొఫైల్ ఈమెయిళ్లు, యాప్లు మరియు వెబ్సైట్లతో సహా మీ నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగల <xliff:g id="VPN_APP">%1$s</xliff:g>కి కనెక్ట్ చేయబడింది."</string> + <string name="monitoring_description_personal_profile_named_vpn" msgid="8179722332380953673">"మీ వ్యక్తిగత ప్రొఫైల్ ఈమెయిళ్లు, యాప్లు మరియు వెబ్సైట్లతో సహా మీ నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగల <xliff:g id="VPN_APP">%1$s</xliff:g>కి కనెక్ట్ చేయబడింది."</string> <string name="monitoring_description_do_header_generic" msgid="6130190408164834986">"మీ పరికరం <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> ద్వారా నిర్వహించబడుతోంది."</string> <string name="monitoring_description_do_header_with_name" msgid="2696255132542779511">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> మీ పరికరాన్ని నిర్వహించడానికి <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g>ని ఉపయోగిస్తుంది."</string> <string name="monitoring_description_do_body" msgid="7700878065625769970">"మీ పరికరంతో అనుబంధించబడిన సెట్టింగ్లు, కార్పొరేట్ యాక్సెస్, యాప్లు, డేటా మరియు మీ పరికరం యొక్క లొకేషన్ సమాచారాన్ని మీ అడ్మిన్ పర్యవేక్షించగలరు, మేనేజ్ చేయగలరు."</string> <string name="monitoring_description_do_learn_more_separator" msgid="1467280496376492558">" "</string> <string name="monitoring_description_do_learn_more" msgid="645149183455573790">"మరింత తెలుసుకోండి"</string> - <string name="monitoring_description_do_body_vpn" msgid="7699280130070502303">"మీరు <xliff:g id="VPN_APP">%1$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు, ఇది ఇమెయిల్లు, యాప్లు మరియు వెబ్సైట్లతో సహా మీ వ్యక్తిగత నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string> + <string name="monitoring_description_do_body_vpn" msgid="7699280130070502303">"మీరు <xliff:g id="VPN_APP">%1$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు, ఇది ఈమెయిళ్లు, యాప్లు మరియు వెబ్సైట్లతో సహా మీ వ్యక్తిగత నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string> <string name="monitoring_description_vpn_settings_separator" msgid="8292589617720435430">" "</string> <string name="monitoring_description_vpn_settings" msgid="5264167033247632071">"VPN సెట్టింగ్లను తెరవండి"</string> <string name="monitoring_description_ca_cert_settings_separator" msgid="7107390013344435439">" "</string> <string name="monitoring_description_ca_cert_settings" msgid="8329781950135541003">"విశ్వసనీయ ఆధారాలను తెరువు"</string> <string name="monitoring_description_network_logging" msgid="577305979174002252">"మీ నిర్వాహకులు మీ పరికరంలోని ట్రాఫిక్ని పర్యవేక్షించగల నెట్వర్క్ లాగింగ్ని ఆన్ చేశారు.\n\nమరింత సమాచారం కావాలంటే, మీ నిర్వాహకులను సంప్రదించండి."</string> - <string name="monitoring_description_vpn" msgid="1685428000684586870">"మీరు VPN కనెక్షన్ సెటప్ చేయడానికి ఒక యాప్నకు అనుమతి ఇచ్చారు.\n\nఈ యాప్ ఇమెయిల్లు,యాప్లు మరియు వెబ్సైట్లతో సహా మీ డివైజ్ మరియు నెట్వర్క్ యాక్టివిటీని పర్యవేక్షించగలదు."</string> - <string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> ద్వారా మీ కార్యాలయ ప్రొఫైల్ నిర్వహించబడుతోంది.\n\nఇమెయిల్లు, యాప్లు మరియు వెబ్సైట్లతో సహా మీ నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగల సామర్థ్యం మీ నిర్వాహకులకు ఉంది.\n\nమరింత సమాచారం కావాలంటే, మీ నిర్వాహకులను సంప్రదించండి.\n\nమీరు VPNకి కూడా కనెక్ట్ అయ్యారు, ఇది మీ నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string> + <string name="monitoring_description_vpn" msgid="1685428000684586870">"మీరు VPN కనెక్షన్ సెటప్ చేయడానికి ఒక యాప్నకు అనుమతి ఇచ్చారు.\n\nఈ యాప్ ఈమెయిళ్లు,యాప్లు మరియు వెబ్సైట్లతో సహా మీ డివైజ్ మరియు నెట్వర్క్ యాక్టివిటీని పర్యవేక్షించగలదు."</string> + <string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> ద్వారా మీ కార్యాలయ ప్రొఫైల్ నిర్వహించబడుతోంది.\n\nఈమెయిళ్లు, యాప్లు మరియు వెబ్సైట్లతో సహా మీ నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగల సామర్థ్యం మీ నిర్వాహకులకు ఉంది.\n\nమరింత సమాచారం కావాలంటే, మీ నిర్వాహకులను సంప్రదించండి.\n\nమీరు VPNకి కూడా కనెక్ట్ అయ్యారు, ఇది మీ నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string> <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"ఈ పరికరాన్ని మీ తల్లి/తండ్రి మేనేజ్ చేస్తున్నారు. మీ తల్లి/తండ్రి, మీరు ఉపయోగించే యాప్లు, మీ లొకేషన్, అలాగే మీ పరికర వినియోగ వ్యవధి వంటి సమాచారాన్ని చూడగలరు, మేనేజ్ చేయగలరు."</string> <string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string> - <string name="monitoring_description_app" msgid="376868879287922929">"మీరు ఇమెయిల్లు, యాప్లు మరియు వెబ్సైట్లతో సహా మీ నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగల <xliff:g id="APPLICATION">%1$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు."</string> - <string name="monitoring_description_app_personal" msgid="1970094872688265987">"మీరు <xliff:g id="APPLICATION">%1$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు, ఇది ఇమెయిల్లు, యాప్లు మరియు వెబ్సైట్లతో సహా మీ వ్యక్తిగత నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string> - <string name="branded_monitoring_description_app_personal" msgid="1703511985892688885">"మీరు <xliff:g id="APPLICATION">%1$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు, ఇది ఇమెయిల్లు, యాప్లు మరియు వెబ్సైట్లతో సహా మీ వ్యక్తిగత నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string> - <string name="monitoring_description_app_work" msgid="3713084153786663662">"మీ కార్యాలయ ప్రొఫైల్ <xliff:g id="ORGANIZATION">%1$s</xliff:g> నిర్వహణలో ఉంది. ఇమెయిల్లు, యాప్లు మరియు వెబ్సైట్లతో సహా మీ కార్యాలయ నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగల <xliff:g id="APPLICATION">%2$s</xliff:g>కి ప్రొఫైల్ కనెక్ట్ చేయబడింది.\n\nమరింత సమాచారం కోసం, మీ నిర్వాహకులను సంప్రదించండి."</string> - <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"మీ కార్యాలయ ప్రొఫైల్ <xliff:g id="ORGANIZATION">%1$s</xliff:g> నిర్వహణలో ఉంది. ఇమెయిల్లు, యాప్లు మరియు వెబ్సైట్లతో సహా మీ కార్యాలయ నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగల <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>కి ప్రొఫైల్ కనెక్ట్ చేయబడింది.\n\nమీ వ్యక్తిగత నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగల <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>కి కూడా మీరు కనెక్ట్ చేయబడ్డారు."</string> + <string name="monitoring_description_app" msgid="376868879287922929">"మీరు ఈమెయిళ్లు, యాప్లు మరియు వెబ్సైట్లతో సహా మీ నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగల <xliff:g id="APPLICATION">%1$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు."</string> + <string name="monitoring_description_app_personal" msgid="1970094872688265987">"మీరు <xliff:g id="APPLICATION">%1$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు, ఇది ఈమెయిళ్లు, యాప్లు మరియు వెబ్సైట్లతో సహా మీ వ్యక్తిగత నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string> + <string name="branded_monitoring_description_app_personal" msgid="1703511985892688885">"మీరు <xliff:g id="APPLICATION">%1$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు, ఇది ఈమెయిళ్లు, యాప్లు మరియు వెబ్సైట్లతో సహా మీ వ్యక్తిగత నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string> + <string name="monitoring_description_app_work" msgid="3713084153786663662">"మీ కార్యాలయ ప్రొఫైల్ <xliff:g id="ORGANIZATION">%1$s</xliff:g> నిర్వహణలో ఉంది. ఈమెయిళ్లు, యాప్లు మరియు వెబ్సైట్లతో సహా మీ కార్యాలయ నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగల <xliff:g id="APPLICATION">%2$s</xliff:g>కి ప్రొఫైల్ కనెక్ట్ చేయబడింది.\n\nమరింత సమాచారం కోసం, మీ నిర్వాహకులను సంప్రదించండి."</string> + <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"మీ కార్యాలయ ప్రొఫైల్ <xliff:g id="ORGANIZATION">%1$s</xliff:g> నిర్వహణలో ఉంది. ఈమెయిళ్లు, యాప్లు మరియు వెబ్సైట్లతో సహా మీ కార్యాలయ నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగల <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>కి ప్రొఫైల్ కనెక్ట్ చేయబడింది.\n\nమీ వ్యక్తిగత నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగల <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>కి కూడా మీరు కనెక్ట్ చేయబడ్డారు."</string> <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent ద్వారా అన్లాక్ చేయబడింది"</string> <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"మీరు మాన్యువల్గా అన్లాక్ చేస్తే మినహా పరికరం లాక్ చేయబడి ఉంటుంది"</string> <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string> @@ -611,7 +611,7 @@ <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"మీరు అన్పిన్ చేసే వరకు ఇది వీక్షణలో ఉంచబడుతుంది. అన్పిన్ చేయడానికి, పైకి స్వైప్ చేసి & పట్టుకోండి."</string> <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"దీని వలన మీరు అన్పిన్ చేసే వరకు ఇది వీక్షణలో ఉంచబడుతుంది. అన్పిన్ చేయడానికి స్థూలదృష్టిని తాకి & అలాగే పట్టుకోండి."</string> <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"దీని వలన మీరు అన్పిన్ చేసే వరకు ఇది వీక్షణలో ఉంచబడుతుంది. అన్పిన్ చేయడానికి హోమ్ని తాకి & అలాగే పట్టుకోండి."</string> - <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"వ్యక్తిగత డేటా (కాంటాక్ట్లు, ఇంకా ఇమెయిల్ కంటెంట్ లాంటివి) యాక్సెస్ చేయబడవచ్చు."</string> + <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"వ్యక్తిగత డేటా (కాంటాక్ట్లు, ఇంకా ఈమెయిల్ కంటెంట్ లాంటివి) యాక్సెస్ చేయబడవచ్చు."</string> <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"పిన్ చేయబడిన యాప్ ఇతర యాప్లను తెరవవచ్చు."</string> <string name="screen_pinning_toast" msgid="8177286912533744328">"ఈ యాప్ను అన్పిన్ చేయడానికి, \'వెనుకకు\', \'ఓవర్వ్యూ\' బటన్లను తాకి & అలాగే పట్టుకోండి"</string> <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"ఈ యాప్ను అన్పిన్ చేయడానికి, వెనుకకు, హోమ్ బటన్లను తాకి & అలాగే పట్టుకోండి"</string> @@ -844,7 +844,7 @@ <string name="keyboard_shortcut_group_applications_assist" msgid="771606231466098742">"సహాయకం"</string> <string name="keyboard_shortcut_group_applications_browser" msgid="2776211137869809251">"బ్రౌజర్"</string> <string name="keyboard_shortcut_group_applications_contacts" msgid="2807268086386201060">"కాంటాక్ట్లు"</string> - <string name="keyboard_shortcut_group_applications_email" msgid="7852376788894975192">"ఇమెయిల్"</string> + <string name="keyboard_shortcut_group_applications_email" msgid="7852376788894975192">"ఈమెయిల్"</string> <string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string> <string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"మ్యూజిక్"</string> <string name="keyboard_shortcut_group_applications_youtube" msgid="5078136084632450333">"YouTube"</string> @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"కొనసాగించండి"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"సెట్టింగ్లు"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> పాడిన <xliff:g id="SONG_NAME">%1$s</xliff:g> <xliff:g id="APP_LABEL">%3$s</xliff:g> నుండి ప్లే అవుతోంది"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="TOTAL_TIME">%2$s</xliff:g>లో <xliff:g id="ELAPSED_TIME">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"ప్లే చేయండి"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g>ను తెరవండి"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="APP_LABEL">%3$s</xliff:g> నుండి <xliff:g id="ARTIST_NAME">%2$s</xliff:g> పాడిన <xliff:g id="SONG_NAME">%1$s</xliff:g>ను ప్లే చేయండి"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"ప్రస్తుతానికి Wi-Fi ఆటోమేటిక్గా కనెక్ట్ అవ్వదు"</string> <string name="see_all_networks" msgid="3773666844913168122">"అన్నీ చూడండి"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"నెట్వర్క్లను మార్చడానికి, ఈథర్నెట్ను డిస్కనెక్ట్ చేయండి"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"పరికర అనుభవాన్ని మెరుగుపరచడానికి, Wi‑Fi ఆఫ్లో ఉన్నప్పుడు కూడా, ఏ సమయంలో అయినా ఇప్పటికీ Wi‑Fi నెట్వర్క్ల కోసం యాప్లు, సర్వీస్లు స్కాన్ చేయగలవు. మీరు దీనిని Wi‑Fi స్కానింగ్ సెట్టింగ్లలో మార్చవచ్చు. "<annotation id="link">"మార్చండి"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"యూజర్ను ఎంచుకోండి"</string> </resources> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index 6da88882859f..75314ee0a525 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"เล่นต่อ"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"การตั้งค่า"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"กำลังเปิดเพลง <xliff:g id="SONG_NAME">%1$s</xliff:g> ของ <xliff:g id="ARTIST_NAME">%2$s</xliff:g> จาก <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> จาก <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"เล่น"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"เปิด <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"เปิดเพลง <xliff:g id="SONG_NAME">%1$s</xliff:g> ของ <xliff:g id="ARTIST_NAME">%2$s</xliff:g> จาก <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi จะไม่เชื่อมต่ออัตโนมัติในตอนนี้"</string> <string name="see_all_networks" msgid="3773666844913168122">"ดูทั้งหมด"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ตัดการเชื่อมต่ออีเทอร์เน็ตเพื่อสลับเครือข่าย"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"เพื่อปรับปรุงประสบการณ์การใช้อุปกรณ์ แอปและบริการต่างๆ จะยังคงสแกนหาเครือข่าย Wi‑Fi ได้ทุกเมื่อแม้ว่า Wi‑Fi จะปิดอยู่ คุณเปลี่ยนตัวเลือกนี้ได้ในการตั้งค่าการสแกนหา Wi-Fi "<annotation id="link">"เปลี่ยน"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"เลือกผู้ใช้"</string> </resources> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index a9c588699311..baefb76e6685 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Ituloy"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Mga Setting"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Nagpe-play ang <xliff:g id="SONG_NAME">%1$s</xliff:g> ni/ng <xliff:g id="ARTIST_NAME">%2$s</xliff:g> mula sa <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> sa <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"I-play"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Buksan ang <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"I-play ang <xliff:g id="SONG_NAME">%1$s</xliff:g> ni/ng <xliff:g id="ARTIST_NAME">%2$s</xliff:g> mula sa <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Hindi awtomatikong kokonekta ang Wi-Fi sa ngayon"</string> <string name="see_all_networks" msgid="3773666844913168122">"Tingnan lahat"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para lumipat ng network, idiskonekta ang ethernet"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Para pahusayin ang karanasan sa device, puwede pa ring mag-scan ng mga Wi-Fi network ang mga app at serbisyo anumang oras, kahit habang naka-off ang Wi‑Fi. Mababago mo ito sa mga setting ng pag-scan ng Wi-Fi. "<annotation id="link">"Baguhin"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Pumili ng user"</string> </resources> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index 8fe7862d1469..905b34c610e0 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Devam ettir"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Ayarlar"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g> uygulamasından <xliff:g id="ARTIST_NAME">%2$s</xliff:g>, <xliff:g id="SONG_NAME">%1$s</xliff:g> şarkısı çalıyor"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g>/<xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Oynat"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> uygulamasını aç"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="APP_LABEL">%3$s</xliff:g> uygulamasından <xliff:g id="ARTIST_NAME">%2$s</xliff:g>, <xliff:g id="SONG_NAME">%1$s</xliff:g> şarkısını çal"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Şu anda kablosuz ağa otomatik olarak bağlanılamıyor"</string> <string name="see_all_networks" msgid="3773666844913168122">"Tümünü göster"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Ağ değiştirmek için ethernet bağlantısını kesin"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Uygulamalar ve hizmetler, cihaz deneyimini iyileştirmek için Kablosuz özelliği kapalı bile olsa kablosuz ağlar herhangi bir zamanda tarayabilir. Bunu kablosuz ağ taraması ayarlarından değiştirebilirsiniz. "<annotation id="link">"Değiştir"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Kullanıcı seçin"</string> </resources> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index 596ba953844e..7f6f91086b0a 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -1102,6 +1102,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Відновити"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Налаштування"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Пісня \"<xliff:g id="SONG_NAME">%1$s</xliff:g>\", яку виконує <xliff:g id="ARTIST_NAME">%2$s</xliff:g>, грає в додатку <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> з <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Відтворення"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Відкрити додаток <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Увімкнути пісню \"<xliff:g id="SONG_NAME">%1$s</xliff:g>\", яку виконує <xliff:g id="ARTIST_NAME">%2$s</xliff:g>, у додатку <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -1190,5 +1191,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Пристрій не підключатиметься до Wi-Fi автоматично"</string> <string name="see_all_networks" msgid="3773666844913168122">"Показати все"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Щоб вибрати іншу мережу, від’єднайте кабель Ethernet"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Щоб користуватися пристроєм було зручніше, додатки й сервіси можуть шукати бездротові мережі, навіть якщо Wi-Fi вимкнено. Це налаштування можна змінити в параметрах пошуку мереж Wi-Fi. "<annotation id="link">"Змінити"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Виберіть користувача"</string> </resources> diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml index f05c709d131b..4dcfc09889b7 100644 --- a/packages/SystemUI/res/values-ur/strings.xml +++ b/packages/SystemUI/res/values-ur/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"دوبارہ شروع کریں"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"ترتیبات"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g> سے <xliff:g id="ARTIST_NAME">%2$s</xliff:g> کا <xliff:g id="SONG_NAME">%1$s</xliff:g> چل رہا ہے"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> از <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"چلائیں"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> کھولیں"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="APP_LABEL">%3$s</xliff:g> سے <xliff:g id="ARTIST_NAME">%2$s</xliff:g> کا <xliff:g id="SONG_NAME">%1$s</xliff:g> چلائیں"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"ابھی Wi-Fi خود کار طور پر منسلک نہیں ہوگا"</string> <string name="see_all_networks" msgid="3773666844913168122">"سبھی دیکھیں"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"نیٹ ورکس پر سوئچ کرنے کیلئے، ایتھرنیٹ غیر منسلک کریں"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"آلے کے تجربے کو بہتر بنانے کے لیے، Wi‑Fi کے آف ہونے پر بھی ایپس اور سروسز کسی بھی وقت Wi‑Fi نیٹ ورکس اسکین کر سکتی ہیں۔ آپ اسے Wi‑Fi اسکیننگ کی ترتیبات میں تبدیل کر سکتے ہیں۔ "<annotation id="link">"تبدیل کریں"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"صارف منتخب کریں"</string> </resources> diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml index e9c20a92219f..5d135423bbe2 100644 --- a/packages/SystemUI/res/values-uz/strings.xml +++ b/packages/SystemUI/res/values-uz/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Davom etish"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Sozlamalar"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g> ilovasida ijro etilmoqda: <xliff:g id="SONG_NAME">%1$s</xliff:g> – <xliff:g id="ARTIST_NAME">%2$s</xliff:g>"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> / <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Ijro"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g> ilovasini ochish"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="APP_LABEL">%3$s</xliff:g> ilovasida ijro etish: <xliff:g id="SONG_NAME">%1$s</xliff:g> – <xliff:g id="ARTIST_NAME">%2$s</xliff:g>"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi hozir avtomatik ulanmaydi"</string> <string name="see_all_networks" msgid="3773666844913168122">"Hammasi"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Boshqa tarmoqqa almashish uchun Ethernet tarmogʻini uzing"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Qurilma ishlashini yaxshilash uchun ilova va xizmatlar hatto Wi-Fi yoqilmaganda ham istalgan vaqt Wi-Fi tarmoqlarni qidirishi mumkin. Buni taqiqlash uchun Wi-Fi tarmoqlarni qidirish funksiyasini faolsizlantiring. "<annotation id="link">"Sozlamalarni ochish"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Foydalanuvchini tanlang"</string> </resources> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index 07a08ad1270c..810f31dcf22a 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Tiếp tục"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Cài đặt"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Đang phát <xliff:g id="SONG_NAME">%1$s</xliff:g> của <xliff:g id="ARTIST_NAME">%2$s</xliff:g> trên <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g>/<xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Phát"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Mở <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Phát <xliff:g id="SONG_NAME">%1$s</xliff:g> của <xliff:g id="ARTIST_NAME">%2$s</xliff:g> trên <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Tạm thời, Wi-Fi sẽ không tự động kết nối"</string> <string name="see_all_networks" msgid="3773666844913168122">"Xem tất cả"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Để chuyển mạng, hãy rút cáp Ethernet"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Để cải thiện trải nghiệm khi dùng thiết bị, các ứng dụng và dịch vụ vẫn có thể quét tìm mạng Wi‑Fi bất cứ lúc nào, ngay cả khi Wi‑Fi tắt. Bạn có thể thay đổi chế độ này trong phần cài đặt tính năng Quét tìm Wi‑Fi. "<annotation id="link">"Thay đổi"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Chọn người dùng"</string> </resources> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index 377d15cba0e3..b7a475d1de63 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"继续播放"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"设置"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"正在通过<xliff:g id="APP_LABEL">%3$s</xliff:g>播放<xliff:g id="ARTIST_NAME">%2$s</xliff:g>的《<xliff:g id="SONG_NAME">%1$s</xliff:g>》"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> / <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"播放"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"打开<xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"通过<xliff:g id="APP_LABEL">%3$s</xliff:g>播放<xliff:g id="ARTIST_NAME">%2$s</xliff:g>的《<xliff:g id="SONG_NAME">%1$s</xliff:g>》"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"WLAN 暂时无法自动连接"</string> <string name="see_all_networks" msgid="3773666844913168122">"查看全部"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"如要切换网络,请断开以太网连接"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"为了提升设备的使用体验,即使 WLAN 已关闭,应用和服务仍可以随时扫描 WLAN 网络。您可以在 WLAN 扫描设置中更改此设置。"<annotation id="link">"更改"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"选择用户"</string> </resources> diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml index 73df468c1aa2..df207ad69ce1 100644 --- a/packages/SystemUI/res/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"繼續播放"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"設定"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"正在透過 <xliff:g id="APP_LABEL">%3$s</xliff:g> 播放 <xliff:g id="ARTIST_NAME">%2$s</xliff:g> 的《<xliff:g id="SONG_NAME">%1$s</xliff:g>》"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g>/<xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"播放"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"開啟 <xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"在 <xliff:g id="APP_LABEL">%3$s</xliff:g> 播放 <xliff:g id="ARTIST_NAME">%2$s</xliff:g> 的《<xliff:g id="SONG_NAME">%1$s</xliff:g>》"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"目前系統不會自動連線至 Wi-Fi"</string> <string name="see_all_networks" msgid="3773666844913168122">"顯示全部"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"如要切換網絡,請中斷以太網連線"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"為改善裝置的使用體驗,應用程式和服務仍可隨時掃瞄 Wi-Fi 網絡 (即使 Wi-Fi 已關閉)。您可在 Wi-Fi 掃瞄設定中變更此設定。"<annotation id="link">"變更"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"選取使用者"</string> </resources> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index f883b1091f7b..2fb31207deaf 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"繼續播放"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"設定"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"系統正透過「<xliff:g id="APP_LABEL">%3$s</xliff:g>」播放<xliff:g id="ARTIST_NAME">%2$s</xliff:g>的〈<xliff:g id="SONG_NAME">%1$s</xliff:g>〉"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g>,共 <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"播放"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"開啟「<xliff:g id="APP_LABEL">%1$s</xliff:g>」"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"透過「<xliff:g id="APP_LABEL">%3$s</xliff:g>」播放<xliff:g id="ARTIST_NAME">%2$s</xliff:g>的〈<xliff:g id="SONG_NAME">%1$s</xliff:g>〉"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"目前不會自動連上 Wi-Fi"</string> <string name="see_all_networks" msgid="3773666844913168122">"查看全部"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"如要切換網路,請中斷乙太網路連線"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"為提升裝置的使用體驗,應用程式和服務仍可隨時掃描 Wi‑Fi 網路,即使 Wi-Fi 連線功能處於關閉狀態時亦然。你可以前往「掃描 Wi-Fi」設定進行變更。"<annotation id="link">"變更"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"選取使用者"</string> </resources> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index e1c1f6fa219b..96dd7ede6f2e 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -1090,6 +1090,7 @@ <string name="controls_media_resume" msgid="1933520684481586053">"Qalisa kabusha"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Izilungiselelo"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"I-<xliff:g id="SONG_NAME">%1$s</xliff:g> ka-<xliff:g id="ARTIST_NAME">%2$s</xliff:g> idlala kusuka ku-<xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> + <string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> ku-<xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Dlala"</string> <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"Vula i-<xliff:g id="APP_LABEL">%1$s</xliff:g>"</string> <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Dlala i-<xliff:g id="SONG_NAME">%1$s</xliff:g> ka-<xliff:g id="ARTIST_NAME">%2$s</xliff:g> kusuka ku-<xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -1178,5 +1179,6 @@ <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"I-Wi-Fi ngeke ixhume ngokuzenzakalelayo okwamanje"</string> <string name="see_all_networks" msgid="3773666844913168122">"Bona konke"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Ukuze ushintshe amanethiwekhi, nqamula i-ethernet"</string> + <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Ukuze kuthuthukiswe ukuzizwela kwedivayisi, ama-app namasevisi kusengakwazi ukuskena amanethiwekhi we-Wi-Fi noma kunini, ngisho noma i-Wi-Fi ivaliwe, Ungashintsha lokhu kumasethingi Wokuskena i-Wi-Fi. "<annotation id="link">"Shintsha"</annotation></string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Khetha umsebenzisi"</string> </resources> diff --git a/packages/SystemUI/res/values/flags.xml b/packages/SystemUI/res/values/flags.xml index 675838766175..c598097cd5af 100644 --- a/packages/SystemUI/res/values/flags.xml +++ b/packages/SystemUI/res/values/flags.xml @@ -18,40 +18,12 @@ <resources> <bool name="are_flags_overrideable">false</bool> - <bool name="flag_notification_pipeline2">true</bool> - <bool name="flag_notification_pipeline2_rendering">false</bool> - <bool name="flag_notif_updates">true</bool> - <bool name="flag_monet">true</bool> <!-- People Tile flag --> <bool name="flag_conversations">false</bool> - <!-- The new animations to/from lockscreen and AOD! --> - <bool name="flag_lockscreen_animations">true</bool> - - <!-- The new swipe to unlock animation, which shows the app/launcher behind the keyguard during - the swipe. --> - <bool name="flag_new_unlock_swipe_animation">true</bool> - - <!-- The shared-element transition between lockscreen smartspace and launcher smartspace. --> - <bool name="flag_smartspace_shared_element_transition">false</bool> - - <bool name="flag_pm_lite">true</bool> - <bool name="flag_charging_ripple">false</bool> - <bool name="flag_ongoing_call_status_bar_chip">true</bool> - - <bool name="flag_ongoing_call_in_immersive">true</bool> - - <bool name="flag_ongoing_call_in_immersive_chip_tap">true</bool> - <bool name="flag_smartspace">false</bool> - - <bool name="flag_smartspace_deduping">true</bool> - - <bool name="flag_combined_status_bar_signal_icons">false</bool> - - <bool name="flag_new_user_switcher">true</bool> </resources> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 523b9c8c8f87..986f82f98565 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -2878,7 +2878,7 @@ <!-- Summary for media output group with the active device count [CHAR LIMIT=NONE] --> <string name="media_output_dialog_multiple_devices"><xliff:g id="count" example="2">%1$d</xliff:g> devices selected</string> <!-- Summary for disconnected status [CHAR LIMIT=50] --> - <string name="media_output_dialog_disconnected"><xliff:g id="device_name" example="My device">%1$s</xliff:g> (disconnected)</string> + <string name="media_output_dialog_disconnected">(disconnected)</string> <!-- Summary for connecting error message [CHAR LIMIT=NONE] --> <string name="media_output_dialog_connect_failed">Couldn\'t connect. Try again.</string> <!-- Title for pairing item [CHAR LIMIT=60] --> @@ -3028,6 +3028,8 @@ <string name="see_all_networks">See all</string> <!-- Summary for warning to disconnect ethernet first then switch to other networks. [CHAR LIMIT=60] --> <string name="to_switch_networks_disconnect_ethernet">To switch networks, disconnect ethernet</string> + <!-- Message to describe "Wi-Fi scan always available feature" when Wi-Fi is off and Wi-Fi scanning is on. [CHAR LIMIT=NONE] --> + <string name="wifi_scan_notify_message">To improve device experience, apps and services can still scan for Wi\u2011Fi networks at any time, even when Wi\u2011Fi is off. You can change this in Wi\u2011Fi scanning settings. <annotation id="link">Change</annotation></string> <!-- Title for User Switch dialog. [CHAR LIMIT=20] --> <string name="qs_user_switch_dialog_title">Select user</string> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java index 196e6f335b14..d447b485f33b 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java @@ -118,6 +118,8 @@ public class QuickStepContract { public static final int SYSUI_STATE_DEVICE_DOZING = 1 << 21; // The home feature is disabled (either by SUW/SysUI/device policy) public static final int SYSUI_STATE_BACK_DISABLED = 1 << 22; + // The bubble stack is expanded AND the mange menu for bubbles is expanded on top of it. + public static final int SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED = 1 << 23; @Retention(RetentionPolicy.SOURCE) @IntDef({SYSUI_STATE_SCREEN_PINNING, @@ -142,7 +144,8 @@ public class QuickStepContract { SYSUI_STATE_MAGNIFICATION_OVERLAP, SYSUI_STATE_IME_SWITCHER_SHOWING, SYSUI_STATE_DEVICE_DOZING, - SYSUI_STATE_BACK_DISABLED + SYSUI_STATE_BACK_DISABLED, + SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED }) public @interface SystemUiStateFlags {} @@ -174,6 +177,8 @@ public class QuickStepContract { str.add((flags & SYSUI_STATE_IME_SWITCHER_SHOWING) != 0 ? "ime_switcher_showing" : ""); str.add((flags & SYSUI_STATE_DEVICE_DOZING) != 0 ? "device_dozing" : ""); str.add((flags & SYSUI_STATE_BACK_DISABLED) != 0 ? "back_disabled" : ""); + str.add((flags & SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED) != 0 + ? "bubbles_mange_menu_expanded" : ""); return str.toString(); } diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt index 10e6c2bfea3a..90f5998053b8 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt +++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt @@ -16,6 +16,7 @@ package com.android.systemui.unfold.progress import android.os.Handler +import android.util.Log import android.util.MathUtils.saturate import androidx.dynamicanimation.animation.DynamicAnimation import androidx.dynamicanimation.animation.FloatPropertyCompat @@ -92,7 +93,14 @@ internal class PhysicsBasedUnfoldTransitionProgressProvider( } } FOLD_UPDATE_FINISH_FULL_OPEN -> { - cancelTransition(endValue = 1f, animate = true) + // Do not cancel if we haven't started the transition yet. + // This could happen when we fully unfolded the device before the screen + // became available. In this case we start and immediately cancel the animation + // in FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE event handler, so we don't need to + // cancel it here. + if (isTransitionRunning) { + cancelTransition(endValue = 1f, animate = true) + } } FOLD_UPDATE_FINISH_CLOSED -> { cancelTransition(endValue = 0f, animate = false) @@ -101,6 +109,10 @@ internal class PhysicsBasedUnfoldTransitionProgressProvider( startTransition(startValue = 1f) } } + + if (DEBUG) { + Log.d(TAG, "onFoldUpdate = $update") + } } private fun cancelTransition(endValue: Float, animate: Boolean) { @@ -118,6 +130,10 @@ internal class PhysicsBasedUnfoldTransitionProgressProvider( listeners.forEach { it.onTransitionFinished() } + + if (DEBUG) { + Log.d(TAG, "onTransitionFinished") + } } } @@ -137,6 +153,10 @@ internal class PhysicsBasedUnfoldTransitionProgressProvider( it.onTransitionStarted() } isTransitionRunning = true + + if (DEBUG) { + Log.d(TAG, "onTransitionStarted") + } } private fun startTransition(startValue: Float) { @@ -189,6 +209,9 @@ internal class PhysicsBasedUnfoldTransitionProgressProvider( } } +private const val TAG = "PhysicsBasedUnfoldTransitionProgressProvider" +private const val DEBUG = true + private const val TRANSITION_TIMEOUT_MILLIS = 2000L private const val SPRING_STIFFNESS = 200.0f private const val MINIMAL_VISIBLE_CHANGE = 0.001f diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt index c37ab06abb60..35e2b30d0a39 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt +++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt @@ -25,7 +25,7 @@ import com.android.systemui.unfold.updates.hinge.FULLY_OPEN_DEGREES import com.android.systemui.unfold.updates.hinge.HingeAngleProvider import java.util.concurrent.Executor -internal class DeviceFoldStateProvider( +class DeviceFoldStateProvider( context: Context, private val hingeAngleProvider: HingeAngleProvider, private val screenStatusProvider: ScreenStatusProvider, @@ -43,6 +43,7 @@ internal class DeviceFoldStateProvider( private val foldStateListener = FoldStateListener(context) private var isFolded = false + private var isUnfoldHandled = true override fun start() { deviceStateManager.registerCallback( @@ -104,6 +105,7 @@ internal class DeviceFoldStateProvider( lastFoldUpdate = FOLD_UPDATE_FINISH_CLOSED outputListeners.forEach { it.onFoldUpdate(FOLD_UPDATE_FINISH_CLOSED) } hingeAngleProvider.stop() + isUnfoldHandled = false } else { lastFoldUpdate = FOLD_UPDATE_START_OPENING outputListeners.forEach { it.onFoldUpdate(FOLD_UPDATE_START_OPENING) } @@ -115,8 +117,15 @@ internal class DeviceFoldStateProvider( ScreenStatusProvider.ScreenListener { override fun onScreenTurnedOn() { - if (!isFolded) { + // Trigger this event only if we are unfolded and this is the first screen + // turned on event since unfold started. This prevents running the animation when + // turning on the internal display using the power button. + // Initially isUnfoldHandled is true so it will be reset to false *only* when we + // receive 'folded' event. If SystemUI started when device is already folded it will + // still receive 'folded' event on startup. + if (!isFolded && !isUnfoldHandled) { outputListeners.forEach { it.onFoldUpdate(FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE) } + isUnfoldHandled = true } } } diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/FoldStateProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/FoldStateProvider.kt index 11984b93638e..643ece353522 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/FoldStateProvider.kt +++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/FoldStateProvider.kt @@ -24,7 +24,7 @@ import com.android.systemui.statusbar.policy.CallbackController * Allows to subscribe to main events related to fold/unfold process such as hinge angle update, * start folding/unfolding, screen availability */ -internal interface FoldStateProvider : CallbackController<FoldUpdatesListener> { +interface FoldStateProvider : CallbackController<FoldUpdatesListener> { fun start() fun stop() diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/HingeAngleProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/HingeAngleProvider.kt index 2520d356b721..6f524560de99 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/HingeAngleProvider.kt +++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/HingeAngleProvider.kt @@ -9,7 +9,7 @@ import com.android.systemui.statusbar.policy.CallbackController * For foldable devices usually 0 corresponds to fully closed (folded) state and * 180 degrees corresponds to fully open (flat) state */ -internal interface HingeAngleProvider : CallbackController<Consumer<Float>> { +interface HingeAngleProvider : CallbackController<Consumer<Float>> { fun start() fun stop() } diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/util/NaturalRotationUnfoldProgressProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/util/NaturalRotationUnfoldProgressProvider.kt new file mode 100644 index 000000000000..e072d41e4eee --- /dev/null +++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/util/NaturalRotationUnfoldProgressProvider.kt @@ -0,0 +1,73 @@ +package com.android.systemui.unfold.util + +import android.content.Context +import android.os.RemoteException +import android.util.Log +import android.view.IRotationWatcher +import android.view.IWindowManager +import android.view.Surface +import com.android.systemui.unfold.UnfoldTransitionProgressProvider +import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener + +/** + * [UnfoldTransitionProgressProvider] that emits transition progress only when the display has + * default rotation or 180 degrees opposite rotation (ROTATION_0 or ROTATION_180). + * It could be helpful to run the animation only when the display's rotation is perpendicular + * to the fold. + */ +class NaturalRotationUnfoldProgressProvider( + private val context: Context, + private val windowManagerInterface: IWindowManager, + unfoldTransitionProgressProvider: UnfoldTransitionProgressProvider +) : UnfoldTransitionProgressProvider { + + private val scopedUnfoldTransitionProgressProvider = + ScopedUnfoldTransitionProgressProvider(unfoldTransitionProgressProvider) + private val rotationWatcher = RotationWatcher() + + private var isNaturalRotation: Boolean = false + + fun init() { + try { + windowManagerInterface.watchRotation(rotationWatcher, context.display.displayId) + } catch (e: RemoteException) { + throw e.rethrowFromSystemServer() + } + + onRotationChanged(context.display.rotation) + } + + private fun onRotationChanged(rotation: Int) { + val isNewRotationNatural = rotation == Surface.ROTATION_0 || + rotation == Surface.ROTATION_180 + + if (isNaturalRotation != isNewRotationNatural) { + isNaturalRotation = isNewRotationNatural + scopedUnfoldTransitionProgressProvider.setReadyToHandleTransition(isNewRotationNatural) + } + } + + override fun destroy() { + try { + windowManagerInterface.removeRotationWatcher(rotationWatcher) + } catch (e: RemoteException) { + e.rethrowFromSystemServer() + } + + scopedUnfoldTransitionProgressProvider.destroy() + } + + override fun addCallback(listener: TransitionProgressListener) { + scopedUnfoldTransitionProgressProvider.addCallback(listener) + } + + override fun removeCallback(listener: TransitionProgressListener) { + scopedUnfoldTransitionProgressProvider.removeCallback(listener) + } + + private inner class RotationWatcher : IRotationWatcher.Stub() { + override fun onRotationChanged(rotation: Int) { + this@NaturalRotationUnfoldProgressProvider.onRotationChanged(rotation) + } + } +} diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/util/ScopedUnfoldTransitionProgressProvider.java b/packages/SystemUI/shared/src/com/android/systemui/unfold/util/ScopedUnfoldTransitionProgressProvider.java new file mode 100644 index 000000000000..543232da303e --- /dev/null +++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/util/ScopedUnfoldTransitionProgressProvider.java @@ -0,0 +1,142 @@ +/* + * 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.unfold.util; + +import android.annotation.NonNull; +import android.annotation.Nullable; + +import com.android.systemui.unfold.UnfoldTransitionProgressProvider; +import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener; + +import java.util.ArrayList; +import java.util.List; + +/** + * Manages progress listeners that can have smaller lifespan than the unfold animation. + * Allows to limit getting transition updates to only when + * {@link ScopedUnfoldTransitionProgressProvider#setReadyToHandleTransition} is called + * with readyToHandleTransition = true + * + * If the transition has already started by the moment when the clients are ready to play + * the transition then it will report transition started callback and current animation progress. + */ +public final class ScopedUnfoldTransitionProgressProvider implements + UnfoldTransitionProgressProvider, TransitionProgressListener { + + private static final float PROGRESS_UNSET = -1f; + + @Nullable + private UnfoldTransitionProgressProvider mSource; + + private final List<TransitionProgressListener> mListeners = new ArrayList<>(); + + private boolean mIsReadyToHandleTransition; + private boolean mIsTransitionRunning; + private float mLastTransitionProgress = PROGRESS_UNSET; + + public ScopedUnfoldTransitionProgressProvider() { + this(null); + } + + public ScopedUnfoldTransitionProgressProvider( + @Nullable UnfoldTransitionProgressProvider source) { + setSourceProvider(source); + } + + /** + * Sets the source for the unfold transition progress updates, + * it replaces current provider if it is already set + * @param provider transition provider that emits transition progress updates + */ + public void setSourceProvider(@Nullable UnfoldTransitionProgressProvider provider) { + if (mSource != null) { + mSource.removeCallback(this); + } + + if (provider != null) { + mSource = provider; + mSource.addCallback(this); + } else { + mSource = null; + } + } + + /** + * Allows to notify this provide whether the listeners can play the transition or not. + * Call this method with readyToHandleTransition = true when all listeners + * are ready to consume the transition progress events. + * Call it with readyToHandleTransition = false when listeners can't process the events. + */ + public void setReadyToHandleTransition(boolean isReadyToHandleTransition) { + if (mIsTransitionRunning) { + if (isReadyToHandleTransition) { + mListeners.forEach(TransitionProgressListener::onTransitionStarted); + + if (mLastTransitionProgress != PROGRESS_UNSET) { + mListeners.forEach(listener -> + listener.onTransitionProgress(mLastTransitionProgress)); + } + } else { + mIsTransitionRunning = false; + mListeners.forEach(TransitionProgressListener::onTransitionFinished); + } + } + + mIsReadyToHandleTransition = isReadyToHandleTransition; + } + + @Override + public void addCallback(@NonNull TransitionProgressListener listener) { + mListeners.add(listener); + } + + @Override + public void removeCallback(@NonNull TransitionProgressListener listener) { + mListeners.remove(listener); + } + + @Override + public void destroy() { + mSource.removeCallback(this); + } + + @Override + public void onTransitionStarted() { + this.mIsTransitionRunning = true; + if (mIsReadyToHandleTransition) { + mListeners.forEach(TransitionProgressListener::onTransitionStarted); + } + } + + @Override + public void onTransitionProgress(float progress) { + if (mIsReadyToHandleTransition) { + mListeners.forEach(listener -> listener.onTransitionProgress(progress)); + } + + mLastTransitionProgress = progress; + } + + @Override + public void onTransitionFinished() { + if (mIsReadyToHandleTransition) { + mListeners.forEach(TransitionProgressListener::onTransitionFinished); + } + + mIsTransitionRunning = false; + mLastTransitionProgress = PROGRESS_UNSET; + } +} diff --git a/packages/SystemUI/src-debug/com/android/systemui/flags/FeatureFlagManager.java b/packages/SystemUI/src-debug/com/android/systemui/flags/FeatureFlagManager.java index b3a6699ca646..5b6845fcdb4f 100644 --- a/packages/SystemUI/src-debug/com/android/systemui/flags/FeatureFlagManager.java +++ b/packages/SystemUI/src-debug/com/android/systemui/flags/FeatureFlagManager.java @@ -16,37 +16,174 @@ package com.android.systemui.flags; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Bundle; +import android.util.Log; + import com.android.systemui.dagger.SysUISingleton; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.HashMap; +import java.util.Map; + import javax.inject.Inject; /** * Concrete implementation of the a Flag manager that returns default values for debug builds + * + * Flags can be set (or unset) via the following adb command: + * + * adb shell am broadcast -a com.android.systemui.action.SET_FLAG --ei id <id> [--ez value <0|1>] + * + * To restore a flag back to its default, leave the `--ez value <0|1>` off of the command. */ @SysUISingleton public class FeatureFlagManager implements FlagReader, FlagWriter { + private static final String TAG = "SysUIFlags"; + + private static final String SYSPROP_PREFIX = "persist.systemui.flag_"; + private static final String FIELD_TYPE = "type"; + private static final String FIELD_ID = "id"; + private static final String FIELD_VALUE = "value"; + private static final String TYPE_BOOLEAN = "boolean"; + private static final String ACTION_SET_FLAG = "com.android.systemui.action.SET_FLAG"; + private static final String FLAGS_PERMISSION = "com.android.systemui.permission.FLAGS"; + private final SystemPropertiesHelper mSystemPropertiesHelper; + + private final Map<Integer, Boolean> mBooleanFlagCache = new HashMap<>(); + @Inject - public FeatureFlagManager() {} + public FeatureFlagManager(SystemPropertiesHelper systemPropertiesHelper, Context context) { + mSystemPropertiesHelper = systemPropertiesHelper; - public boolean isEnabled(int key, boolean defaultValue) { - return isEnabled(Integer.toString(key), defaultValue); + IntentFilter filter = new IntentFilter(ACTION_SET_FLAG); + context.registerReceiver(mReceiver, filter, FLAGS_PERMISSION, null); } - public boolean isEnabled(String key, boolean defaultValue) { - // TODO - return false; + /** Return a {@link BooleanFlag}'s value. */ + public boolean isEnabled(int id, boolean defaultValue) { + if (!mBooleanFlagCache.containsKey(id)) { + Boolean result = isEnabledInternal(id); + mBooleanFlagCache.put(id, result == null ? defaultValue : result); + } + + return mBooleanFlagCache.get(id); } - public void setEnabled(int key, boolean value) { - setEnabled(Integer.toString(key), value); + /** Returns the stored value or null if not set. */ + private Boolean isEnabledInternal(int id) { + String data = mSystemPropertiesHelper.get(keyToSysPropKey(id)); + if (data.isEmpty()) { + return null; + } + JSONObject json; + try { + json = new JSONObject(data); + if (!assertType(json, TYPE_BOOLEAN)) { + return null; + } + + return json.getBoolean(FIELD_VALUE); + } catch (JSONException e) { + eraseInternal(id); // Don't restart SystemUI in this case. + } + return null; + } + + /** Set whether a given {@link BooleanFlag} is enabled or not. */ + public void setEnabled(int id, boolean value) { + Boolean currentValue = isEnabledInternal(id); + if (currentValue != null && currentValue == value) { + return; + } + + JSONObject json = new JSONObject(); + try { + json.put(FIELD_TYPE, TYPE_BOOLEAN); + json.put(FIELD_VALUE, value); + mSystemPropertiesHelper.set(keyToSysPropKey(id), json.toString()); + Log.i(TAG, "Set id " + id + " to " + value); + restartSystemUI(); + } catch (JSONException e) { + // no-op + } } - public void setEnabled(String key, boolean value) { - // TODO + /** Erase a flag's overridden value if there is one. */ + public void eraseFlag(int id) { + eraseInternal(id); + restartSystemUI(); + } + + /** Works just like {@link #eraseFlag(int)} except that it doesn't restart SystemUI. */ + private void eraseInternal(int id) { + // We can't actually "erase" things from sysprops, but we can set them to empty! + mSystemPropertiesHelper.set(keyToSysPropKey(id), ""); + Log.i(TAG, "Erase id " + id); } public void addListener(Listener run) {} public void removeListener(Listener run) {} + private void restartSystemUI() { + Log.i(TAG, "Restarting SystemUI"); + // SysUI starts back when up exited. Is there a better way to do this? + System.exit(0); + } + + private static String keyToSysPropKey(int key) { + return SYSPROP_PREFIX + key; + } + + private static boolean assertType(JSONObject json, String type) { + try { + return json.getString(FIELD_TYPE).equals(TYPE_BOOLEAN); + } catch (JSONException e) { + return false; + } + } + + private final BroadcastReceiver mReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (action == null) { + return; + } + + if (ACTION_SET_FLAG.equals(action)) { + handleSetFlag(intent.getExtras()); + } + } + + private void handleSetFlag(Bundle extras) { + int id = extras.getInt(FIELD_ID); + if (id <= 0) { + Log.w(TAG, "ID not set or less than or equal to 0: " + id); + return; + } + + Map<Integer, Flag<?>> flagMap = Flags.collectFlags(); + if (!flagMap.containsKey(id)) { + Log.w(TAG, "Tried to set unknown id: " + id); + return; + } + Flag<?> flag = flagMap.get(id); + + if (!extras.containsKey(FIELD_VALUE)) { + eraseFlag(id); + return; + } + + if (flag instanceof BooleanFlag) { + setEnabled(id, extras.getBoolean(FIELD_VALUE)); + } + } + }; } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java index 6fd0c821bad1..3d4e896178f6 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java @@ -89,6 +89,7 @@ public class KeyguardClockSwitch extends RelativeLayout { private int mClockSwitchYAmount; @VisibleForTesting boolean mChildrenAreLaidOut = false; + private OnPreDrawListener mPreDrawListener; public KeyguardClockSwitch(Context context, AttributeSet attrs) { super(context, attrs); @@ -284,15 +285,14 @@ public class KeyguardClockSwitch extends RelativeLayout { if (mChildrenAreLaidOut) { animateClockChange(clockSize == LARGE); mDisplayedClockSize = clockSize; - } else { - getViewTreeObserver().addOnPreDrawListener(new OnPreDrawListener() { - @Override - public boolean onPreDraw() { - switchToClock(clockSize); - getViewTreeObserver().removeOnPreDrawListener(this); - return true; - } - }); + } else if (mPreDrawListener == null) { + mPreDrawListener = () -> { + switchToClock(clockSize); + getViewTreeObserver().removeOnPreDrawListener(mPreDrawListener); + mPreDrawListener = null; + return true; + }; + getViewTreeObserver().addOnPreDrawListener(mPreDrawListener); } return true; } @@ -303,6 +303,13 @@ public class KeyguardClockSwitch extends RelativeLayout { mChildrenAreLaidOut = true; } + void onViewDetached() { + if (mPreDrawListener != null) { + getViewTreeObserver().removeOnPreDrawListener(mPreDrawListener); + mPreDrawListener = null; + } + } + public Paint getPaint() { return mClockView.getPaint(); } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java index 01976b41a4b2..1931c0a1645c 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java @@ -238,6 +238,7 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS } mColorExtractor.removeOnColorsChangedListener(mColorsListener); mView.setClockPlugin(null, mStatusBarStateController.getState()); + mView.onViewDetached(); } /** diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java index 11eeac2272ff..099dd5d82a10 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java @@ -27,8 +27,10 @@ import android.text.TextUtils; import android.util.AttributeSet; import android.util.TypedValue; import android.view.View; +import android.view.ViewGroup; import android.widget.TextView; +import com.android.internal.policy.SystemBarUtils; import com.android.settingslib.Utils; import com.android.systemui.R; @@ -55,6 +57,8 @@ public class KeyguardMessageArea extends TextView implements SecurityMessageDisp private ColorStateList mNextMessageColorState = ColorStateList.valueOf(DEFAULT_COLOR); private boolean mBouncerVisible; private boolean mAltBouncerShowing; + private ViewGroup mContainer; + private int mTopMargin; public KeyguardMessageArea(Context context, AttributeSet attrs) { super(context, attrs); @@ -65,6 +69,24 @@ public class KeyguardMessageArea extends TextView implements SecurityMessageDisp } @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + mContainer = getRootView().findViewById(R.id.keyguard_message_area_container); + } + + void onConfigChanged() { + final int newTopMargin = SystemBarUtils.getStatusBarHeight(getContext()); + if (mTopMargin == newTopMargin) { + return; + } + mTopMargin = newTopMargin; + ViewGroup.MarginLayoutParams lp = + (ViewGroup.MarginLayoutParams) mContainer.getLayoutParams(); + lp.topMargin = mTopMargin; + mContainer.setLayoutParams(lp); + } + + @Override public void setNextMessageColor(ColorStateList colorState) { mNextMessageColorState = colorState; } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java index 51ded3fcafdf..05318bb0df78 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java @@ -17,6 +17,7 @@ package com.android.keyguard; import android.content.res.ColorStateList; +import android.content.res.Configuration; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener; @@ -48,6 +49,11 @@ public class KeyguardMessageAreaController extends ViewController<KeyguardMessag private ConfigurationListener mConfigurationListener = new ConfigurationListener() { @Override + public void onConfigChanged(Configuration newConfig) { + mView.onConfigChanged(); + } + + @Override public void onThemeChanged() { mView.onThemeChanged(); } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index 5707fa7b18d7..a41a49799c2d 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -89,6 +89,7 @@ import androidx.lifecycle.Observer; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.jank.InteractionJankMonitor; +import com.android.internal.util.LatencyTracker; import com.android.internal.widget.LockPatternUtils; import com.android.settingslib.WirelessUtils; import com.android.settingslib.fuelgauge.BatteryStatus; @@ -313,6 +314,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab private final DevicePolicyManager mDevicePolicyManager; private final BroadcastDispatcher mBroadcastDispatcher; private final InteractionJankMonitor mInteractionJankMonitor; + private final LatencyTracker mLatencyTracker; private boolean mLogoutEnabled; // cached value to avoid IPCs private boolean mIsUdfpsEnrolled; @@ -1739,8 +1741,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab AuthController authController, TelephonyListenerManager telephonyListenerManager, FeatureFlags featureFlags, - InteractionJankMonitor interactionJankMonitor - ) { + InteractionJankMonitor interactionJankMonitor, + LatencyTracker latencyTracker) { mContext = context; mSubscriptionManager = SubscriptionManager.from(context); mTelephonyListenerManager = telephonyListenerManager; @@ -1749,6 +1751,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab mBackgroundExecutor = backgroundExecutor; mBroadcastDispatcher = broadcastDispatcher; mInteractionJankMonitor = interactionJankMonitor; + mLatencyTracker = latencyTracker; mRingerModeTracker = ringerModeTracker; mStatusBarStateController = statusBarStateController; mStatusBarStateController.addCallback(mStatusBarStateControllerListener); @@ -2579,6 +2582,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } } mInteractionJankMonitor.end(InteractionJankMonitor.CUJ_USER_SWITCH); + mLatencyTracker.onActionEnd(LatencyTracker.ACTION_USER_SWITCH); } /** diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconView.java b/packages/SystemUI/src/com/android/keyguard/LockIconView.java index ef4353b93179..68132f4c598b 100644 --- a/packages/SystemUI/src/com/android/keyguard/LockIconView.java +++ b/packages/SystemUI/src/com/android/keyguard/LockIconView.java @@ -26,6 +26,7 @@ import android.view.View; import android.widget.FrameLayout; import android.widget.ImageView; +import androidx.annotation.IntDef; import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; @@ -40,6 +41,17 @@ import java.io.PrintWriter; * A view positioned under the notification shade. */ public class LockIconView extends FrameLayout implements Dumpable { + @IntDef({ICON_NONE, ICON_LOCK, ICON_FINGERPRINT, ICON_UNLOCK}) + public @interface IconType {} + + public static final int ICON_NONE = -1; + public static final int ICON_LOCK = 0; + public static final int ICON_FINGERPRINT = 1; + public static final int ICON_UNLOCK = 2; + + private @IconType int mIconType; + private boolean mAod; + @NonNull private final RectF mSensorRect; @NonNull private PointF mLockIconCenter = new PointF(0f, 0f); private int mRadius; @@ -49,6 +61,7 @@ public class LockIconView extends FrameLayout implements Dumpable { private int mLockIconColor; private boolean mUseBackground = false; + private float mDozeAmount = 0f; public LockIconView(Context context, AttributeSet attrs) { super(context, attrs); @@ -62,11 +75,17 @@ public class LockIconView extends FrameLayout implements Dumpable { mBgView = findViewById(R.id.lock_icon_bg); } + void setDozeAmount(float dozeAmount) { + mDozeAmount = dozeAmount; + updateColorAndBackgroundVisibility(); + } + void updateColorAndBackgroundVisibility() { if (mUseBackground && mLockIcon.getDrawable() != null) { mLockIconColor = Utils.getColorAttrDefaultColor(getContext(), android.R.attr.textColorPrimary); mBgView.setBackground(getContext().getDrawable(R.drawable.fingerprint_bg)); + mBgView.setAlpha(1f - mDozeAmount); mBgView.setVisibility(View.VISIBLE); } else { mLockIconColor = Utils.getColorAttrDefaultColor(getContext(), @@ -129,10 +148,75 @@ public class LockIconView extends FrameLayout implements Dumpable { return mLockIconCenter.y - mRadius; } + /** + * Updates the icon its default state where no visual is shown. + */ + public void clearIcon() { + updateIcon(ICON_NONE, false); + } + + /** + * Transition the current icon to a new state + * @param icon type (ie: lock icon, unlock icon, fingerprint icon) + * @param aod whether to use the aod icon variant (some icons don't have aod variants and will + * therefore show no icon) + */ + public void updateIcon(@IconType int icon, boolean aod) { + mIconType = icon; + mAod = aod; + + mLockIcon.setImageState(getLockIconState(mIconType, mAod), true); + } + + private static int[] getLockIconState(@IconType int icon, boolean aod) { + if (icon == ICON_NONE) { + return new int[0]; + } + + int[] lockIconState = new int[2]; + switch (icon) { + case ICON_LOCK: + lockIconState[0] = android.R.attr.state_first; + break; + case ICON_FINGERPRINT: + lockIconState[0] = android.R.attr.state_middle; + break; + case ICON_UNLOCK: + lockIconState[0] = android.R.attr.state_last; + break; + } + + if (aod) { + lockIconState[1] = android.R.attr.state_single; + } else { + lockIconState[1] = -android.R.attr.state_single; + } + + return lockIconState; + } + + private String typeToString(@IconType int type) { + switch (type) { + case ICON_NONE: + return "none"; + case ICON_LOCK: + return "lock"; + case ICON_FINGERPRINT: + return "fingerprint"; + case ICON_UNLOCK: + return "unlock"; + } + + return "invalid"; + } + @Override public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) { pw.println("Center in px (x, y)= (" + mLockIconCenter.x + ", " + mLockIconCenter.y + ")"); pw.println("Radius in pixels: " + mRadius); pw.println("topLeft= (" + getX() + ", " + getY() + ")"); + pw.println("topLeft= (" + getX() + ", " + getY() + ")"); + pw.println("mIconType=" + typeToString(mIconType)); + pw.println("mAod=" + mAod); } } diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java index 321c1a309cb5..3c80a186a4a7 100644 --- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java @@ -18,6 +18,9 @@ package com.android.keyguard; import static android.hardware.biometrics.BiometricSourceType.FINGERPRINT; +import static com.android.keyguard.LockIconView.ICON_FINGERPRINT; +import static com.android.keyguard.LockIconView.ICON_LOCK; +import static com.android.keyguard.LockIconView.ICON_UNLOCK; import static com.android.systemui.classifier.Classifier.LOCK_ICON; import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset; import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInProgressOffset; @@ -26,8 +29,7 @@ import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.PointF; import android.graphics.Rect; -import android.graphics.drawable.AnimatedVectorDrawable; -import android.graphics.drawable.Drawable; +import android.graphics.drawable.AnimatedStateListDrawable; import android.hardware.biometrics.BiometricSourceType; import android.hardware.biometrics.SensorLocationInternal; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; @@ -103,11 +105,8 @@ public class LockIconViewController extends ViewController<LockIconView> impleme private boolean mUdfpsEnrolled; @Nullable private LottieAnimationView mAodFp; + @NonNull private final AnimatedStateListDrawable mIcon; - @NonNull private final AnimatedVectorDrawable mFpToUnlockIcon; - @NonNull private final AnimatedVectorDrawable mLockToUnlockIcon; - @NonNull private final Drawable mLockIcon; - @NonNull private final Drawable mUnlockIcon; @NonNull private CharSequence mUnlockedLabel; @NonNull private CharSequence mLockedLabel; @Nullable private final Vibrator mVibrator; @@ -133,13 +132,13 @@ public class LockIconViewController extends ViewController<LockIconView> impleme private boolean mShowLockIcon; // for udfps when strong auth is required or unlocked on AOD + private boolean mShowAodLockIcon; private boolean mShowAODFpIcon; private final int mMaxBurnInOffsetX; private final int mMaxBurnInOffsetY; private float mInterpolatedDarkAmount; private boolean mDownDetected; - private boolean mDetectedLongPress; private final Rect mSensorTouchLocation = new Rect(); @Inject @@ -177,12 +176,9 @@ public class LockIconViewController extends ViewController<LockIconView> impleme mMaxBurnInOffsetX = resources.getDimensionPixelSize(R.dimen.udfps_burn_in_offset_x); mMaxBurnInOffsetY = resources.getDimensionPixelSize(R.dimen.udfps_burn_in_offset_y); - mUnlockIcon = resources.getDrawable(R.drawable.ic_unlock, mView.getContext().getTheme()); - mLockIcon = resources.getDrawable(R.anim.lock_to_unlock, mView.getContext().getTheme()); - mFpToUnlockIcon = (AnimatedVectorDrawable) resources.getDrawable( - R.anim.fp_to_unlock, mView.getContext().getTheme()); - mLockToUnlockIcon = (AnimatedVectorDrawable) resources.getDrawable(R.anim.lock_to_unlock, - mView.getContext().getTheme()); + mIcon = (AnimatedStateListDrawable) + resources.getDrawable(R.drawable.super_lock_icon, mView.getContext().getTheme()); + mView.setImageDrawable(mIcon); mUnlockedLabel = resources.getString(R.string.accessibility_unlock_button); mLockedLabel = resources.getString(R.string.accessibility_lock_icon); dumpManager.registerDumpable("LockIconViewController", this); @@ -256,42 +252,47 @@ public class LockIconViewController extends ViewController<LockIconView> impleme return; } + boolean wasShowingUnlock = mShowUnlockIcon; boolean wasShowingFpIcon = mUdfpsEnrolled && !mShowUnlockIcon && !mShowLockIcon; - boolean wasShowingLockIcon = mShowLockIcon; - boolean wasShowingUnlockIcon = mShowUnlockIcon; mShowLockIcon = !mCanDismissLockScreen && !mUserUnlockedWithBiometric && isLockScreen() && (!mUdfpsEnrolled || !mRunningFPS); mShowUnlockIcon = (mCanDismissLockScreen || mUserUnlockedWithBiometric) && isLockScreen(); - mShowAODFpIcon = mIsDozing && mUdfpsEnrolled && !mRunningFPS; + mShowAODFpIcon = mIsDozing && mUdfpsEnrolled && !mRunningFPS && mCanDismissLockScreen; + mShowAodLockIcon = mIsDozing && mUdfpsEnrolled && !mRunningFPS && !mCanDismissLockScreen; final CharSequence prevContentDescription = mView.getContentDescription(); if (mShowLockIcon) { - mView.setImageDrawable(mLockIcon); - mView.setVisibility(View.VISIBLE); + mView.updateIcon(ICON_LOCK, false); mView.setContentDescription(mLockedLabel); + mView.setVisibility(View.VISIBLE); } else if (mShowUnlockIcon) { - if (!wasShowingUnlockIcon) { - if (wasShowingFpIcon) { - mView.setImageDrawable(mFpToUnlockIcon); - mFpToUnlockIcon.forceAnimationOnUI(); - mFpToUnlockIcon.start(); - } else if (wasShowingLockIcon) { - mView.setImageDrawable(mLockToUnlockIcon); - mLockToUnlockIcon.forceAnimationOnUI(); - mLockToUnlockIcon.start(); - } else { - mView.setImageDrawable(mUnlockIcon); - } + if (wasShowingFpIcon) { + // fp icon was shown by UdfpsView, and now we still want to animate the transition + // in this drawable + mView.updateIcon(ICON_FINGERPRINT, false); } - mView.setVisibility(View.VISIBLE); + mView.updateIcon(ICON_UNLOCK, false); mView.setContentDescription(mUnlockedLabel); + mView.setVisibility(View.VISIBLE); } else if (mShowAODFpIcon) { - mView.setImageDrawable(null); + // AOD fp icon is special cased as a lottie view (it updates for each burn-in offset), + // this state shows a transparent view mView.setContentDescription(null); mAodFp.setVisibility(View.VISIBLE); mAodFp.setContentDescription(mCanDismissLockScreen ? mUnlockedLabel : mLockedLabel); + + mView.updateIcon(ICON_FINGERPRINT, true); // this shows no icon + mView.setVisibility(View.VISIBLE); + } else if (mShowAodLockIcon) { + if (wasShowingUnlock) { + // transition to the unlock icon first + mView.updateIcon(ICON_LOCK, false); + } + mView.updateIcon(ICON_LOCK, true); + mView.setContentDescription(mLockedLabel); mView.setVisibility(View.VISIBLE); } else { + mView.clearIcon(); mView.setVisibility(View.INVISIBLE); mView.setContentDescription(null); } @@ -381,6 +382,11 @@ public class LockIconViewController extends ViewController<LockIconView> impleme pw.println("mUdfpsSupported: " + mUdfpsSupported); pw.println("mUdfpsEnrolled: " + mUdfpsEnrolled); pw.println("mIsKeyguardShowing: " + mIsKeyguardShowing); + pw.println(" mIcon: "); + for (int state : mIcon.getState()) { + pw.print(" " + state); + } + pw.println(); pw.println(" mShowUnlockIcon: " + mShowUnlockIcon); pw.println(" mShowLockIcon: " + mShowLockIcon); pw.println(" mShowAODFpIcon: " + mShowAODFpIcon); @@ -418,6 +424,11 @@ public class LockIconViewController extends ViewController<LockIconView> impleme mAodFp.setProgress(progress); mAodFp.setAlpha(255 * mInterpolatedDarkAmount); } + + if (mShowAodLockIcon) { + mView.setTranslationX(offsetX); + mView.setTranslationY(offsetY); + } } private void updateIsUdfpsEnrolled() { @@ -442,6 +453,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme @Override public void onDozeAmountChanged(float linear, float eased) { mInterpolatedDarkAmount = eased; + mView.setDozeAmount(eased); updateBurnInOffsets(); } @@ -562,7 +574,6 @@ public class LockIconViewController extends ViewController<LockIconView> impleme private final GestureDetector mGestureDetector = new GestureDetector(new SimpleOnGestureListener() { public boolean onDown(MotionEvent e) { - mDetectedLongPress = false; if (!isClickable()) { mDownDetected = false; return false; @@ -587,7 +598,6 @@ public class LockIconViewController extends ViewController<LockIconView> impleme if (!wasClickableOnDownEvent()) { return; } - mDetectedLongPress = true; if (onAffordanceClick() && mVibrator != null) { // only vibrate if the click went through and wasn't intercepted by falsing @@ -685,8 +695,11 @@ public class LockIconViewController extends ViewController<LockIconView> impleme private final AuthController.Callback mAuthControllerCallback = new AuthController.Callback() { @Override public void onAllAuthenticatorsRegistered() { - updateIsUdfpsEnrolled(); - updateConfiguration(); + // must be called from the main thread since it may update the views + mExecutor.execute(() -> { + updateIsUdfpsEnrolled(); + updateConfiguration(); + }); } }; } diff --git a/packages/SystemUI/src/com/android/keyguard/clock/AnalogClockController.java b/packages/SystemUI/src/com/android/keyguard/clock/AnalogClockController.java index 99e122ef74e9..7517deed7cbb 100644 --- a/packages/SystemUI/src/com/android/keyguard/clock/AnalogClockController.java +++ b/packages/SystemUI/src/com/android/keyguard/clock/AnalogClockController.java @@ -91,7 +91,7 @@ public class AnalogClockController implements ClockPlugin { mResources = res; mLayoutInflater = inflater; mColorExtractor = colorExtractor; - mClockPosition = new SmallClockPosition(res); + mClockPosition = new SmallClockPosition(inflater.getContext()); } private void createViews() { diff --git a/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java b/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java index fac923c01af5..1add1a3abf5a 100644 --- a/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java +++ b/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java @@ -91,7 +91,7 @@ public class BubbleClockController implements ClockPlugin { mResources = res; mLayoutInflater = inflater; mColorExtractor = colorExtractor; - mClockPosition = new SmallClockPosition(res); + mClockPosition = new SmallClockPosition(inflater.getContext()); } private void createViews() { diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java index 3775628df0e0..013cdac94ab8 100644 --- a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java +++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java @@ -41,7 +41,6 @@ import com.android.systemui.plugins.ClockPlugin; import com.android.systemui.plugins.PluginListener; import com.android.systemui.settings.CurrentUserObservable; import com.android.systemui.shared.plugins.PluginManager; -import com.android.systemui.util.InjectionInflationController; import java.util.ArrayList; import java.util.Collection; @@ -125,16 +124,16 @@ public final class ClockManager { private final int mHeight; @Inject - public ClockManager(Context context, InjectionInflationController injectionInflater, + public ClockManager(Context context, LayoutInflater layoutInflater, PluginManager pluginManager, SysuiColorExtractor colorExtractor, @Nullable DockManager dockManager, BroadcastDispatcher broadcastDispatcher) { - this(context, injectionInflater, pluginManager, colorExtractor, + this(context, layoutInflater, pluginManager, colorExtractor, context.getContentResolver(), new CurrentUserObservable(broadcastDispatcher), new SettingsWrapper(context.getContentResolver()), dockManager); } @VisibleForTesting - ClockManager(Context context, InjectionInflationController injectionInflater, + ClockManager(Context context, LayoutInflater layoutInflater, PluginManager pluginManager, SysuiColorExtractor colorExtractor, ContentResolver contentResolver, CurrentUserObservable currentUserObservable, SettingsWrapper settingsWrapper, DockManager dockManager) { @@ -147,7 +146,6 @@ public final class ClockManager { mPreviewClocks = new AvailableClocks(); Resources res = context.getResources(); - LayoutInflater layoutInflater = injectionInflater.injectable(LayoutInflater.from(context)); addBuiltinClock(() -> new DefaultClockController(res, layoutInflater, colorExtractor)); diff --git a/packages/SystemUI/src/com/android/keyguard/clock/SmallClockPosition.java b/packages/SystemUI/src/com/android/keyguard/clock/SmallClockPosition.java index b3040744ce7a..4e51b98b0a4c 100644 --- a/packages/SystemUI/src/com/android/keyguard/clock/SmallClockPosition.java +++ b/packages/SystemUI/src/com/android/keyguard/clock/SmallClockPosition.java @@ -16,10 +16,11 @@ package com.android.keyguard.clock; -import android.content.res.Resources; +import android.content.Context; import android.util.MathUtils; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.policy.SystemBarUtils; import com.android.systemui.R; /** @@ -40,11 +41,11 @@ class SmallClockPosition { */ private float mDarkAmount; - SmallClockPosition(Resources res) { - this(res.getDimensionPixelSize(R.dimen.status_bar_height), - res.getDimensionPixelSize(R.dimen.keyguard_lock_padding), - res.getDimensionPixelSize(R.dimen.keyguard_lock_height), - res.getDimensionPixelSize(R.dimen.burn_in_prevention_offset_y) + SmallClockPosition(Context context) { + this(SystemBarUtils.getStatusBarHeight(context), + context.getResources().getDimensionPixelSize(R.dimen.keyguard_lock_padding), + context.getResources().getDimensionPixelSize(R.dimen.keyguard_lock_height), + context.getResources().getDimensionPixelSize(R.dimen.burn_in_prevention_offset_y) ); } diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java index c73d19b5a20d..4e4034a28cb0 100644 --- a/packages/SystemUI/src/com/android/systemui/Dependency.java +++ b/packages/SystemUI/src/com/android/systemui/Dependency.java @@ -89,8 +89,12 @@ import com.android.systemui.statusbar.notification.NotificationEntryManager.Keyg import com.android.systemui.statusbar.notification.NotificationFilter; import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager; +import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager; +import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; +import com.android.systemui.statusbar.notification.stack.AmbientState; +import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager; import com.android.systemui.statusbar.phone.AutoHideController; import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.statusbar.phone.KeyguardDismissUtil; @@ -102,6 +106,7 @@ import com.android.systemui.statusbar.phone.ShadeController; import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider; import com.android.systemui.statusbar.phone.StatusBarIconController; import com.android.systemui.statusbar.phone.StatusBarWindowController; +import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController; import com.android.systemui.statusbar.policy.AccessibilityController; import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper; import com.android.systemui.statusbar.policy.BatteryController; @@ -360,6 +365,11 @@ public class Dependency { @Inject Lazy<FeatureFlags> mFeatureFlagsLazy; @Inject Lazy<StatusBarContentInsetsProvider> mContentInsetsProviderLazy; @Inject Lazy<InternetDialogFactory> mInternetDialogFactory; + @Inject Lazy<NotificationSectionsManager> mNotificationSectionsManagerLazy; + @Inject Lazy<UnlockedScreenOffAnimationController> mUnlockedScreenOffAnimationControllerLazy; + @Inject Lazy<AmbientState> mAmbientStateLazy; + @Inject Lazy<GroupMembershipManager> mGroupMembershipManagerLazy; + @Inject Lazy<GroupExpansionManager> mGroupExpansionManagerLazy; @Inject public Dependency() { @@ -574,6 +584,12 @@ public class Dependency { mProviders.put(UiEventLogger.class, mUiEventLogger::get); mProviders.put(FeatureFlags.class, mFeatureFlagsLazy::get); mProviders.put(StatusBarContentInsetsProvider.class, mContentInsetsProviderLazy::get); + mProviders.put(NotificationSectionsManager.class, mNotificationSectionsManagerLazy::get); + mProviders.put(UnlockedScreenOffAnimationController.class, + mUnlockedScreenOffAnimationControllerLazy::get); + mProviders.put(AmbientState.class, mAmbientStateLazy::get); + mProviders.put(GroupMembershipManager.class, mGroupMembershipManagerLazy::get); + mProviders.put(GroupExpansionManager.class, mGroupExpansionManagerLazy::get); Dependency.setInstance(this); } diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java index cffc048f3fd4..d1739aaccac2 100644 --- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java +++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java @@ -127,7 +127,12 @@ public class ImageWallpaper extends WallpaperService { setFixedSizeAllowed(true); updateSurfaceSize(); - mRenderer.setOnBitmapChanged(this::updateMiniBitmap); + mRenderer.setOnBitmapChanged(b -> { + mLocalColorsToAdd.addAll(mColorAreas); + if (mLocalColorsToAdd.size() > 0) { + updateMiniBitmapAndNotify(b); + } + }); getDisplayContext().getSystemService(DisplayManager.class) .registerDisplayListener(this, mWorker.getThreadHandler()); Trace.endSection(); @@ -171,7 +176,7 @@ public class ImageWallpaper extends WallpaperService { computeAndNotifyLocalColors(new ArrayList<>(mColorAreas), mMiniBitmap)); } - private void updateMiniBitmap(Bitmap b) { + private void updateMiniBitmapAndNotify(Bitmap b) { if (b == null) return; int size = Math.min(b.getWidth(), b.getHeight()); float scale = 1.0f; @@ -233,6 +238,7 @@ public class ImageWallpaper extends WallpaperService { Bitmap bitmap = mMiniBitmap; if (bitmap == null) { mLocalColorsToAdd.addAll(regions); + if (mRenderer != null) mRenderer.use(this::updateMiniBitmapAndNotify); } else { computeAndNotifyLocalColors(regions, bitmap); } diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java index 23a3f8d58f71..80c3616f693e 100644 --- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java +++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java @@ -161,8 +161,6 @@ public class ScreenDecorations extends SystemUI implements Tunable { private boolean mPendingRotationChange; private boolean mIsRoundedCornerMultipleRadius; private boolean mIsPrivacyDotEnabled; - private int mStatusBarHeightPortrait; - private int mStatusBarHeightLandscape; private Drawable mRoundedCornerDrawable; private Drawable mRoundedCornerDrawableTop; private Drawable mRoundedCornerDrawableBottom; @@ -315,7 +313,6 @@ public class ScreenDecorations extends SystemUI implements Tunable { private void setupDecorations() { if (hasRoundedCorners() || shouldDrawCutout() || mIsPrivacyDotEnabled) { - updateStatusBarHeight(); final DisplayCutout cutout = getCutout(); for (int i = 0; i < BOUNDS_POSITION_LENGTH; i++) { if (shouldShowCutout(i, cutout) || shouldShowRoundedCorner(i, cutout) @@ -326,7 +323,8 @@ public class ScreenDecorations extends SystemUI implements Tunable { } } - if (mIsPrivacyDotEnabled) { + if (mTopLeftDot != null && mTopRightDot != null && mBottomLeftDot != null + && mBottomRightDot != null) { // Overlays have been created, send the dots to the controller //TODO: need a better way to do this mDotViewController.initialize( @@ -430,7 +428,7 @@ public class ScreenDecorations extends SystemUI implements Tunable { if (mOverlays[pos] != null) { return; } - mOverlays[pos] = overlayForPosition(pos); + mOverlays[pos] = overlayForPosition(pos, cutout); mCutoutViews[pos] = new DisplayCutoutView(mContext, pos, this); ((ViewGroup) mOverlays[pos]).addView(mCutoutViews[pos]); @@ -462,10 +460,46 @@ public class ScreenDecorations extends SystemUI implements Tunable { /** * Allow overrides for top/bottom positions */ - private View overlayForPosition(@BoundsPosition int pos) { + private View overlayForPosition(@BoundsPosition int pos, @Nullable DisplayCutout cutout) { final int layoutId = (pos == BOUNDS_POSITION_LEFT || pos == BOUNDS_POSITION_TOP) ? R.layout.rounded_corners_top : R.layout.rounded_corners_bottom; - return LayoutInflater.from(mContext).inflate(layoutId, null); + final ViewGroup vg = (ViewGroup) LayoutInflater.from(mContext).inflate(layoutId, null); + initPrivacyDotView(vg, pos, cutout); + return vg; + } + + private void initPrivacyDotView(@NonNull ViewGroup viewGroup, @BoundsPosition int pos, + @Nullable DisplayCutout cutout) { + final View left = viewGroup.findViewById(R.id.privacy_dot_left_container); + final View right = viewGroup.findViewById(R.id.privacy_dot_right_container); + if (!shouldShowPrivacyDot(pos, cutout)) { + viewGroup.removeView(left); + viewGroup.removeView(right); + return; + } + + switch (pos) { + case BOUNDS_POSITION_LEFT: { + mTopLeftDot = left; + mBottomLeftDot = right; + break; + } + case BOUNDS_POSITION_TOP: { + mTopLeftDot = left; + mTopRightDot = right; + break; + } + case BOUNDS_POSITION_RIGHT: { + mTopRightDot = left; + mBottomRightDot = right; + break; + } + case BOUNDS_POSITION_BOTTOM: { + mBottomLeftDot = left; + mBottomRightDot = right; + break; + } + } } private void updateView(@BoundsPosition int pos, @Nullable DisplayCutout cutout) { @@ -483,8 +517,6 @@ public class ScreenDecorations extends SystemUI implements Tunable { if (mCutoutViews != null && mCutoutViews[pos] != null) { mCutoutViews[pos].setRotation(mRotation); } - - updatePrivacyDotView(pos, cutout); } @VisibleForTesting @@ -671,14 +703,6 @@ public class ScreenDecorations extends SystemUI implements Tunable { } } - private void updateStatusBarHeight() { - mStatusBarHeightLandscape = mContext.getResources().getDimensionPixelSize( - com.android.internal.R.dimen.status_bar_height_landscape); - mStatusBarHeightPortrait = mContext.getResources().getDimensionPixelSize( - com.android.internal.R.dimen.status_bar_height_portrait); - mDotViewController.setStatusBarHeights(mStatusBarHeightPortrait, mStatusBarHeightLandscape); - } - private void updateRoundedCornerRadii() { // We should eventually move to just using the intrinsic size of the drawables since // they should be sized to the exact pixels they want to cover. Therefore I'm purposely not @@ -812,26 +836,6 @@ public class ScreenDecorations extends SystemUI implements Tunable { } } - private void updatePrivacyDotView(@BoundsPosition int pos, @Nullable DisplayCutout cutout) { - final ViewGroup viewGroup = (ViewGroup) mOverlays[pos]; - - final View left = viewGroup.findViewById(R.id.privacy_dot_left_container); - final View right = viewGroup.findViewById(R.id.privacy_dot_right_container); - if (shouldShowPrivacyDot(pos, cutout)) { - // TODO (b/201481944) Privacy Dots pos and var are wrong with long side cutout enable - if (pos == BOUNDS_POSITION_LEFT || pos == BOUNDS_POSITION_TOP) { - mTopLeftDot = left; - mTopRightDot = right; - } else { - mBottomLeftDot = left; - mBottomRightDot = right; - } - } else { - viewGroup.removeView(left); - viewGroup.removeView(right); - } - } - private int getRoundedCornerGravity(@BoundsPosition int pos, boolean isStart) { final int rotatedPos = getBoundPositionFromRotation(pos, mRotation); switch (rotatedPos) { diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java index a28223de2bf1..c64f416f9672 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java @@ -118,6 +118,7 @@ public class SystemUIFactory { .setTaskViewFactory(mWMComponent.getTaskViewFactory()) .setTransitions(mWMComponent.getTransitions()) .setStartingSurface(mWMComponent.getStartingSurface()) + .setDisplayAreaHelper(mWMComponent.getDisplayAreaHelper()) .setTaskSurfaceHelper(mWMComponent.getTaskSurfaceHelper()); } else { // TODO: Call on prepareSysUIComponentBuilder but not with real components. Other option @@ -133,6 +134,7 @@ public class SystemUIFactory { .setAppPairs(Optional.ofNullable(null)) .setTaskViewFactory(Optional.ofNullable(null)) .setTransitions(Transitions.createEmptyForTesting()) + .setDisplayAreaHelper(Optional.ofNullable(null)) .setStartingSurface(Optional.ofNullable(null)) .setTaskSurfaceHelper(Optional.ofNullable(null)); } diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AnnotationLinkSpan.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AnnotationLinkSpan.java index d8e80fe99331..0d7551ff66e9 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AnnotationLinkSpan.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AnnotationLinkSpan.java @@ -30,7 +30,7 @@ import java.util.Optional; /** * A span that turns the text wrapped by annotation tag into the clickable link text. */ -class AnnotationLinkSpan extends ClickableSpan { +public class AnnotationLinkSpan extends ClickableSpan { private final Optional<View.OnClickListener> mClickListener; private AnnotationLinkSpan(View.OnClickListener listener) { @@ -50,7 +50,7 @@ class AnnotationLinkSpan extends ClickableSpan { * @param linkInfos used to attach the click action into the corresponding span * @return the text attached with the span */ - static CharSequence linkify(CharSequence text, LinkInfo... linkInfos) { + public static CharSequence linkify(CharSequence text, LinkInfo... linkInfos) { final SpannableString msg = new SpannableString(text); final Annotation[] spans = msg.getSpans(/* queryStart= */ 0, msg.length(), Annotation.class); @@ -78,12 +78,12 @@ class AnnotationLinkSpan extends ClickableSpan { /** * Data class to store the annotation and the click action. */ - static class LinkInfo { - static final String DEFAULT_ANNOTATION = "link"; + public static class LinkInfo { + public static final String DEFAULT_ANNOTATION = "link"; private final Optional<String> mAnnotation; private final Optional<View.OnClickListener> mListener; - LinkInfo(@NonNull String annotation, View.OnClickListener listener) { + public LinkInfo(@NonNull String annotation, View.OnClickListener listener) { mAnnotation = Optional.of(annotation); mListener = Optional.ofNullable(listener); } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java index b2eaa2b8a821..3a3f22a4fda8 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java @@ -889,6 +889,7 @@ public class UdfpsController implements DozeReceiver { } if (!mKeyguardUpdateMonitor.isFingerprintDetectionRunning()) { + mKeyguardViewManager.showBouncer(true); return; } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java index 37a6cfaabb5e..0a9329845b23 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java @@ -330,7 +330,7 @@ public class BrightLineFalsingManager implements FalsingManager { || mTestHarness || mDataProvider.isJustUnlockedWithFace() || mDataProvider.isDocked() - || mAccessibilityManager.isEnabled(); + || mAccessibilityManager.isTouchExplorationEnabled(); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java index d74df37401d0..79723188348e 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java @@ -374,6 +374,12 @@ public class FrameworkServicesModule { @Provides @Singleton + static Optional<TelecomManager> provideOptionalTelecomManager(Context context) { + return Optional.ofNullable(context.getSystemService(TelecomManager.class)); + } + + @Provides + @Singleton static TelephonyManager provideTelephonyManager(Context context) { return context.getSystemService(TelephonyManager.class); } diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java index 0fdc4d8e86a7..a9a4da8d94a2 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java @@ -25,11 +25,11 @@ import com.android.systemui.dump.DumpManager; import com.android.systemui.keyguard.KeyguardSliceProvider; import com.android.systemui.people.PeopleProvider; import com.android.systemui.statusbar.policy.ConfigurationController; -import com.android.systemui.util.InjectionInflationController; import com.android.wm.shell.ShellCommandHandler; import com.android.wm.shell.TaskViewFactory; import com.android.wm.shell.apppairs.AppPairs; import com.android.wm.shell.bubbles.Bubbles; +import com.android.wm.shell.displayareahelper.DisplayAreaHelper; import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout; import com.android.wm.shell.legacysplitscreen.LegacySplitScreen; import com.android.wm.shell.onehanded.OneHanded; @@ -96,6 +96,9 @@ public interface SysUIComponent { Builder setStartingSurface(Optional<StartingSurface> s); @BindsInstance + Builder setDisplayAreaHelper(Optional<DisplayAreaHelper> h); + + @BindsInstance Builder setTaskSurfaceHelper(Optional<TaskSurfaceHelper> t); SysUIComponent build(); @@ -143,11 +146,6 @@ public interface SysUIComponent { InitController getInitController(); /** - * ViewInstanceCreator generates all Views that need injection. - */ - InjectionInflationController.ViewInstanceCreator.Factory createViewInstanceCreatorFactory(); - - /** * Member injection into the supplied argument. */ void inject(SystemUIAppComponentFactory factory); diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java index 0923caaf0d76..50d2dd16b407 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java @@ -187,9 +187,13 @@ public abstract class SystemUIDefaultModule { return new Recents(context, recentsImplementation, commandQueue); } - @Binds - abstract DeviceProvisionedController bindDeviceProvisionedController( - DeviceProvisionedControllerImpl deviceProvisionedController); + @SysUISingleton + @Provides + static DeviceProvisionedController bindDeviceProvisionedController( + DeviceProvisionedControllerImpl deviceProvisionedController) { + deviceProvisionedController.init(); + return deviceProvisionedController; + } @Binds abstract KeyguardViewController bindKeyguardViewController( diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java index f9331280ece3..a4e2572836f8 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java @@ -75,7 +75,6 @@ import com.android.systemui.statusbar.policy.dagger.SmartRepliesInflationModule; import com.android.systemui.statusbar.policy.dagger.StatusBarPolicyModule; import com.android.systemui.tuner.dagger.TunerModule; import com.android.systemui.user.UserModule; -import com.android.systemui.util.InjectionInflationController; import com.android.systemui.util.concurrency.SysUIConcurrencyModule; import com.android.systemui.util.dagger.UtilModule; import com.android.systemui.util.sensors.SensorModule; @@ -216,11 +215,9 @@ public abstract class SystemUIModule { @Provides @SysUISingleton - static StatusBarWindowView providesStatusBarWindowView(Context context, - InjectionInflationController injectionInflationController) { + static StatusBarWindowView providesStatusBarWindowView(LayoutInflater layoutInflater) { StatusBarWindowView view = - (StatusBarWindowView) injectionInflationController.injectable( - LayoutInflater.from(context)).inflate(R.layout.super_status_bar, + (StatusBarWindowView) layoutInflater.inflate(R.layout.super_status_bar, /* root= */ null); if (view == null) { throw new IllegalStateException( diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java index 442d351729d7..618c26b89196 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java @@ -27,6 +27,7 @@ import com.android.wm.shell.ShellInit; import com.android.wm.shell.TaskViewFactory; import com.android.wm.shell.apppairs.AppPairs; import com.android.wm.shell.bubbles.Bubbles; +import com.android.wm.shell.displayareahelper.DisplayAreaHelper; import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout; import com.android.wm.shell.legacysplitscreen.LegacySplitScreen; import com.android.wm.shell.onehanded.OneHanded; @@ -105,5 +106,8 @@ public interface WMComponent { Optional<StartingSurface> getStartingSurface(); @WMSingleton + Optional<DisplayAreaHelper> getDisplayAreaHelper(); + + @WMSingleton Optional<TaskSurfaceHelper> getTaskSurfaceHelper(); } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java index 845d7dc26ee5..669965bcbea5 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java @@ -26,6 +26,7 @@ import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.systemui.Dumpable; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dump.DumpManager; +import com.android.systemui.statusbar.policy.DevicePostureController; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -268,6 +269,16 @@ public class DozeLog implements Dumpable { } /** + * Appends doze updates due to a posture change. + */ + public void tracePostureChanged( + @DevicePostureController.DevicePostureInt int posture, + String partUpdated + ) { + mLogger.logPostureChanged(posture, partUpdated); + } + + /** * Appends pulse dropped event to logs */ public void tracePulseDropped(boolean pulsePending, DozeMachine.State state, boolean blocked) { @@ -391,8 +402,8 @@ public class DozeLog implements Dumpable { case REASON_SENSOR_DOUBLE_TAP: return "doubletap"; case PULSE_REASON_SENSOR_LONG_PRESS: return "longpress"; case PULSE_REASON_DOCKING: return "docking"; - case PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN: return "reach-wakelockscreen"; - case REASON_SENSOR_WAKE_UP: return "presence-wakeup"; + case PULSE_REASON_SENSOR_WAKE_REACH: return "reach-wakelockscreen"; + case REASON_SENSOR_WAKE_UP_PRESENCE: return "presence-wakeup"; case REASON_SENSOR_TAP: return "tap"; case REASON_SENSOR_UDFPS_LONG_PRESS: return "udfps"; case REASON_SENSOR_QUICK_PICKUP: return "quickPickup"; @@ -403,8 +414,8 @@ public class DozeLog implements Dumpable { @Retention(RetentionPolicy.SOURCE) @IntDef({PULSE_REASON_NONE, PULSE_REASON_INTENT, PULSE_REASON_NOTIFICATION, PULSE_REASON_SENSOR_SIGMOTION, REASON_SENSOR_PICKUP, REASON_SENSOR_DOUBLE_TAP, - PULSE_REASON_SENSOR_LONG_PRESS, PULSE_REASON_DOCKING, REASON_SENSOR_WAKE_UP, - PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN, REASON_SENSOR_TAP, + PULSE_REASON_SENSOR_LONG_PRESS, PULSE_REASON_DOCKING, REASON_SENSOR_WAKE_UP_PRESENCE, + PULSE_REASON_SENSOR_WAKE_REACH, REASON_SENSOR_TAP, REASON_SENSOR_UDFPS_LONG_PRESS, REASON_SENSOR_QUICK_PICKUP}) public @interface Reason {} public static final int PULSE_REASON_NONE = -1; @@ -415,8 +426,8 @@ public class DozeLog implements Dumpable { public static final int REASON_SENSOR_DOUBLE_TAP = 4; public static final int PULSE_REASON_SENSOR_LONG_PRESS = 5; public static final int PULSE_REASON_DOCKING = 6; - public static final int REASON_SENSOR_WAKE_UP = 7; - public static final int PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN = 8; + public static final int REASON_SENSOR_WAKE_UP_PRESENCE = 7; + public static final int PULSE_REASON_SENSOR_WAKE_REACH = 8; public static final int REASON_SENSOR_TAP = 9; public static final int REASON_SENSOR_UDFPS_LONG_PRESS = 10; public static final int REASON_SENSOR_QUICK_PICKUP = 11; diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt b/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt index dc186182432f..d79bf22cced2 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt @@ -24,6 +24,7 @@ import com.android.systemui.log.LogLevel.DEBUG import com.android.systemui.log.LogLevel.ERROR import com.android.systemui.log.LogLevel.INFO import com.android.systemui.log.dagger.DozeLog +import com.android.systemui.statusbar.policy.DevicePostureController import java.text.SimpleDateFormat import java.util.Date import java.util.Locale @@ -195,6 +196,16 @@ class DozeLogger @Inject constructor( }) } + fun logPostureChanged(posture: Int, partUpdated: String) { + buffer.log(TAG, INFO, { + int1 = posture + str1 = partUpdated + }, { + "Posture changed, posture=${DevicePostureController.devicePostureToString(int1)}" + + " partUpdated=$str1" + }) + } + fun logPulseDropped(pulsePending: Boolean, state: DozeMachine.State, blocked: Boolean) { buffer.log(TAG, INFO, { bool1 = pulsePending diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java index da7b389fbd36..765c24507662 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java @@ -29,16 +29,18 @@ import android.os.SystemProperties; import android.os.Trace; import android.os.UserHandle; import android.provider.Settings; +import android.util.IndentingPrintWriter; -import com.android.systemui.dock.DockManager; import com.android.systemui.doze.dagger.BrightnessSensor; import com.android.systemui.doze.dagger.DozeScope; import com.android.systemui.doze.dagger.WrappedService; import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.statusbar.phone.DozeParameters; +import com.android.systemui.statusbar.policy.DevicePostureController; import com.android.systemui.util.sensors.AsyncSensorManager; import java.io.PrintWriter; +import java.util.Objects; import java.util.Optional; import javax.inject.Inject; @@ -60,14 +62,17 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi private final DozeHost mDozeHost; private final Handler mHandler; private final SensorManager mSensorManager; - private final Optional<Sensor> mLightSensorOptional; + private final Optional<Sensor>[] mLightSensorOptional; // light sensors to use per posture private final WakefulnessLifecycle mWakefulnessLifecycle; private final DozeParameters mDozeParameters; - private final DockManager mDockManager; + private final DevicePostureController mDevicePostureController; + private final DozeLog mDozeLog; private final int[] mSensorToBrightness; private final int[] mSensorToScrimOpacity; private final int mScreenBrightnessDim; + @DevicePostureController.DevicePostureInt + private int mDevicePosture; private boolean mRegistered; private int mDefaultDozeBrightness; private boolean mPaused = false; @@ -83,27 +88,36 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi private int mDebugBrightnessBucket = -1; @Inject - public DozeScreenBrightness(Context context, @WrappedService DozeMachine.Service service, + public DozeScreenBrightness( + Context context, + @WrappedService DozeMachine.Service service, AsyncSensorManager sensorManager, - @BrightnessSensor Optional<Sensor> lightSensorOptional, DozeHost host, Handler handler, + @BrightnessSensor Optional<Sensor>[] lightSensorOptional, + DozeHost host, Handler handler, AlwaysOnDisplayPolicy alwaysOnDisplayPolicy, WakefulnessLifecycle wakefulnessLifecycle, DozeParameters dozeParameters, - DockManager dockManager) { + DevicePostureController devicePostureController, + DozeLog dozeLog + ) { mContext = context; mDozeService = service; mSensorManager = sensorManager; mLightSensorOptional = lightSensorOptional; + mDevicePostureController = devicePostureController; + mDevicePosture = mDevicePostureController.getDevicePosture(); mWakefulnessLifecycle = wakefulnessLifecycle; mDozeParameters = dozeParameters; mDozeHost = host; mHandler = handler; - mDockManager = dockManager; + mDozeLog = dozeLog; mDefaultDozeBrightness = alwaysOnDisplayPolicy.defaultDozeBrightness; mScreenBrightnessDim = alwaysOnDisplayPolicy.dimBrightness; mSensorToBrightness = alwaysOnDisplayPolicy.screenBrightnessArray; mSensorToScrimOpacity = alwaysOnDisplayPolicy.dimmingScrimArray; + + mDevicePostureController.addCallback(mDevicePostureCallback); } @Override @@ -133,6 +147,7 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi private void onDestroy() { setLightSensorEnabled(false); + mDevicePostureController.removeCallback(mDevicePostureCallback); } @Override @@ -159,7 +174,7 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi } int scrimOpacity = -1; - if (!mLightSensorOptional.isPresent()) { + if (!isLightSensorPresent()) { // No light sensor, scrims are always transparent. scrimOpacity = 0; } else if (brightnessReady) { @@ -172,6 +187,27 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi } } + private boolean lightSensorSupportsCurrentPosture() { + return mLightSensorOptional != null + && mDevicePosture < mLightSensorOptional.length; + } + + private boolean isLightSensorPresent() { + if (!lightSensorSupportsCurrentPosture()) { + return mLightSensorOptional != null && mLightSensorOptional[0].isPresent(); + } + + return mLightSensorOptional[mDevicePosture].isPresent(); + } + + private Sensor getLightSensor() { + if (!lightSensorSupportsCurrentPosture()) { + return null; + } + + return mLightSensorOptional[mDevicePosture].get(); + } + private int computeScrimOpacity(int sensorValue) { if (sensorValue < 0 || sensorValue >= mSensorToScrimOpacity.length) { return -1; @@ -220,9 +256,9 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi } private void setLightSensorEnabled(boolean enabled) { - if (enabled && !mRegistered && mLightSensorOptional.isPresent()) { + if (enabled && !mRegistered && isLightSensorPresent()) { // Wait until we get an event from the sensor until indicating ready. - mRegistered = mSensorManager.registerListener(this, mLightSensorOptional.get(), + mRegistered = mSensorManager.registerListener(this, getLightSensor(), SensorManager.SENSOR_DELAY_NORMAL, mHandler); mLastSensorValue = -1; } else if (!enabled && mRegistered) { @@ -255,6 +291,41 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi /** Dump current state */ public void dump(PrintWriter pw) { - pw.println("DozeScreenBrightnessSensorRegistered=" + mRegistered); + pw.println("DozeScreenBrightness:"); + IndentingPrintWriter idpw = new IndentingPrintWriter(pw); + idpw.increaseIndent(); + idpw.println("registered=" + mRegistered); + idpw.println("posture=" + DevicePostureController.devicePostureToString(mDevicePosture)); } + + private final DevicePostureController.Callback mDevicePostureCallback = + new DevicePostureController.Callback() { + @Override + public void onPostureChanged(int posture) { + if (mDevicePosture == posture + || mLightSensorOptional.length < 2 + || posture >= mLightSensorOptional.length) { + return; + } + + final Sensor oldSensor = mLightSensorOptional[mDevicePosture].get(); + final Sensor newSensor = mLightSensorOptional[posture].get(); + if (Objects.equals(oldSensor, newSensor)) { + mDevicePosture = posture; + // uses the same sensor for the new posture + return; + } + + // cancel the previous sensor: + if (mRegistered) { + setLightSensorEnabled(false); + mDevicePosture = posture; + setLightSensorEnabled(true); + } else { + mDevicePosture = posture; + } + mDozeLog.tracePostureChanged(mDevicePosture, "DozeScreenBrightness swap " + + "{" + oldSensor + "} => {" + newSensor + "}, mRegistered=" + mRegistered); + } + }; } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java index 3cefce83393a..9d0591e4bda2 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java @@ -38,6 +38,7 @@ import android.util.IndentingPrintWriter; import android.util.Log; import android.view.Display; +import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; import com.android.internal.logging.UiEvent; @@ -54,10 +55,36 @@ import com.android.systemui.util.settings.SecureSettings; import com.android.systemui.util.wakelock.WakeLock; import java.io.PrintWriter; +import java.util.Arrays; import java.util.Collection; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.Objects; import java.util.function.Consumer; +/** + * Tracks and registers/unregisters sensors while the device is dozing based on the config + * provided by {@link AmbientDisplayConfiguration} and parameters provided by {@link DozeParameters} + * + * Sensors registration depends on: + * - sensor existence/availability + * - user configuration (some can be toggled on/off via settings) + * - use of the proximity sensor (sometimes prox cannot be registered in certain display states) + * - touch state + * - device posture + * + * Sensors will trigger the provided Callback's {@link Callback#onSensorPulse} method. + * These sensors include: + * - pickup gesture + * - single and double tap gestures + * - udfps long-press gesture + * - reach and presence gestures + * - quick pickup gesture (low-threshold pickup gesture) + * + * This class also registers a ProximitySensor that reports near/far events and will + * trigger callbacks on the provided {@link mProxCallback}. + */ public class DozeSensors { private static final boolean DEBUG = DozeService.DEBUG; @@ -68,15 +95,21 @@ public class DozeSensors { private final AsyncSensorManager mSensorManager; private final AmbientDisplayConfiguration mConfig; private final WakeLock mWakeLock; - private final Consumer<Boolean> mProxCallback; + private final DozeLog mDozeLog; private final SecureSettings mSecureSettings; - private final Callback mCallback; + private final DevicePostureController mDevicePostureController; private final boolean mScreenOffUdfpsEnabled; + + // Sensors @VisibleForTesting - protected TriggerSensor[] mSensors; + protected TriggerSensor[] mTriggerSensors; + private final ProximitySensor mProximitySensor; + + // Sensor callbacks + private final Callback mSensorCallback; // receives callbacks on registered sensor events + private final Consumer<Boolean> mProxCallback; // receives callbacks on near/far updates private final Handler mHandler = new Handler(); - private final ProximitySensor mProximitySensor; private long mDebounceFrom; private boolean mSettingRegistered; private boolean mListening; @@ -106,37 +139,47 @@ public class DozeSensors { } } - DozeSensors(Context context, AsyncSensorManager sensorManager, - DozeParameters dozeParameters, AmbientDisplayConfiguration config, WakeLock wakeLock, - Callback callback, Consumer<Boolean> proxCallback, DozeLog dozeLog, - ProximitySensor proximitySensor, SecureSettings secureSettings, + DozeSensors( + Context context, + AsyncSensorManager sensorManager, + DozeParameters dozeParameters, + AmbientDisplayConfiguration config, + WakeLock wakeLock, + Callback sensorCallback, + Consumer<Boolean> proxCallback, + DozeLog dozeLog, + ProximitySensor proximitySensor, + SecureSettings secureSettings, AuthController authController, - int devicePosture) { + DevicePostureController devicePostureController + ) { mContext = context; mSensorManager = sensorManager; mConfig = config; mWakeLock = wakeLock; mProxCallback = proxCallback; mSecureSettings = secureSettings; - mCallback = callback; + mSensorCallback = sensorCallback; + mDozeLog = dozeLog; mProximitySensor = proximitySensor; mProximitySensor.setTag(TAG); mSelectivelyRegisterProxSensors = dozeParameters.getSelectivelyRegisterSensorsUsingProx(); mListeningProxSensors = !mSelectivelyRegisterProxSensors; mScreenOffUdfpsEnabled = config.screenOffUdfpsEnabled(KeyguardUpdateMonitor.getCurrentUser()); - mDevicePosture = devicePosture; + mDevicePostureController = devicePostureController; + mDevicePosture = mDevicePostureController.getDevicePosture(); boolean udfpsEnrolled = authController.isUdfpsEnrolled(KeyguardUpdateMonitor.getCurrentUser()); boolean alwaysOn = mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT); - mSensors = new TriggerSensor[] { + mTriggerSensors = new TriggerSensor[] { new TriggerSensor( mSensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION), null /* setting */, dozeParameters.getPulseOnSigMotion(), DozeLog.PULSE_REASON_SENSOR_SIGMOTION, false /* touchCoords */, - false /* touchscreen */, dozeLog), + false /* touchscreen */), new TriggerSensor( mSensorManager.getDefaultSensor(Sensor.TYPE_PICK_UP_GESTURE), Settings.Secure.DOZE_PICK_UP_GESTURE, @@ -145,18 +188,16 @@ public class DozeSensors { DozeLog.REASON_SENSOR_PICKUP, false /* touchCoords */, false /* touchscreen */, false /* ignoresSetting */, - false /* requires prox */, - dozeLog), + false /* requires prox */), new TriggerSensor( findSensor(config.doubleTapSensorType()), Settings.Secure.DOZE_DOUBLE_TAP_GESTURE, true /* configured */, DozeLog.REASON_SENSOR_DOUBLE_TAP, dozeParameters.doubleTapReportsTouchCoordinates(), - true /* touchscreen */, - dozeLog), + true /* touchscreen */), new TriggerSensor( - findSensor(config.tapSensorType(mDevicePosture)), + findSensors(config.tapSensorTypeMapping()), Settings.Secure.DOZE_TAP_SCREEN_GESTURE, true /* settingDef */, true /* configured */, @@ -165,7 +206,7 @@ public class DozeSensors { true /* touchscreen */, false /* ignoresSetting */, dozeParameters.singleTapUsesProx(mDevicePosture) /* requiresProx */, - dozeLog), + mDevicePosture), new TriggerSensor( findSensor(config.longPressSensorType()), Settings.Secure.DOZE_PULSE_ON_LONG_PRESS, @@ -175,8 +216,7 @@ public class DozeSensors { true /* reports touch coordinates */, true /* touchscreen */, false /* ignoresSetting */, - dozeParameters.longPressUsesProx() /* requiresProx */, - dozeLog), + dozeParameters.longPressUsesProx() /* requiresProx */), new TriggerSensor( findSensor(config.udfpsLongPressSensorType()), "doze_pulse_on_auth", @@ -186,25 +226,22 @@ public class DozeSensors { true /* reports touch coordinates */, true /* touchscreen */, false /* ignoresSetting */, - dozeParameters.longPressUsesProx(), - dozeLog), + dozeParameters.longPressUsesProx()), new PluginSensor( new SensorManagerPlugin.Sensor(TYPE_WAKE_DISPLAY), Settings.Secure.DOZE_WAKE_DISPLAY_GESTURE, mConfig.wakeScreenGestureAvailable() && alwaysOn, - DozeLog.REASON_SENSOR_WAKE_UP, + DozeLog.REASON_SENSOR_WAKE_UP_PRESENCE, false /* reports touch coordinates */, - false /* touchscreen */, - dozeLog), + false /* touchscreen */), new PluginSensor( new SensorManagerPlugin.Sensor(TYPE_WAKE_LOCK_SCREEN), Settings.Secure.DOZE_WAKE_LOCK_SCREEN_GESTURE, mConfig.wakeScreenGestureAvailable(), - DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN, + DozeLog.PULSE_REASON_SENSOR_WAKE_REACH, false /* reports touch coordinates */, false /* touchscreen */, - mConfig.getWakeLockScreenDebounce(), - dozeLog), + mConfig.getWakeLockScreenDebounce()), new TriggerSensor( findSensor(config.quickPickupSensorType()), Settings.Secure.DOZE_QUICK_PICKUP_GESTURE, @@ -212,10 +249,11 @@ public class DozeSensors { config.quickPickupSensorEnabled(KeyguardUpdateMonitor.getCurrentUser()) && udfpsEnrolled, DozeLog.REASON_SENSOR_QUICK_PICKUP, - false /* touchCoords */, - false /* touchscreen */, dozeLog), + false /* requiresTouchCoordinates */, + false /* requiresTouchscreen */, + false /* ignoresSetting */, + false /* requiresProx */), }; - setProxListening(false); // Don't immediately start listening when we register. mProximitySensor.register( proximityEvent -> { @@ -223,17 +261,21 @@ public class DozeSensors { mProxCallback.accept(!proximityEvent.getBelow()); } }); + + mDevicePostureController.addCallback(mDevicePostureCallback); } /** - * Unregister any sensors. + * Unregister all sensors and callbacks. */ public void destroy() { // Unregisters everything, which is enough to allow gc. - for (TriggerSensor triggerSensor : mSensors) { + for (TriggerSensor triggerSensor : mTriggerSensors) { triggerSensor.setListening(false); } mProximitySensor.pause(); + + mDevicePostureController.removeCallback(mDevicePostureCallback); } /** @@ -248,6 +290,24 @@ public class DozeSensors { return findSensor(mSensorManager, type, null); } + @NonNull + private Sensor[] findSensors(@NonNull String[] types) { + Sensor[] sensorMap = new Sensor[DevicePostureController.SUPPORTED_POSTURES_SIZE]; + + // Map of sensorType => Sensor, so we reuse the same sensor if it's the same between + // postures + Map<String, Sensor> typeToSensorMap = new HashMap<>(); + for (int i = 0; i < types.length; i++) { + String sensorType = types[i]; + if (!typeToSensorMap.containsKey(sensorType)) { + typeToSensorMap.put(sensorType, findSensor(sensorType)); + } + sensorMap[i] = typeToSensorMap.get(sensorType); + } + + return sensorMap; + } + /** * Utility method to find a {@link Sensor} for the supplied string type and string name. * @@ -306,7 +366,7 @@ public class DozeSensors { */ private void updateListening() { boolean anyListening = false; - for (TriggerSensor s : mSensors) { + for (TriggerSensor s : mTriggerSensors) { boolean listen = mListening && (!s.mRequiresTouchscreen || mListeningTouchScreenSensors) && (!s.mRequiresProx || mListeningProxSensors); @@ -319,7 +379,7 @@ public class DozeSensors { if (!anyListening) { mSecureSettings.unregisterContentObserver(mSettingsObserver); } else if (!mSettingRegistered) { - for (TriggerSensor s : mSensors) { + for (TriggerSensor s : mTriggerSensors) { s.registerSettingsObserver(mSettingsObserver); } } @@ -328,7 +388,7 @@ public class DozeSensors { /** Set the listening state of only the sensors that require the touchscreen. */ public void setTouchscreenSensorsListening(boolean listening) { - for (TriggerSensor sensor : mSensors) { + for (TriggerSensor sensor : mTriggerSensors) { if (sensor.mRequiresTouchscreen) { sensor.setListening(listening); } @@ -336,7 +396,7 @@ public class DozeSensors { } public void onUserSwitched() { - for (TriggerSensor s : mSensors) { + for (TriggerSensor s : mTriggerSensors) { s.updateListening(); } } @@ -366,7 +426,7 @@ public class DozeSensors { if (userId != ActivityManager.getCurrentUser()) { return; } - for (TriggerSensor s : mSensors) { + for (TriggerSensor s : mTriggerSensors) { s.updateListening(); } } @@ -374,7 +434,7 @@ public class DozeSensors { /** Ignore the setting value of only the sensors that require the touchscreen. */ public void ignoreTouchScreenSensorsSettingInterferingWithDocking(boolean ignore) { - for (TriggerSensor sensor : mSensors) { + for (TriggerSensor sensor : mTriggerSensors) { if (sensor.mRequiresTouchscreen) { sensor.ignoreSetting(ignore); } @@ -392,7 +452,7 @@ public class DozeSensors { pw.println("mScreenOffUdfpsEnabled=" + mScreenOffUdfpsEnabled); IndentingPrintWriter idpw = new IndentingPrintWriter(pw); idpw.increaseIndent(); - for (TriggerSensor s : mSensors) { + for (TriggerSensor s : mTriggerSensors) { idpw.println("Sensor: " + s.toString()); } idpw.println("ProxSensor: " + mProximitySensor.toString()); @@ -407,7 +467,7 @@ public class DozeSensors { @VisibleForTesting class TriggerSensor extends TriggerEventListener { - final Sensor mSensor; + @NonNull final Sensor[] mSensors; // index = posture, value = sensor final boolean mConfigured; final int mPulseReason; private final String mSetting; @@ -420,27 +480,67 @@ public class DozeSensors { protected boolean mRegistered; protected boolean mDisabled; protected boolean mIgnoresSetting; - protected final DozeLog mDozeLog; - - public TriggerSensor(Sensor sensor, String setting, boolean configured, int pulseReason, - boolean reportsTouchCoordinates, boolean requiresTouchscreen, DozeLog dozeLog) { - this(sensor, setting, true /* settingDef */, configured, pulseReason, - reportsTouchCoordinates, requiresTouchscreen, dozeLog); - } - - public TriggerSensor(Sensor sensor, String setting, boolean settingDef, - boolean configured, int pulseReason, boolean reportsTouchCoordinates, - boolean requiresTouchscreen, DozeLog dozeLog) { - this(sensor, setting, settingDef, configured, pulseReason, reportsTouchCoordinates, - requiresTouchscreen, false /* ignoresSetting */, - false /* requiresProx */, dozeLog); - } - - private TriggerSensor(Sensor sensor, String setting, boolean settingDef, - boolean configured, int pulseReason, boolean reportsTouchCoordinates, - boolean requiresTouchscreen, boolean ignoresSetting, boolean requiresProx, - DozeLog dozeLog) { - mSensor = sensor; + private @DevicePostureController.DevicePostureInt int mPosture; + + TriggerSensor( + Sensor sensor, + String setting, + boolean configured, + int pulseReason, + boolean reportsTouchCoordinates, + boolean requiresTouchscreen + ) { + this( + sensor, + setting, + true /* settingDef */, + configured, + pulseReason, + false /* ignoresSetting */, + false /* requiresProx */, + reportsTouchCoordinates, + requiresTouchscreen + ); + } + + TriggerSensor( + Sensor sensor, + String setting, + boolean settingDef, + boolean configured, + int pulseReason, + boolean reportsTouchCoordinates, + boolean requiresTouchscreen, + boolean ignoresSetting, + boolean requiresProx + ) { + this( + new Sensor[]{ sensor }, + setting, + settingDef, + configured, + pulseReason, + reportsTouchCoordinates, + requiresTouchscreen, + ignoresSetting, + requiresProx, + DevicePostureController.DEVICE_POSTURE_UNKNOWN + ); + } + + TriggerSensor( + @NonNull Sensor[] sensors, + String setting, + boolean settingDef, + boolean configured, + int pulseReason, + boolean reportsTouchCoordinates, + boolean requiresTouchscreen, + boolean ignoresSetting, + boolean requiresProx, + @DevicePostureController.DevicePostureInt int posture + ) { + mSensors = sensors; mSetting = setting; mSettingDefault = settingDef; mConfigured = configured; @@ -449,7 +549,43 @@ public class DozeSensors { mRequiresTouchscreen = requiresTouchscreen; mIgnoresSetting = ignoresSetting; mRequiresProx = requiresProx; - mDozeLog = dozeLog; + mPosture = posture; + } + + /** + * @return true if the sensor changed based for the new posture + */ + public boolean setPosture(@DevicePostureController.DevicePostureInt int posture) { + if (mPosture == posture + || mSensors.length < 2 + || posture >= mSensors.length) { + return false; + } + + Sensor oldSensor = mSensors[mPosture]; + Sensor newSensor = mSensors[posture]; + if (Objects.equals(oldSensor, newSensor)) { + mPosture = posture; + // uses the same sensor for the new posture + return false; + } + + // cancel the previous sensor: + if (mRegistered) { + final boolean rt = mSensorManager.cancelTriggerSensor(this, oldSensor); + if (DEBUG) { + Log.d(TAG, "posture changed, cancelTriggerSensor[" + oldSensor + "] " + + rt); + } + mRegistered = false; + } + + // update the new sensor: + mPosture = posture; + updateListening(); + mDozeLog.tracePostureChanged(mPosture, "DozeSensors swap " + + "{" + oldSensor + "} => {" + newSensor + "}, mRegistered=" + mRegistered); + return true; } public void setListening(boolean listen) { @@ -471,24 +607,23 @@ public class DozeSensors { } public void updateListening() { - if (!mConfigured || mSensor == null) return; + final Sensor sensor = mSensors[mPosture]; + if (!mConfigured || sensor == null) return; if (mRequested && !mDisabled && (enabledBySetting() || mIgnoresSetting)) { if (!mRegistered) { - mRegistered = mSensorManager.requestTriggerSensor(this, mSensor); + mRegistered = mSensorManager.requestTriggerSensor(this, sensor); if (DEBUG) { - Log.d(TAG, "requestTriggerSensor[" + mSensor - + "] " + mRegistered); + Log.d(TAG, "requestTriggerSensor[" + sensor + "] " + mRegistered); } } else { if (DEBUG) { - Log.d(TAG, "requestTriggerSensor[" + mSensor - + "] already registered"); + Log.d(TAG, "requestTriggerSensor[" + sensor + "] already registered"); } } } else if (mRegistered) { - final boolean rt = mSensorManager.cancelTriggerSensor(this, mSensor); + final boolean rt = mSensorManager.cancelTriggerSensor(this, sensor); if (DEBUG) { - Log.d(TAG, "cancelTriggerSensor[" + mSensor + "] " + rt); + Log.d(TAG, "cancelTriggerSensor[" + sensor + "] " + rt); } mRegistered = false; } @@ -506,21 +641,29 @@ public class DozeSensors { @Override public String toString() { - return new StringBuilder("{mRegistered=").append(mRegistered) + StringBuilder sb = new StringBuilder(); + sb.append("{") + .append("mRegistered=").append(mRegistered) .append(", mRequested=").append(mRequested) .append(", mDisabled=").append(mDisabled) .append(", mConfigured=").append(mConfigured) .append(", mIgnoresSetting=").append(mIgnoresSetting) - .append(", mSensor=").append(mSensor).append("}").toString(); + .append(", mSensors=").append(Arrays.toString(mSensors)); + if (mSensors.length > 2) { + sb.append(", mPosture=") + .append(DevicePostureController.devicePostureToString(mDevicePosture)); + } + return sb.append("}").toString(); } @Override @AnyThread public void onTrigger(TriggerEvent event) { + final Sensor sensor = mSensors[mDevicePosture]; mDozeLog.traceSensor(mPulseReason); mHandler.post(mWakeLock.wrap(() -> { if (DEBUG) Log.d(TAG, "onTrigger: " + triggerEventToString(event)); - if (mSensor != null && mSensor.getType() == Sensor.TYPE_PICK_UP_GESTURE) { + if (sensor != null && sensor.getType() == Sensor.TYPE_PICK_UP_GESTURE) { UI_EVENT_LOGGER.log(DozeSensorsUiEvent.ACTION_AMBIENT_GESTURE_PICKUP); } @@ -531,7 +674,7 @@ public class DozeSensors { screenX = event.values[0]; screenY = event.values[1]; } - mCallback.onSensorPulse(mPulseReason, screenX, screenY, event.values); + mSensorCallback.onSensorPulse(mPulseReason, screenX, screenY, event.values); if (!mRegistered) { updateListening(); // reregister, this sensor only fires once } @@ -569,17 +712,16 @@ public class DozeSensors { private long mDebounce; PluginSensor(SensorManagerPlugin.Sensor sensor, String setting, boolean configured, - int pulseReason, boolean reportsTouchCoordinates, boolean requiresTouchscreen, - DozeLog dozeLog) { + int pulseReason, boolean reportsTouchCoordinates, boolean requiresTouchscreen) { this(sensor, setting, configured, pulseReason, reportsTouchCoordinates, - requiresTouchscreen, 0L /* debounce */, dozeLog); + requiresTouchscreen, 0L /* debounce */); } PluginSensor(SensorManagerPlugin.Sensor sensor, String setting, boolean configured, int pulseReason, boolean reportsTouchCoordinates, boolean requiresTouchscreen, - long debounce, DozeLog dozeLog) { + long debounce) { super(null, setting, configured, pulseReason, reportsTouchCoordinates, - requiresTouchscreen, dozeLog); + requiresTouchscreen); mPluginSensor = sensor; mDebounce = debounce; } @@ -633,11 +775,22 @@ public class DozeSensors { return; } if (DEBUG) Log.d(TAG, "onSensorEvent: " + triggerEventToString(event)); - mCallback.onSensorPulse(mPulseReason, -1, -1, event.getValues()); + mSensorCallback.onSensorPulse(mPulseReason, -1, -1, event.getValues()); })); } } + private final DevicePostureController.Callback mDevicePostureCallback = posture -> { + if (mDevicePosture == posture) { + return; + } + mDevicePosture = posture; + + for (TriggerSensor triggerSensor : mTriggerSensors) { + triggerSensor.setPosture(mDevicePosture); + } + }; + public interface Callback { /** diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java index b17f078e24ef..20cd5b987c1c 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java @@ -99,8 +99,6 @@ public class DozeTriggers implements DozeMachine.Part { private final UiEventLogger mUiEventLogger; private final DevicePostureController mDevicePostureController; - private @DevicePostureController.DevicePostureInt int mDevicePosture; - private long mNotificationPulseTime; private boolean mPulsePending; private Runnable mAodInterruptRunnable; @@ -197,11 +195,12 @@ public class DozeTriggers implements DozeMachine.Part { mSensorManager = sensorManager; mWakeLock = wakeLock; mAllowPulseTriggers = true; + mDevicePostureController = devicePostureController; - mDevicePosture = devicePostureController.getDevicePosture(); mDozeSensors = new DozeSensors(context, mSensorManager, dozeParameters, config, wakeLock, this::onSensor, this::onProximityFar, dozeLog, proximitySensor, - secureSettings, authController, mDevicePosture); + secureSettings, authController, devicePostureController); + mUiModeManager = mContext.getSystemService(UiModeManager.class); mDockManager = dockManager; mProxCheck = proxCheck; @@ -212,6 +211,10 @@ public class DozeTriggers implements DozeMachine.Part { mUiEventLogger = uiEventLogger; mKeyguardStateController = keyguardStateController; } + private final DevicePostureController.Callback mDevicePostureCallback = + posture -> { + + }; @Override public void setDozeMachine(DozeMachine dozeMachine) { @@ -284,8 +287,8 @@ public class DozeTriggers implements DozeMachine.Part { boolean isTap = pulseReason == DozeLog.REASON_SENSOR_TAP; boolean isPickup = pulseReason == DozeLog.REASON_SENSOR_PICKUP; boolean isLongPress = pulseReason == DozeLog.PULSE_REASON_SENSOR_LONG_PRESS; - boolean isWakeOnPresence = pulseReason == DozeLog.REASON_SENSOR_WAKE_UP; - boolean isWakeOnReach = pulseReason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN; + boolean isWakeOnPresence = pulseReason == DozeLog.REASON_SENSOR_WAKE_UP_PRESENCE; + boolean isWakeOnReach = pulseReason == DozeLog.PULSE_REASON_SENSOR_WAKE_REACH; boolean isUdfpsLongPress = pulseReason == DozeLog.REASON_SENSOR_UDFPS_LONG_PRESS; boolean isQuickPickup = pulseReason == DozeLog.REASON_SENSOR_QUICK_PICKUP; boolean isWakeDisplayEvent = isQuickPickup || ((isWakeOnPresence || isWakeOnReach) @@ -455,7 +458,7 @@ public class DozeTriggers implements DozeMachine.Part { mWantSensors = true; mWantTouchScreenSensors = true; if (newState == DozeMachine.State.DOZE_AOD && !sWakeDisplaySensorState) { - onWakeScreen(false, newState, DozeLog.REASON_SENSOR_WAKE_UP); + onWakeScreen(false, newState, DozeLog.REASON_SENSOR_WAKE_UP_PRESENCE); } break; case DOZE_AOD_PAUSED: @@ -524,7 +527,7 @@ public class DozeTriggers implements DozeMachine.Part { // When already pulsing we're allowed to show the wallpaper directly without // requesting a new pulse. if (dozeState == DozeMachine.State.DOZE_PULSING - && reason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN) { + && reason == DozeLog.PULSE_REASON_SENSOR_WAKE_REACH) { mMachine.requestState(DozeMachine.State.DOZE_PULSING_BRIGHT); return; } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java index fbe06b02d955..374bed31eb7d 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java @@ -155,7 +155,7 @@ public class DozeUi implements DozeMachine.Part, TunerService.Tunable, public void onPulseStarted() { try { mMachine.requestState( - reason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN + reason == DozeLog.PULSE_REASON_SENSOR_WAKE_REACH ? DozeMachine.State.DOZE_PULSING_BRIGHT : DozeMachine.State.DOZE_PULSING); } catch (IllegalStateException e) { diff --git a/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeModule.java b/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeModule.java index 571b666e4573..32b7658b6e09 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeModule.java +++ b/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeModule.java @@ -43,6 +43,9 @@ import com.android.systemui.util.sensors.AsyncSensorManager; import com.android.systemui.util.wakelock.DelayedWakeLock; import com.android.systemui.util.wakelock.WakeLock; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; import java.util.Optional; import dagger.Module; @@ -94,16 +97,43 @@ public abstract class DozeModule { @Provides @BrightnessSensor - static Optional<Sensor> providesBrightnessSensor( + static Optional<Sensor>[] providesBrightnessSensors( AsyncSensorManager sensorManager, Context context, - DozeParameters dozeParameters, - DevicePostureController devicePostureController) { - return Optional.ofNullable( - DozeSensors.findSensor( - sensorManager, - context.getString(R.string.doze_brightness_sensor_type), - dozeParameters.brightnessName(devicePostureController.getDevicePosture()) - )); + DozeParameters dozeParameters) { + String[] sensorNames = dozeParameters.brightnessNames(); + if (sensorNames.length == 0 || sensorNames == null) { + // if no brightness names are specified, just use the brightness sensor type + return new Optional[]{ + Optional.ofNullable(DozeSensors.findSensor( + sensorManager, + context.getString(R.string.doze_brightness_sensor_type), + null + )) + }; + } + + // length and index of brightnessMap correspond to DevicePostureController.DevicePostureInt: + final Optional<Sensor>[] brightnessSensorMap = + new Optional[DevicePostureController.SUPPORTED_POSTURES_SIZE]; + Arrays.fill(brightnessSensorMap, Optional.empty()); + + // Map of sensorName => Sensor, so we reuse the same sensor if it's the same between + // postures + Map<String, Optional<Sensor>> nameToSensorMap = new HashMap<>(); + for (int i = 0; i < sensorNames.length; i++) { + final String sensorName = sensorNames[i]; + if (!nameToSensorMap.containsKey(sensorName)) { + nameToSensorMap.put(sensorName, + Optional.ofNullable( + DozeSensors.findSensor( + sensorManager, + context.getString(R.string.doze_brightness_sensor_type), + sensorNames[i] + ))); + } + brightnessSensorMap[i] = nameToSensorMap.get(sensorName); + } + return brightnessSensorMap; } } diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.java b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.java index 105e7f514dc4..947a39a32365 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.java +++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.java @@ -33,7 +33,7 @@ import javax.inject.Inject; /** * Class to manage simple DeviceConfig-based feature flags. * - * See {@link FeatureFlagReader} for instructions on defining and flipping flags. + * See {@link Flags} for instructions on defining new flags. */ @SysUISingleton public class FeatureFlags { @@ -87,67 +87,70 @@ public class FeatureFlags { } public boolean isNewNotifPipelineEnabled() { - return mFlagReader.isEnabled(R.bool.flag_notification_pipeline2); + return isEnabled(Flags.NEW_NOTIFICATION_PIPELINE); } public boolean isNewNotifPipelineRenderingEnabled() { - return mFlagReader.isEnabled(R.bool.flag_notification_pipeline2_rendering); + return isEnabled(Flags.NEW_NOTIFICATION_PIPELINE_RENDERING); } /** */ public boolean useNewLockscreenAnimations() { - return mFlagReader.isEnabled(R.bool.flag_lockscreen_animations); + return isEnabled(Flags.LOCKSCREEN_ANIMATIONS); } public boolean isPeopleTileEnabled() { + // TODO(b/202860494): different resource overlays have different values. return mFlagReader.isEnabled(R.bool.flag_conversations); } public boolean isMonetEnabled() { + // TODO(b/202860494): used in wallpaper picker. Always true, maybe delete. return mFlagReader.isEnabled(R.bool.flag_monet); } public boolean isPMLiteEnabled() { - return mFlagReader.isEnabled(R.bool.flag_pm_lite); + return isEnabled(Flags.POWER_MENU_LITE); } public boolean isChargingRippleEnabled() { + // TODO(b/202860494): different resource overlays have different values. return mFlagReader.isEnabled(R.bool.flag_charging_ripple); } public boolean isOngoingCallStatusBarChipEnabled() { - return mFlagReader.isEnabled(R.bool.flag_ongoing_call_status_bar_chip); + return isEnabled(Flags.ONGOING_CALL_STATUS_BAR_CHIP); } public boolean isOngoingCallInImmersiveEnabled() { - return isOngoingCallStatusBarChipEnabled() - && mFlagReader.isEnabled(R.bool.flag_ongoing_call_in_immersive); + return isOngoingCallStatusBarChipEnabled() && isEnabled(Flags.ONGOING_CALL_IN_IMMERSIVE); } public boolean isOngoingCallInImmersiveChipTapEnabled() { return isOngoingCallInImmersiveEnabled() - && mFlagReader.isEnabled(R.bool.flag_ongoing_call_in_immersive_chip_tap); + && isEnabled(Flags.ONGOING_CALL_IN_IMMERSIVE_CHIP_TAP); } public boolean isSmartspaceEnabled() { + // TODO(b/202860494): different resource overlays have different values. return mFlagReader.isEnabled(R.bool.flag_smartspace); } public boolean isSmartspaceDedupingEnabled() { - return isSmartspaceEnabled() && mFlagReader.isEnabled(R.bool.flag_smartspace_deduping); + return isSmartspaceEnabled() && isEnabled(Flags.SMARTSPACE_DEDUPING); } public boolean isNewKeyguardSwipeAnimationEnabled() { - return mFlagReader.isEnabled(R.bool.flag_new_unlock_swipe_animation); + return isEnabled(Flags.NEW_UNLOCK_SWIPE_ANIMATION); } public boolean isSmartSpaceSharedElementTransitionEnabled() { - return mFlagReader.isEnabled(R.bool.flag_smartspace_shared_element_transition); + return isEnabled(Flags.SMARTSPACE_SHARED_ELEMENT_TRANSITION_ENABLED); } /** Whether or not to use the provider model behavior for the status bar icons */ public boolean isCombinedStatusBarSignalIconsEnabled() { - return mFlagReader.isEnabled(R.bool.flag_combined_status_bar_signal_icons); + return isEnabled(Flags.COMBINED_STATUS_BAR_SIGNAL_ICONS); } /** System setting for provider model behavior */ @@ -159,7 +162,7 @@ public class FeatureFlags { * Use the new version of the user switcher */ public boolean useNewUserSwitcher() { - return mFlagReader.isEnabled(R.bool.flag_new_user_switcher); + return isEnabled(Flags.NEW_USER_SWITCHER); } /** static method for the system setting */ diff --git a/packages/SystemUI/src/com/android/systemui/flags/SystemPropertiesHelper.kt b/packages/SystemUI/src/com/android/systemui/flags/SystemPropertiesHelper.kt index 6561bd5a5323..1dc5a9f3adc5 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/SystemPropertiesHelper.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/SystemPropertiesHelper.kt @@ -26,11 +26,19 @@ import javax.inject.Inject */ @SysUISingleton open class SystemPropertiesHelper @Inject constructor() { + fun get(name: String): String { + return SystemProperties.get(name) + } + fun getBoolean(name: String, default: Boolean): Boolean { return SystemProperties.getBoolean(name, default) } + fun set(name: String, value: String) { + SystemProperties.set(name, value) + } + fun set(name: String, value: Int) { - SystemProperties.set(name, value.toString()) + set(name, value.toString()) } }
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java deleted file mode 100644 index df6aa348ed84..000000000000 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java +++ /dev/null @@ -1,599 +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.globalactions; - -import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; - -import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT; -import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_GLOBAL_ACTIONS_SHOWING; - -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.AnimatorSet; -import android.animation.ObjectAnimator; -import android.annotation.Nullable; -import android.app.IActivityManager; -import android.app.PendingIntent; -import android.app.admin.DevicePolicyManager; -import android.app.trust.TrustManager; -import android.content.Context; -import android.content.DialogInterface; -import android.content.pm.PackageManager; -import android.content.res.Resources; -import android.database.ContentObserver; -import android.graphics.drawable.Drawable; -import android.media.AudioManager; -import android.os.Handler; -import android.os.UserManager; -import android.os.Vibrator; -import android.provider.Settings; -import android.service.dreams.IDreamManager; -import android.telecom.TelecomManager; -import android.transition.AutoTransition; -import android.transition.TransitionManager; -import android.transition.TransitionSet; -import android.view.IWindowManager; -import android.view.View; -import android.view.ViewGroup; -import android.view.Window; -import android.view.WindowInsets; -import android.view.WindowManager; -import android.widget.FrameLayout; -import android.widget.TextView; - -import androidx.lifecycle.LifecycleOwner; - -import com.android.internal.R; -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.UiEventLogger; -import com.android.internal.statusbar.IStatusBarService; -import com.android.internal.view.RotationPolicy; -import com.android.internal.widget.LockPatternUtils; -import com.android.keyguard.KeyguardUpdateMonitor; -import com.android.systemui.animation.Interpolators; -import com.android.systemui.broadcast.BroadcastDispatcher; -import com.android.systemui.colorextraction.SysuiColorExtractor; -import com.android.systemui.dagger.qualifiers.Background; -import com.android.systemui.dagger.qualifiers.Main; -import com.android.systemui.model.SysUiState; -import com.android.systemui.plugins.ActivityStarter; -import com.android.systemui.plugins.GlobalActions.GlobalActionsManager; -import com.android.systemui.plugins.GlobalActionsPanelPlugin; -import com.android.systemui.statusbar.NotificationShadeWindowController; -import com.android.systemui.statusbar.phone.StatusBar; -import com.android.systemui.statusbar.policy.ConfigurationController; -import com.android.systemui.statusbar.policy.KeyguardStateController; -import com.android.systemui.telephony.TelephonyListenerManager; -import com.android.systemui.util.RingerModeTracker; -import com.android.systemui.util.leak.RotationUtils; -import com.android.systemui.util.settings.GlobalSettings; -import com.android.systemui.util.settings.SecureSettings; - -import java.util.Optional; -import java.util.concurrent.Executor; - -import javax.inject.Inject; -import javax.inject.Provider; - -/** - * Helper to show the global actions dialog. Each item is an {@link Action} that may show depending - * on whether the keyguard is showing, and whether the device is provisioned. - * This version includes wallet. - */ -public class GlobalActionsDialog extends GlobalActionsDialogLite - implements DialogInterface.OnDismissListener, - DialogInterface.OnShowListener, - ConfigurationController.ConfigurationListener, - GlobalActionsPanelPlugin.Callbacks, - LifecycleOwner { - - private static final String TAG = "GlobalActionsDialog"; - - private final LockPatternUtils mLockPatternUtils; - private final KeyguardStateController mKeyguardStateController; - private final SysUiState mSysUiState; - private final ActivityStarter mActivityStarter; - private final SysuiColorExtractor mSysuiColorExtractor; - private final IStatusBarService mStatusBarService; - private final NotificationShadeWindowController mNotificationShadeWindowController; - private GlobalActionsPanelPlugin mWalletPlugin; - - @VisibleForTesting - boolean mShowLockScreenCards = false; - - private final KeyguardStateController.Callback mKeyguardStateControllerListener = - new KeyguardStateController.Callback() { - @Override - public void onUnlockedChanged() { - if (mDialog != null) { - ActionsDialog dialog = (ActionsDialog) mDialog; - boolean unlocked = mKeyguardStateController.isUnlocked(); - if (dialog.mWalletViewController != null) { - dialog.mWalletViewController.onDeviceLockStateChanged(!unlocked); - } - - if (unlocked) { - dialog.hideLockMessage(); - } - } - } - }; - - private final ContentObserver mSettingsObserver = new ContentObserver(mMainHandler) { - @Override - public void onChange(boolean selfChange) { - onPowerMenuLockScreenSettingsChanged(); - } - }; - - /** - * @param context everything needs a context :( - */ - @Inject - public GlobalActionsDialog( - Context context, - GlobalActionsManager windowManagerFuncs, - AudioManager audioManager, - IDreamManager iDreamManager, - DevicePolicyManager devicePolicyManager, - LockPatternUtils lockPatternUtils, - BroadcastDispatcher broadcastDispatcher, - TelephonyListenerManager telephonyListenerManager, - GlobalSettings globalSettings, - SecureSettings secureSettings, - @Nullable Vibrator vibrator, - @Main Resources resources, - ConfigurationController configurationController, - ActivityStarter activityStarter, - KeyguardStateController keyguardStateController, - UserManager userManager, - TrustManager trustManager, - IActivityManager iActivityManager, - @Nullable TelecomManager telecomManager, - MetricsLogger metricsLogger, - SysuiColorExtractor colorExtractor, - IStatusBarService statusBarService, - NotificationShadeWindowController notificationShadeWindowController, - IWindowManager iWindowManager, - @Background Executor backgroundExecutor, - UiEventLogger uiEventLogger, - RingerModeTracker ringerModeTracker, - SysUiState sysUiState, - @Main Handler handler, - PackageManager packageManager, - Optional<StatusBar> statusBarOptional, - KeyguardUpdateMonitor keyguardUpdateMonitor) { - - super(context, - windowManagerFuncs, - audioManager, - iDreamManager, - devicePolicyManager, - lockPatternUtils, - broadcastDispatcher, - telephonyListenerManager, - globalSettings, - secureSettings, - vibrator, - resources, - configurationController, - keyguardStateController, - userManager, - trustManager, - iActivityManager, - telecomManager, - metricsLogger, - colorExtractor, - statusBarService, - notificationShadeWindowController, - iWindowManager, - backgroundExecutor, - uiEventLogger, - ringerModeTracker, - sysUiState, - handler, - packageManager, - statusBarOptional, - keyguardUpdateMonitor); - - mLockPatternUtils = lockPatternUtils; - mKeyguardStateController = keyguardStateController; - mSysuiColorExtractor = colorExtractor; - mStatusBarService = statusBarService; - mNotificationShadeWindowController = notificationShadeWindowController; - mSysUiState = sysUiState; - mActivityStarter = activityStarter; - - mKeyguardStateController.addCallback(mKeyguardStateControllerListener); - - // Listen for changes to show pay on the power menu while locked - onPowerMenuLockScreenSettingsChanged(); - mGlobalSettings.registerContentObserver( - Settings.Secure.getUriFor(Settings.Secure.POWER_MENU_LOCKED_SHOW_CONTENT), - false /* notifyForDescendants */, - mSettingsObserver); - } - - @Override - public void destroy() { - super.destroy(); - mKeyguardStateController.removeCallback(mKeyguardStateControllerListener); - mGlobalSettings.unregisterContentObserver(mSettingsObserver); - } - - /** - * Show the global actions dialog (creating if necessary) - * - * @param keyguardShowing True if keyguard is showing - */ - public void showOrHideDialog(boolean keyguardShowing, boolean isDeviceProvisioned, - GlobalActionsPanelPlugin walletPlugin) { - mWalletPlugin = walletPlugin; - super.showOrHideDialog(keyguardShowing, isDeviceProvisioned); - } - - /** - * Returns the maximum number of power menu items to show based on which GlobalActions - * layout is being used. - */ - @VisibleForTesting - @Override - protected int getMaxShownPowerItems() { - return getContext().getResources().getInteger( - com.android.systemui.R.integer.power_menu_max_columns); - } - - /** - * Create the global actions dialog. - * - * @return A new dialog. - */ - @Override - protected ActionsDialogLite createDialog() { - initDialogItems(); - - ActionsDialog dialog = new ActionsDialog(getContext(), mAdapter, mOverflowAdapter, - this::getWalletViewController, mSysuiColorExtractor, - mStatusBarService, mNotificationShadeWindowController, - mSysUiState, this::onRotate, isKeyguardShowing(), mPowerAdapter, getEventLogger(), - getStatusBar(), getKeyguardUpdateMonitor(), mLockPatternUtils); - - if (shouldShowLockMessage(dialog)) { - dialog.showLockMessage(); - } - dialog.setCanceledOnTouchOutside(false); // Handled by the custom class. - dialog.setOnDismissListener(this); - dialog.setOnShowListener(this); - - return dialog; - } - - @Nullable - private GlobalActionsPanelPlugin.PanelViewController getWalletViewController() { - if (mWalletPlugin == null) { - return null; - } - return mWalletPlugin.onPanelShown(this, !mKeyguardStateController.isUnlocked()); - } - - /** - * Implements {@link GlobalActionsPanelPlugin.Callbacks#dismissGlobalActionsMenu()}, which is - * called when the quick access wallet requests that an intent be started (with lock screen - * shown first if needed). - */ - @Override - public void startPendingIntentDismissingKeyguard(PendingIntent pendingIntent) { - mActivityStarter.startPendingIntentDismissingKeyguard(pendingIntent); - } - - @Override - protected int getEmergencyTextColor(Context context) { - return context.getResources().getColor( - com.android.systemui.R.color.global_actions_emergency_text); - } - - @Override - protected int getEmergencyIconColor(Context context) { - return getContext().getResources().getColor( - com.android.systemui.R.color.global_actions_emergency_text); - } - - @Override - protected int getEmergencyBackgroundColor(Context context) { - return getContext().getResources().getColor( - com.android.systemui.R.color.global_actions_emergency_background); - } - - @Override - protected int getGridItemLayoutResource() { - return com.android.systemui.R.layout.global_actions_grid_item_v2; - } - - @VisibleForTesting - static class ActionsDialog extends ActionsDialogLite { - - private final Provider<GlobalActionsPanelPlugin.PanelViewController> mWalletFactory; - @Nullable private GlobalActionsPanelPlugin.PanelViewController mWalletViewController; - private ResetOrientationData mResetOrientationData; - @VisibleForTesting ViewGroup mLockMessageContainer; - private TextView mLockMessage; - - ActionsDialog(Context context, MyAdapter adapter, MyOverflowAdapter overflowAdapter, - Provider<GlobalActionsPanelPlugin.PanelViewController> walletFactory, - SysuiColorExtractor sysuiColorExtractor, IStatusBarService statusBarService, - NotificationShadeWindowController notificationShadeWindowController, - SysUiState sysuiState, Runnable onRotateCallback, boolean keyguardShowing, - MyPowerOptionsAdapter powerAdapter, UiEventLogger uiEventLogger, - Optional<StatusBar> statusBarOptional, KeyguardUpdateMonitor keyguardUpdateMonitor, - LockPatternUtils lockPatternUtils) { - super(context, com.android.systemui.R.style.Theme_SystemUI_Dialog_GlobalActions, - adapter, overflowAdapter, sysuiColorExtractor, statusBarService, - notificationShadeWindowController, sysuiState, onRotateCallback, - keyguardShowing, powerAdapter, uiEventLogger, statusBarOptional, - keyguardUpdateMonitor, lockPatternUtils); - mWalletFactory = walletFactory; - - // Update window attributes - Window window = getWindow(); - window.getAttributes().systemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - | View.SYSTEM_UI_FLAG_LAYOUT_STABLE - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION; - window.setLayout(MATCH_PARENT, MATCH_PARENT); - window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND); - window.addFlags( - WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN - | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL - | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR - | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED - | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH - | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED); - setTitle(R.string.global_actions); - initializeLayout(); - } - - private boolean isWalletViewAvailable() { - return mWalletViewController != null && mWalletViewController.getPanelContent() != null; - } - - private void initializeWalletView() { - if (mWalletFactory == null) { - return; - } - mWalletViewController = mWalletFactory.get(); - if (!isWalletViewAvailable()) { - return; - } - - boolean isLandscapeWalletViewShown = mContext.getResources().getBoolean( - com.android.systemui.R.bool.global_actions_show_landscape_wallet_view); - - int rotation = RotationUtils.getRotation(mContext); - boolean rotationLocked = RotationPolicy.isRotationLocked(mContext); - if (rotation != RotationUtils.ROTATION_NONE) { - if (rotationLocked) { - if (mResetOrientationData == null) { - mResetOrientationData = new ResetOrientationData(); - mResetOrientationData.locked = true; - mResetOrientationData.rotation = rotation; - } - - // Unlock rotation, so user can choose to rotate to portrait to see the panel. - // This call is posted so that the rotation does not change until post-layout, - // otherwise onConfigurationChanged() may not get invoked. - mGlobalActionsLayout.post(() -> - RotationPolicy.setRotationLockAtAngle( - mContext, false, RotationUtils.ROTATION_NONE)); - - if (!isLandscapeWalletViewShown) { - return; - } - } - } else { - if (!rotationLocked) { - if (mResetOrientationData == null) { - mResetOrientationData = new ResetOrientationData(); - mResetOrientationData.locked = false; - } - } - - boolean shouldLockRotation = !isLandscapeWalletViewShown; - if (rotationLocked != shouldLockRotation) { - // Locks the screen to portrait if the landscape / seascape orientation does not - // show the wallet view, so the user doesn't accidentally hide the panel. - // This call is posted so that the rotation does not change until post-layout, - // otherwise onConfigurationChanged() may not get invoked. - mGlobalActionsLayout.post(() -> - RotationPolicy.setRotationLockAtAngle( - mContext, shouldLockRotation, RotationUtils.ROTATION_NONE)); - } - } - - // Disable rotation suggestions, if enabled - setRotationSuggestionsEnabled(false); - - FrameLayout panelContainer = - findViewById(com.android.systemui.R.id.global_actions_wallet); - FrameLayout.LayoutParams panelParams = - new FrameLayout.LayoutParams( - FrameLayout.LayoutParams.MATCH_PARENT, - FrameLayout.LayoutParams.MATCH_PARENT); - panelParams.topMargin = mContext.getResources().getDimensionPixelSize( - com.android.systemui.R.dimen.global_actions_wallet_top_margin); - View walletView = mWalletViewController.getPanelContent(); - panelContainer.addView(walletView, panelParams); - // Smooth transitions when wallet is resized, which can happen when a card is added - ViewGroup root = findViewById(com.android.systemui.R.id.global_actions_grid_root); - if (root != null) { - walletView.addOnLayoutChangeListener((v, l, t, r, b, ol, ot, or, ob) -> { - int oldHeight = ob - ot; - int newHeight = b - t; - if (oldHeight > 0 && oldHeight != newHeight) { - TransitionSet transition = new AutoTransition() - .setDuration(250) - .setOrdering(TransitionSet.ORDERING_TOGETHER); - TransitionManager.beginDelayedTransition(root, transition); - } - }); - } - } - - @Override - protected int getLayoutResource() { - return com.android.systemui.R.layout.global_actions_grid_v2; - } - - @Override - protected void initializeLayout() { - super.initializeLayout(); - mLockMessageContainer = requireViewById( - com.android.systemui.R.id.global_actions_lock_message_container); - mLockMessage = requireViewById(com.android.systemui.R.id.global_actions_lock_message); - initializeWalletView(); - getWindow().setBackgroundDrawable(mBackgroundDrawable); - } - - @Override - protected void showDialog() { - mShowing = true; - mNotificationShadeWindowController.setRequestTopUi(true, TAG); - mSysUiState.setFlag(SYSUI_STATE_GLOBAL_ACTIONS_SHOWING, true) - .commitUpdate(mContext.getDisplayId()); - - ViewGroup root = (ViewGroup) mGlobalActionsLayout.getRootView(); - root.setOnApplyWindowInsetsListener((v, windowInsets) -> { - root.setPadding(windowInsets.getStableInsetLeft(), - windowInsets.getStableInsetTop(), - windowInsets.getStableInsetRight(), - windowInsets.getStableInsetBottom()); - return WindowInsets.CONSUMED; - }); - - mBackgroundDrawable.setAlpha(0); - float xOffset = mGlobalActionsLayout.getAnimationOffsetX(); - ObjectAnimator alphaAnimator = - ObjectAnimator.ofFloat(mContainer, "alpha", 0f, 1f); - alphaAnimator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN); - alphaAnimator.setDuration(183); - alphaAnimator.addUpdateListener((animation) -> { - float animatedValue = animation.getAnimatedFraction(); - int alpha = (int) (animatedValue * mScrimAlpha * 255); - mBackgroundDrawable.setAlpha(alpha); - }); - - ObjectAnimator xAnimator = - ObjectAnimator.ofFloat(mContainer, "translationX", xOffset, 0f); - xAnimator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN); - xAnimator.setDuration(350); - - AnimatorSet animatorSet = new AnimatorSet(); - animatorSet.playTogether(alphaAnimator, xAnimator); - animatorSet.start(); - } - - @Override - protected void dismissInternal() { - super.dismissInternal(); - } - - @Override - protected void completeDismiss() { - dismissWallet(); - resetOrientation(); - super.completeDismiss(); - } - - private void dismissWallet() { - if (mWalletViewController != null) { - mWalletViewController.onDismissed(); - // The wallet controller should not be re-used after being dismissed. - mWalletViewController = null; - } - } - - private void resetOrientation() { - if (mResetOrientationData != null) { - RotationPolicy.setRotationLockAtAngle(mContext, mResetOrientationData.locked, - mResetOrientationData.rotation); - } - setRotationSuggestionsEnabled(true); - } - - @Override - public void refreshDialog() { - // ensure dropdown menus are dismissed before re-initializing the dialog - dismissWallet(); - super.refreshDialog(); - } - - void hideLockMessage() { - if (mLockMessageContainer.getVisibility() == View.VISIBLE) { - mLockMessageContainer.animate().alpha(0).setDuration(150).setListener( - new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - mLockMessageContainer.setVisibility(View.GONE); - } - }).start(); - } - } - - void showLockMessage() { - Drawable lockIcon = mContext.getDrawable(com.android.internal.R.drawable.ic_lock); - lockIcon.setTint(mContext.getColor(com.android.systemui.R.color.control_primary_text)); - mLockMessage.setCompoundDrawablesWithIntrinsicBounds(null, lockIcon, null, null); - mLockMessageContainer.setVisibility(View.VISIBLE); - } - - private static class ResetOrientationData { - public boolean locked; - public int rotation; - } - } - - /** - * Determines whether or not debug mode has been activated for the Global Actions Panel. - */ - private static boolean isPanelDebugModeEnabled(Context context) { - return Settings.Secure.getInt(context.getContentResolver(), - Settings.Secure.GLOBAL_ACTIONS_PANEL_DEBUG_ENABLED, 0) == 1; - } - - /** - * Determines whether or not the Global Actions menu should be forced to use the newer - * grid-style layout. - */ - private static boolean isForceGridEnabled(Context context) { - return isPanelDebugModeEnabled(context); - } - - private boolean shouldShowLockMessage(ActionsDialog dialog) { - return isWalletAvailableAfterUnlock(dialog); - } - - // Temporary while we move items out of the power menu - private boolean isWalletAvailableAfterUnlock(ActionsDialog dialog) { - boolean isLockedAfterBoot = mLockPatternUtils.getStrongAuthForUser(getCurrentUser().id) - == STRONG_AUTH_REQUIRED_AFTER_BOOT; - return !mKeyguardStateController.isUnlocked() - && (!mShowLockScreenCards || isLockedAfterBoot) - && dialog.isWalletViewAvailable(); - } - - private void onPowerMenuLockScreenSettingsChanged() { - mShowLockScreenCards = mSecureSettings.getInt( - Settings.Secure.POWER_MENU_LOCKED_SHOW_CONTENT, 0) != 0; - } -} diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java index a51ec54ebcce..729730cdf6f1 100644 --- a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java +++ b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java @@ -66,6 +66,13 @@ public class ImageWallpaperRenderer implements GLWallpaperRenderer { mOnBitmapUpdated = c; } + /** + * @hide + */ + public void use(Consumer<Bitmap> c) { + mTexture.use(c); + } + @Override public boolean isWcgContent() { return mTexture.isWcgContent(); diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java index a5dd6a11c388..01a0f271e5b9 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java @@ -102,7 +102,7 @@ public class KeyguardService extends Service { "persist.wm.enable_remote_keyguard_animation"; private static final int sEnableRemoteKeyguardAnimation = - SystemProperties.getInt(ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY, 0); + SystemProperties.getInt(ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY, 1); /** * @see #ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY @@ -358,7 +358,7 @@ public class KeyguardService extends Service { if (transit == TRANSIT_OLD_KEYGUARD_OCCLUDE) { mBinder.setOccluded(true /* isOccluded */, true /* animate */); } else if (transit == TRANSIT_OLD_KEYGUARD_UNOCCLUDE) { - mBinder.setOccluded(false /* isOccluded */, true /* animate */); + mBinder.setOccluded(false /* isOccluded */, false /* animate */); } // TODO(bc-unlock): Implement (un)occlude animation. finishedCallback.onAnimationFinished(); diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt index e51b60213446..2cc564bf8452 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt @@ -62,7 +62,7 @@ const val SURFACE_BEHIND_SCALE_PIVOT_Y = 0.66f * The dismiss amount is the inverse of the notification panel expansion, which decreases as the * lock screen is swiped away. */ -const val DISMISS_AMOUNT_SHOW_SURFACE_THRESHOLD = 0.1f +const val DISMISS_AMOUNT_SHOW_SURFACE_THRESHOLD = 0.25f /** * Dismiss amount at which to complete the keyguard exit animation and hide the keyguard. @@ -70,7 +70,7 @@ const val DISMISS_AMOUNT_SHOW_SURFACE_THRESHOLD = 0.1f * The dismiss amount is the inverse of the notification panel expansion, which decreases as the * lock screen is swiped away. */ -const val DISMISS_AMOUNT_EXIT_KEYGUARD_THRESHOLD = 0.3f +const val DISMISS_AMOUNT_EXIT_KEYGUARD_THRESHOLD = 0.4f /** * Initiates, controls, and ends the keyguard unlock animation. diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 784346e59721..19ee50ac99cd 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -119,12 +119,15 @@ import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.UserSwitcherController; +import com.android.systemui.unfold.UnfoldLightRevealOverlayAnimation; +import com.android.systemui.unfold.config.UnfoldTransitionConfig; import com.android.systemui.util.DeviceConfigProxy; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicInteger; import dagger.Lazy; @@ -808,6 +811,10 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable, private DeviceConfigProxy mDeviceConfig; private DozeParameters mDozeParameters; + private final UnfoldTransitionConfig mUnfoldTransitionConfig; + private final Lazy<UnfoldLightRevealOverlayAnimation> mUnfoldLightRevealAnimation; + private final AtomicInteger mPendingDrawnTasks = new AtomicInteger(); + private final KeyguardStateController mKeyguardStateController; private final Lazy<KeyguardUnlockAnimationController> mKeyguardUnlockAnimationControllerLazy; private boolean mWallpaperSupportsAmbientMode; @@ -830,6 +837,8 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable, NavigationModeController navigationModeController, KeyguardDisplayManager keyguardDisplayManager, DozeParameters dozeParameters, + UnfoldTransitionConfig unfoldTransitionConfig, + Lazy<UnfoldLightRevealOverlayAnimation> unfoldLightRevealOverlayAnimation, SysuiStatusBarStateController statusBarStateController, KeyguardStateController keyguardStateController, Lazy<KeyguardUnlockAnimationController> keyguardUnlockAnimationControllerLazy, @@ -863,6 +872,8 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable, mInGestureNavigationMode = QuickStepContract.isGesturalMode(mode); })); mDozeParameters = dozeParameters; + mUnfoldTransitionConfig = unfoldTransitionConfig; + mUnfoldLightRevealAnimation = unfoldLightRevealOverlayAnimation; mStatusBarStateController = statusBarStateController; statusBarStateController.addCallback(this); @@ -2545,6 +2556,24 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable, Trace.beginSection("KeyguardViewMediator#handleNotifyScreenTurningOn"); synchronized (KeyguardViewMediator.this) { if (DEBUG) Log.d(TAG, "handleNotifyScreenTurningOn"); + + if (mUnfoldTransitionConfig.isEnabled()) { + mPendingDrawnTasks.set(2); // unfold overlay and keyguard drawn + + mUnfoldLightRevealAnimation.get() + .onScreenTurningOn(() -> { + if (mPendingDrawnTasks.decrementAndGet() == 0) { + try { + callback.onDrawn(); + } catch (RemoteException e) { + Slog.w(TAG, "Exception calling onDrawn():", e); + } + } + }); + } else { + mPendingDrawnTasks.set(1); // only keyguard drawn + } + mKeyguardViewControllerLazy.get().onScreenTurningOn(); if (callback != null) { if (mWakeAndUnlocking) { @@ -2575,10 +2604,12 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable, private void notifyDrawn(final IKeyguardDrawnCallback callback) { Trace.beginSection("KeyguardViewMediator#notifyDrawn"); - try { - callback.onDrawn(); - } catch (RemoteException e) { - Slog.w(TAG, "Exception calling onDrawn():", e); + if (mPendingDrawnTasks.decrementAndGet() == 0) { + try { + callback.onDrawn(); + } catch (RemoteException e) { + Slog.w(TAG, "Exception calling onDrawn():", e); + } } Trace.endSection(); } @@ -2731,6 +2762,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable, pw.print(" mHideAnimationRun: "); pw.println(mHideAnimationRun); pw.print(" mPendingReset: "); pw.println(mPendingReset); pw.print(" mPendingLock: "); pw.println(mPendingLock); + pw.print(" mPendingDrawnTasks: "); pw.println(mPendingDrawnTasks.get()); pw.print(" mWakeAndUnlocking: "); pw.println(mWakeAndUnlocking); pw.print(" mDrawnCallback: "); pw.println(mDrawnCallback); } 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 0730b11e5a01..9b0d69b38374 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java @@ -49,6 +49,8 @@ import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.UserSwitcherController; +import com.android.systemui.unfold.UnfoldLightRevealOverlayAnimation; +import com.android.systemui.unfold.config.UnfoldTransitionConfig; import com.android.systemui.util.DeviceConfigProxy; import com.android.systemui.util.sensors.AsyncSensorManager; @@ -90,6 +92,8 @@ public class KeyguardModule { NavigationModeController navigationModeController, KeyguardDisplayManager keyguardDisplayManager, DozeParameters dozeParameters, + UnfoldTransitionConfig unfoldTransitionConfig, + Lazy<UnfoldLightRevealOverlayAnimation> unfoldLightRevealOverlayAnimation, SysuiStatusBarStateController statusBarStateController, KeyguardStateController keyguardStateController, Lazy<KeyguardUnlockAnimationController> keyguardUnlockAnimationController, @@ -112,6 +116,8 @@ public class KeyguardModule { navigationModeController, keyguardDisplayManager, dozeParameters, + unfoldTransitionConfig, + unfoldLightRevealOverlayAnimation, statusBarStateController, keyguardStateController, keyguardUnlockAnimationController, diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java index 125b87b31e63..113ba59cd514 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java @@ -16,14 +16,10 @@ package com.android.systemui.media.dialog; -import static android.text.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE; - import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.drawable.Drawable; -import android.text.SpannableString; import android.text.TextUtils; -import android.text.style.ForegroundColorSpan; import android.util.Log; import android.view.View; import android.view.ViewGroup; @@ -99,23 +95,6 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter { return mController.getMediaDevices().size(); } - @Override - CharSequence getItemTitle(MediaDevice device) { - if (device.getDeviceType() == MediaDevice.MediaDeviceType.TYPE_BLUETOOTH_DEVICE - && !device.isConnected()) { - final CharSequence deviceName = device.getName(); - // Append status to title only for the disconnected Bluetooth device. - final SpannableString spannableTitle = new SpannableString( - mContext.getString(R.string.media_output_dialog_disconnected, deviceName)); - spannableTitle.setSpan(new ForegroundColorSpan( - Utils.getColorAttrDefaultColor(mContext, android.R.attr.textColorSecondary)), - deviceName.length(), - spannableTitle.length(), SPAN_EXCLUSIVE_EXCLUSIVE); - return spannableTitle; - } - return super.getItemTitle(device); - } - class MediaDeviceViewHolder extends MediaDeviceBaseViewHolder { MediaDeviceViewHolder(View view) { @@ -166,6 +145,14 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter { false /* showProgressBar */, false /* showSubtitle */); initSeekbar(device); mCurrentActivePosition = position; + } else if ( + device.getDeviceType() == MediaDevice.MediaDeviceType.TYPE_BLUETOOTH_DEVICE + && !device.isConnected()) { + setTwoLineLayout(device, false /* bFocused */, + false /* showSeekBar */, false /* showProgressBar */, + true /* showSubtitle */); + mSubTitleText.setText(R.string.media_output_dialog_disconnected); + mContainerLayout.setOnClickListener(v -> onItemClick(v, device)); } else { setSingleLineLayout(getItemTitle(device), false /* bFocused */); mContainerLayout.setOnClickListener(v -> onItemClick(v, device)); @@ -175,7 +162,6 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter { @Override void onBind(int customizedItem, boolean topMargin, boolean bottomMargin) { - super.onBind(customizedItem, topMargin, bottomMargin); if (customizedItem == CUSTOMIZED_ITEM_PAIR_NEW) { mCheckBox.setVisibility(View.GONE); mAddIcon.setVisibility(View.GONE); diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java index 1ffc2c4c35ba..868193b44704 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java @@ -153,9 +153,7 @@ public abstract class MediaOutputBaseAdapter extends }); } - void onBind(int customizedItem, boolean topMargin, boolean bottomMargin) { - // TODO (b/201718621): clean up method after adjustment - } + abstract void onBind(int customizedItem, boolean topMargin, boolean bottomMargin); void setSingleLineLayout(CharSequence title, boolean bFocused) { mTwoLineLayout.setVisibility(View.GONE); diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupAdapter.java index 11d76dba1423..a201c071bbbe 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupAdapter.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupAdapter.java @@ -126,7 +126,6 @@ public class MediaOutputGroupAdapter extends MediaOutputBaseAdapter { @Override void onBind(int customizedItem, boolean topMargin, boolean bottomMargin) { - super.onBind(customizedItem, topMargin, bottomMargin); if (customizedItem == CUSTOMIZED_ITEM_GROUP) { setTwoLineLayout(mContext.getText(R.string.media_output_dialog_group), true /* bFocused */, true /* showSeekBar */, false /* showProgressBar */, diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java index 8576a280c560..7809b5fb83ce 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java @@ -93,7 +93,6 @@ import android.util.Log; import android.view.Display; import android.view.Gravity; import android.view.HapticFeedbackConstants; -import android.view.IWindowManager; import android.view.InsetsState.InternalInsetsType; import android.view.InsetsVisibilities; import android.view.KeyEvent; @@ -118,20 +117,17 @@ import com.android.internal.logging.UiEventLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.util.LatencyTracker; import com.android.internal.view.AppearanceRegion; -import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.accessibility.AccessibilityButtonModeObserver; import com.android.systemui.accessibility.SystemActions; import com.android.systemui.assist.AssistManager; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dagger.qualifiers.Main; -import com.android.systemui.dump.DumpManager; import com.android.systemui.model.SysUiState; import com.android.systemui.navigationbar.buttons.ButtonDispatcher; import com.android.systemui.navigationbar.buttons.KeyButtonView; import com.android.systemui.navigationbar.buttons.RotationContextButton; import com.android.systemui.navigationbar.gestural.QuickswitchOrientedNavHandle; -import com.android.systemui.plugins.DarkIconDispatcher; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.recents.OverviewProxyService; import com.android.systemui.recents.Recents; @@ -151,8 +147,6 @@ import com.android.systemui.statusbar.phone.BarTransitions; import com.android.systemui.statusbar.phone.LightBarController; import com.android.systemui.statusbar.phone.ShadeController; import com.android.systemui.statusbar.phone.StatusBar; -import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper; -import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.wm.shell.legacysplitscreen.LegacySplitScreen; import com.android.wm.shell.pip.Pip; @@ -162,6 +156,8 @@ import java.util.Locale; import java.util.Optional; import java.util.function.Consumer; +import javax.inject.Inject; + import dagger.Lazy; /** @@ -243,7 +239,13 @@ public class NavigationBar implements View.OnAttachStateChangeListener, private boolean mTransientShown; private int mNavBarMode = NAV_BAR_MODE_3BUTTON; private LightBarController mLightBarController; + private final LightBarController mMainLightBarController; + private final LightBarController.Factory mLightBarControllerFactory; private AutoHideController mAutoHideController; + private final AutoHideController mMainAutoHideController; + private final AutoHideController.Factory mAutoHideControllerFactory; + private final Optional<TelecomManager> mTelecomManagerOptional; + private final InputMethodManager mInputMethodManager; @VisibleForTesting public int mDisplayId; @@ -267,6 +269,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener, private ViewTreeObserver.OnGlobalLayoutListener mOrientationHandleGlobalLayoutListener; private boolean mShowOrientedHandleForImmersiveMode; + @com.android.internal.annotations.VisibleForTesting public enum NavBarActionEvent implements UiEventLogger.UiEventEnum { @@ -478,11 +481,10 @@ public class NavigationBar implements View.OnAttachStateChangeListener, } }; - public NavigationBar(Context context, + private NavigationBar(Context context, WindowManager windowManager, Lazy<AssistManager> assistManagerLazy, AccessibilityManager accessibilityManager, - AccessibilityManagerWrapper accessibilityManagerWrapper, DeviceProvisionedController deviceProvisionedController, MetricsLogger metricsLogger, OverviewProxyService overviewProxyService, @@ -504,7 +506,13 @@ public class NavigationBar implements View.OnAttachStateChangeListener, NavigationBarOverlayController navbarOverlayController, UiEventLogger uiEventLogger, NavigationBarA11yHelper navigationBarA11yHelper, - UserTracker userTracker) { + UserTracker userTracker, + LightBarController mainLightBarController, + LightBarController.Factory lightBarControllerFactory, + AutoHideController mainAutoHideController, + AutoHideController.Factory autoHideControllerFactory, + Optional<TelecomManager> telecomManagerOptional, + InputMethodManager inputMethodManager) { mContext = context; mWindowManager = windowManager; mAccessibilityManager = accessibilityManager; @@ -531,6 +539,12 @@ public class NavigationBar implements View.OnAttachStateChangeListener, mNavigationBarA11yHelper = navigationBarA11yHelper; mUserTracker = userTracker; mNotificationShadeDepthController = notificationShadeDepthController; + mMainLightBarController = mainLightBarController; + mLightBarControllerFactory = lightBarControllerFactory; + mMainAutoHideController = mainAutoHideController; + mAutoHideControllerFactory = autoHideControllerFactory; + mTelecomManagerOptional = telecomManagerOptional; + mInputMethodManager = inputMethodManager; mNavBarMode = mNavigationModeController.addListener(this); } @@ -548,7 +562,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener, mNavigationBarView = barView.findViewById(R.id.navigation_bar_view); if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + barView); - mContext.getSystemService(WindowManager.class).addView(mFrame, + mWindowManager.addView(mFrame, getBarLayoutParams(mContext.getResources().getConfiguration().windowConfiguration .getRotation())); mDisplayId = mContext.getDisplayId(); @@ -606,8 +620,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener, public void destroyView() { setAutoHideController(/* autoHideController */ null); mCommandQueue.removeCallback(this); - mContext.getSystemService(WindowManager.class).removeViewImmediate( - mNavigationBarView.getRootView()); + mWindowManager.removeViewImmediate(mNavigationBarView.getRootView()); mNavigationModeController.removeListener(this); mNavigationBarA11yHelper.removeA11yEventListener(mAccessibilityListener); @@ -673,22 +686,16 @@ public class NavigationBar implements View.OnAttachStateChangeListener, // before notifications creation. We cannot directly use getLightBarController() // from NavigationBarFragment directly. LightBarController lightBarController = mIsOnDefaultDisplay - ? Dependency.get(LightBarController.class) - : new LightBarController(mContext, - Dependency.get(DarkIconDispatcher.class), - Dependency.get(BatteryController.class), - Dependency.get(NavigationModeController.class), - Dependency.get(DumpManager.class)); + ? mMainLightBarController : mLightBarControllerFactory.create(mContext); setLightBarController(lightBarController); // TODO(b/118592525): to support multi-display, we start to add something which is // per-display, while others may be global. I think it's time to // add a new class maybe named DisplayDependency to solve // per-display Dependency problem. + // Alternative: this is a good case for a Dagger subcomponent. Same with LightBarController. AutoHideController autoHideController = mIsOnDefaultDisplay - ? Dependency.get(AutoHideController.class) - : new AutoHideController(mContext, mHandler, - Dependency.get(IWindowManager.class)); + ? mMainAutoHideController : mAutoHideControllerFactory.create(mContext); setAutoHideController(autoHideController); restoreAppearanceAndTransientState(); } @@ -1183,9 +1190,8 @@ public class NavigationBar implements View.OnAttachStateChangeListener, switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mHomeBlockedThisTouch = false; - TelecomManager telecomManager = - mContext.getSystemService(TelecomManager.class); - if (telecomManager != null && telecomManager.isRinging()) { + if (mTelecomManagerOptional.isPresent() + && mTelecomManagerOptional.get().isRinging()) { if (statusBarOptional.map(StatusBar::isKeyguardShowing).orElse(false)) { Log.i(TAG, "Ignoring HOME; there's a ringing incoming call. " + "No heads up"); @@ -1267,7 +1273,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener, } private void onImeSwitcherClick(View v) { - mContext.getSystemService(InputMethodManager.class).showInputMethodPickerFromSystem( + mInputMethodManager.showInputMethodPickerFromSystem( true /* showAuxiliarySubtypes */, mDisplayId); }; @@ -1702,4 +1708,121 @@ public class NavigationBar implements View.OnAttachStateChangeListener, int getNavigationIconHints() { return mNavigationIconHints; } -} + + /** + * Injectable factory for construction a {@link NavigationBar}. + */ + public static class Factory { + private final Lazy<AssistManager> mAssistManagerLazy; + private final AccessibilityManager mAccessibilityManager; + private final DeviceProvisionedController mDeviceProvisionedController; + private final MetricsLogger mMetricsLogger; + private final OverviewProxyService mOverviewProxyService; + private final NavigationModeController mNavigationModeController; + private final AccessibilityButtonModeObserver mAccessibilityButtonModeObserver; + private final StatusBarStateController mStatusBarStateController; + private final SysUiState mSysUiFlagsContainer; + private final BroadcastDispatcher mBroadcastDispatcher; + private final CommandQueue mCommandQueue; + private final Optional<Pip> mPipOptional; + private final Optional<LegacySplitScreen> mSplitScreenOptional; + private final Optional<Recents> mRecentsOptional; + private final Lazy<Optional<StatusBar>> mStatusBarOptionalLazy; + private final ShadeController mShadeController; + private final NotificationRemoteInputManager mNotificationRemoteInputManager; + private final NotificationShadeDepthController mNotificationShadeDepthController; + private final SystemActions mSystemActions; + private final Handler mMainHandler; + private final NavigationBarOverlayController mNavbarOverlayController; + private final UiEventLogger mUiEventLogger; + private final NavigationBarA11yHelper mNavigationBarA11yHelper; + private final UserTracker mUserTracker; + private final LightBarController mMainLightBarController; + private final LightBarController.Factory mLightBarControllerFactory; + private final AutoHideController mMainAutoHideController; + private final AutoHideController.Factory mAutoHideControllerFactory; + private final Optional<TelecomManager> mTelecomManagerOptional; + private final InputMethodManager mInputMethodManager; + + @Inject + public Factory( + Lazy<AssistManager> assistManagerLazy, + AccessibilityManager accessibilityManager, + DeviceProvisionedController deviceProvisionedController, + MetricsLogger metricsLogger, + OverviewProxyService overviewProxyService, + NavigationModeController navigationModeController, + AccessibilityButtonModeObserver accessibilityButtonModeObserver, + StatusBarStateController statusBarStateController, + SysUiState sysUiFlagsContainer, + BroadcastDispatcher broadcastDispatcher, + CommandQueue commandQueue, + Optional<Pip> pipOptional, + Optional<LegacySplitScreen> splitScreenOptional, + Optional<Recents> recentsOptional, + Lazy<Optional<StatusBar>> statusBarOptionalLazy, + ShadeController shadeController, + NotificationRemoteInputManager notificationRemoteInputManager, + NotificationShadeDepthController notificationShadeDepthController, + SystemActions systemActions, + @Main Handler mainHandler, + NavigationBarOverlayController navbarOverlayController, + UiEventLogger uiEventLogger, + NavigationBarA11yHelper navigationBarA11yHelper, + UserTracker userTracker, + LightBarController mainLightBarController, + LightBarController.Factory lightBarControllerFactory, + AutoHideController mainAutoHideController, + AutoHideController.Factory autoHideControllerFactory, + Optional<TelecomManager> telecomManagerOptional, + InputMethodManager inputMethodManager) { + mAssistManagerLazy = assistManagerLazy; + mAccessibilityManager = accessibilityManager; + mDeviceProvisionedController = deviceProvisionedController; + mMetricsLogger = metricsLogger; + mOverviewProxyService = overviewProxyService; + mNavigationModeController = navigationModeController; + mAccessibilityButtonModeObserver = accessibilityButtonModeObserver; + mStatusBarStateController = statusBarStateController; + mSysUiFlagsContainer = sysUiFlagsContainer; + mBroadcastDispatcher = broadcastDispatcher; + mCommandQueue = commandQueue; + mPipOptional = pipOptional; + mSplitScreenOptional = splitScreenOptional; + mRecentsOptional = recentsOptional; + mStatusBarOptionalLazy = statusBarOptionalLazy; + mShadeController = shadeController; + mNotificationRemoteInputManager = notificationRemoteInputManager; + mNotificationShadeDepthController = notificationShadeDepthController; + mSystemActions = systemActions; + mMainHandler = mainHandler; + mNavbarOverlayController = navbarOverlayController; + mUiEventLogger = uiEventLogger; + mNavigationBarA11yHelper = navigationBarA11yHelper; + mUserTracker = userTracker; + mMainLightBarController = mainLightBarController; + mLightBarControllerFactory = lightBarControllerFactory; + mMainAutoHideController = mainAutoHideController; + mAutoHideControllerFactory = autoHideControllerFactory; + mTelecomManagerOptional = telecomManagerOptional; + mInputMethodManager = inputMethodManager; + } + + /** Construct a {@link NavigationBar} */ + public NavigationBar create(Context context) { + final WindowManager wm = context.getSystemService(WindowManager.class); + return new NavigationBar(context, wm, mAssistManagerLazy, + mAccessibilityManager, mDeviceProvisionedController, mMetricsLogger, + mOverviewProxyService, mNavigationModeController, + mAccessibilityButtonModeObserver, mStatusBarStateController, + mSysUiFlagsContainer, mBroadcastDispatcher, mCommandQueue, mPipOptional, + mSplitScreenOptional, mRecentsOptional, mStatusBarOptionalLazy, + mShadeController, mNotificationRemoteInputManager, + mNotificationShadeDepthController, mSystemActions, mMainHandler, + mNavbarOverlayController, mUiEventLogger, mNavigationBarA11yHelper, + mUserTracker, mMainLightBarController, mLightBarControllerFactory, + mMainAutoHideController, mAutoHideControllerFactory, mTelecomManagerOptional, + mInputMethodManager); + } + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java index 2badbfa31979..97bcb00eddbd 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java @@ -32,53 +32,31 @@ import android.util.SparseArray; import android.view.Display; import android.view.IWindowManager; import android.view.View; -import android.view.WindowManager; import android.view.WindowManagerGlobal; -import android.view.accessibility.AccessibilityManager; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.UiEventLogger; import com.android.internal.statusbar.RegisterStatusBarResult; import com.android.settingslib.applications.InterestingConfigChanges; import com.android.systemui.Dumpable; -import com.android.systemui.accessibility.AccessibilityButtonModeObserver; -import com.android.systemui.accessibility.SystemActions; -import com.android.systemui.assist.AssistManager; -import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dump.DumpManager; import com.android.systemui.model.SysUiState; -import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.recents.OverviewProxyService; -import com.android.systemui.recents.Recents; -import com.android.systemui.settings.UserTracker; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.CommandQueue.Callbacks; -import com.android.systemui.statusbar.NotificationRemoteInputManager; -import com.android.systemui.statusbar.NotificationShadeDepthController; import com.android.systemui.statusbar.phone.AutoHideController; import com.android.systemui.statusbar.phone.BarTransitions.TransitionMode; -import com.android.systemui.statusbar.phone.ShadeController; -import com.android.systemui.statusbar.phone.StatusBar; -import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper; import com.android.systemui.statusbar.policy.ConfigurationController; -import com.android.systemui.statusbar.policy.DeviceProvisionedController; -import com.android.wm.shell.legacysplitscreen.LegacySplitScreen; -import com.android.wm.shell.pip.Pip; import java.io.FileDescriptor; import java.io.PrintWriter; -import java.util.Optional; import javax.inject.Inject; -import dagger.Lazy; - /** A controller to handle navigation bars. */ @SysUISingleton @@ -91,36 +69,12 @@ public class NavigationBarController implements private static final String TAG = NavigationBarController.class.getSimpleName(); private final Context mContext; - private final WindowManager mWindowManager; - private final Lazy<AssistManager> mAssistManagerLazy; - private final AccessibilityManager mAccessibilityManager; - private final AccessibilityManagerWrapper mAccessibilityManagerWrapper; - private final DeviceProvisionedController mDeviceProvisionedController; - private final MetricsLogger mMetricsLogger; - private final OverviewProxyService mOverviewProxyService; - private final NavigationModeController mNavigationModeController; - private final AccessibilityButtonModeObserver mAccessibilityButtonModeObserver; - private final StatusBarStateController mStatusBarStateController; - private final SysUiState mSysUiFlagsContainer; - private final BroadcastDispatcher mBroadcastDispatcher; - private final CommandQueue mCommandQueue; - private final Optional<Pip> mPipOptional; - private final Optional<LegacySplitScreen> mSplitScreenOptional; - private final Optional<Recents> mRecentsOptional; - private final Lazy<Optional<StatusBar>> mStatusBarOptionalLazy; - private final ShadeController mShadeController; - private final NotificationRemoteInputManager mNotificationRemoteInputManager; - private final SystemActions mSystemActions; - private final UiEventLogger mUiEventLogger; private final Handler mHandler; - private final NavigationBarA11yHelper mNavigationBarA11yHelper; + private final NavigationBar.Factory mNavigationBarFactory; private final DisplayManager mDisplayManager; - private final NavigationBarOverlayController mNavBarOverlayController; private final TaskbarDelegate mTaskbarDelegate; - private final NotificationShadeDepthController mNotificationShadeDepthController; private int mNavMode; @VisibleForTesting boolean mIsTablet; - private final UserTracker mUserTracker; /** A displayId - nav bar maps. */ @VisibleForTesting @@ -133,75 +87,30 @@ public class NavigationBarController implements @Inject public NavigationBarController(Context context, - WindowManager windowManager, - Lazy<AssistManager> assistManagerLazy, - AccessibilityManager accessibilityManager, - AccessibilityManagerWrapper accessibilityManagerWrapper, - DeviceProvisionedController deviceProvisionedController, - MetricsLogger metricsLogger, OverviewProxyService overviewProxyService, NavigationModeController navigationModeController, - AccessibilityButtonModeObserver accessibilityButtonModeObserver, - StatusBarStateController statusBarStateController, SysUiState sysUiFlagsContainer, - BroadcastDispatcher broadcastDispatcher, CommandQueue commandQueue, - Optional<Pip> pipOptional, - Optional<LegacySplitScreen> splitScreenOptional, - Optional<Recents> recentsOptional, - Lazy<Optional<StatusBar>> statusBarOptionalLazy, - ShadeController shadeController, - NotificationRemoteInputManager notificationRemoteInputManager, - NotificationShadeDepthController notificationShadeDepthController, - SystemActions systemActions, @Main Handler mainHandler, - UiEventLogger uiEventLogger, - NavigationBarOverlayController navBarOverlayController, ConfigurationController configurationController, NavigationBarA11yHelper navigationBarA11yHelper, TaskbarDelegate taskbarDelegate, - UserTracker userTracker, + NavigationBar.Factory navigationBarFactory, DumpManager dumpManager, AutoHideController autoHideController) { mContext = context; - mWindowManager = windowManager; - mAssistManagerLazy = assistManagerLazy; - mAccessibilityManager = accessibilityManager; - mAccessibilityManagerWrapper = accessibilityManagerWrapper; - mDeviceProvisionedController = deviceProvisionedController; - mMetricsLogger = metricsLogger; - mOverviewProxyService = overviewProxyService; - mNavigationModeController = navigationModeController; - mAccessibilityButtonModeObserver = accessibilityButtonModeObserver; - mStatusBarStateController = statusBarStateController; - mSysUiFlagsContainer = sysUiFlagsContainer; - mBroadcastDispatcher = broadcastDispatcher; - mCommandQueue = commandQueue; - mPipOptional = pipOptional; - mSplitScreenOptional = splitScreenOptional; - mRecentsOptional = recentsOptional; - mStatusBarOptionalLazy = statusBarOptionalLazy; - mShadeController = shadeController; - mNotificationRemoteInputManager = notificationRemoteInputManager; - mNotificationShadeDepthController = notificationShadeDepthController; - mSystemActions = systemActions; - mUiEventLogger = uiEventLogger; mHandler = mainHandler; - mNavigationBarA11yHelper = navigationBarA11yHelper; + mNavigationBarFactory = navigationBarFactory; mDisplayManager = mContext.getSystemService(DisplayManager.class); commandQueue.addCallback(this); configurationController.addCallback(this); mConfigChanges.applyNewConfig(mContext.getResources()); - mNavBarOverlayController = navBarOverlayController; - mNavMode = mNavigationModeController.addListener(this); - mNavigationModeController.addListener(this); + mNavMode = navigationModeController.addListener(this); mTaskbarDelegate = taskbarDelegate; mTaskbarDelegate.setDependencies(commandQueue, overviewProxyService, navigationBarA11yHelper, navigationModeController, sysUiFlagsContainer, dumpManager, autoHideController); mIsTablet = isTablet(mContext); - mUserTracker = userTracker; - dumpManager.registerDumpable(this); } @@ -357,33 +266,8 @@ public class NavigationBarController implements final Context context = isOnDefaultDisplay ? mContext : mContext.createDisplayContext(display); - NavigationBar navBar = new NavigationBar(context, - mWindowManager, - mAssistManagerLazy, - mAccessibilityManager, - mAccessibilityManagerWrapper, - mDeviceProvisionedController, - mMetricsLogger, - mOverviewProxyService, - mNavigationModeController, - mAccessibilityButtonModeObserver, - mStatusBarStateController, - mSysUiFlagsContainer, - mBroadcastDispatcher, - mCommandQueue, - mPipOptional, - mSplitScreenOptional, - mRecentsOptional, - mStatusBarOptionalLazy, - mShadeController, - mNotificationRemoteInputManager, - mNotificationShadeDepthController, - mSystemActions, - mHandler, - mNavBarOverlayController, - mUiEventLogger, - mNavigationBarA11yHelper, - mUserTracker); + NavigationBar navBar = mNavigationBarFactory.create(context); + mNavigationBars.put(displayId, navBar); View navigationBarView = navBar.createView(savedState); diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java index 3fc4f504d007..8588ddfcfa63 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java @@ -32,6 +32,7 @@ import android.widget.ImageView; import com.android.systemui.Dumpable; import com.android.systemui.R; import com.android.systemui.qs.customize.QSCustomizer; +import com.android.systemui.util.Utils; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -155,8 +156,7 @@ public class QSContainerImpl extends FrameLayout implements Dumpable { QuickStatusBarHeaderController quickStatusBarHeaderController) { mQSPanelContainer.setPaddingRelative( getPaddingStart(), - mContext.getResources() - .getDimensionPixelSize(R.dimen.qs_header_system_icons_area_height), + Utils.getQsHeaderSystemIconsAreaHeight(mContext), getPaddingEnd(), getPaddingBottom() ); diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java index 58a942a05cbc..d43404b8781c 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java @@ -40,6 +40,7 @@ import android.widget.TextView; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.UiEventLogger; +import com.android.internal.policy.SystemBarUtils; import com.android.systemui.Dependency; import com.android.systemui.FontSizeUtils; import com.android.systemui.R; @@ -164,8 +165,7 @@ public class QSDetail extends LinearLayout { public void updateResources() { updateDetailText(); MarginLayoutParams lp = (MarginLayoutParams) getLayoutParams(); - lp.topMargin = mContext.getResources().getDimensionPixelSize( - com.android.internal.R.dimen.quick_qs_offset_height); + lp.topMargin = SystemBarUtils.getQuickQsOffsetHeight(mContext); setLayoutParams(lp); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java index f300efca8a23..89bbcf5053a0 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java @@ -39,6 +39,7 @@ import androidx.annotation.VisibleForTesting; import com.android.systemui.R; import com.android.systemui.animation.Interpolators; +import com.android.systemui.animation.ShadeInterpolation; import com.android.systemui.dump.DumpManager; import com.android.systemui.media.MediaHost; import com.android.systemui.plugins.FalsingManager; @@ -53,7 +54,6 @@ import com.android.systemui.statusbar.notification.stack.StackStateAnimator; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.policy.BrightnessMirrorController; import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler; -import com.android.systemui.util.InjectionInflationController; import com.android.systemui.util.LifecycleFragment; import com.android.systemui.util.Utils; @@ -94,7 +94,6 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca private ImageView mQsDragHandler; private final RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler; - private final InjectionInflationController mInjectionInflater; private final CommandQueue mCommandQueue; private final QSDetailDisplayer mQsDetailDisplayer; private final MediaHost mQsMediaHost; @@ -144,7 +143,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca @Inject public QSFragment(RemoteInputQuickSettingsDisabler remoteInputQsDisabler, - InjectionInflationController injectionInflater, QSTileHost qsTileHost, + QSTileHost qsTileHost, StatusBarStateController statusBarStateController, CommandQueue commandQueue, QSDetailDisplayer qsDetailDisplayer, @Named(QS_PANEL) MediaHost qsMediaHost, @Named(QUICK_QS_PANEL) MediaHost qqsMediaHost, @@ -152,7 +151,6 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca QSFragmentComponent.Factory qsComponentFactory, FalsingManager falsingManager, DumpManager dumpManager) { mRemoteInputQuickSettingsDisabler = remoteInputQsDisabler; - mInjectionInflater = injectionInflater; mCommandQueue = commandQueue; mQsDetailDisplayer = qsDetailDisplayer; mQsMediaHost = qsMediaHost; @@ -169,9 +167,8 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { - inflater = mInjectionInflater.injectable( - inflater.cloneInContext(new ContextThemeWrapper(getContext(), - R.style.Theme_SystemUI_QuickSettings))); + inflater = inflater.cloneInContext(new ContextThemeWrapper(getContext(), + R.style.Theme_SystemUI_QuickSettings)); return inflater.inflate(R.layout.qs_panel, container, false); } @@ -573,7 +570,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca } else if (progress > 0 && view.getVisibility() != View.VISIBLE) { view.setVisibility((View.VISIBLE)); } - float alpha = Interpolators.getNotificationScrimAlpha(progress, true /* uiContent */); + float alpha = ShadeInterpolation.getContentAlpha(progress); view.setAlpha(alpha); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java index a81d3c64d912..071e0535e7c2 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java @@ -34,6 +34,7 @@ import android.widget.Space; import androidx.annotation.NonNull; +import com.android.internal.policy.SystemBarUtils; import com.android.settingslib.Utils; import com.android.systemui.R; import com.android.systemui.battery.BatteryMeterView; @@ -240,8 +241,7 @@ public class QuickStatusBarHeader extends FrameLayout { mRoundedCornerPadding = resources.getDimensionPixelSize( R.dimen.rounded_corner_content_padding); - int qsOffsetHeight = resources.getDimensionPixelSize( - com.android.internal.R.dimen.quick_qs_offset_height); + int qsOffsetHeight = SystemBarUtils.getQuickQsOffsetHeight(mContext); mDatePrivacyView.getLayoutParams().height = Math.max(qsOffsetHeight, mDatePrivacyView.getMinimumHeight()); diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java index 1a6d49070a2f..0a452627427b 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java +++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java @@ -36,6 +36,7 @@ import com.android.systemui.plugins.qs.QS; import com.android.systemui.plugins.qs.QSContainerController; import com.android.systemui.qs.QSDetailClipper; import com.android.systemui.statusbar.phone.LightBarController; +import com.android.systemui.util.Utils; /** * Allows full-screen customization of QS, through show() and hide(). @@ -84,8 +85,7 @@ public class QSCustomizer extends LinearLayout { void updateResources() { LayoutParams lp = (LayoutParams) mTransparentView.getLayoutParams(); - lp.height = mContext.getResources() - .getDimensionPixelSize(R.dimen.qs_header_system_icons_area_height); + lp.height = Utils.getQsHeaderSystemIconsAreaHeight(mContext); mTransparentView.setLayoutParams(lp); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java index 11430d93106a..15b78e7cb08a 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java @@ -36,6 +36,7 @@ import android.telephony.TelephonyDisplayInfo; import android.telephony.TelephonyManager; import android.text.Html; import android.text.TextUtils; +import android.text.method.LinkMovementMethod; import android.util.Log; import android.view.Gravity; import android.view.LayoutInflater; @@ -63,12 +64,15 @@ import com.android.internal.logging.UiEvent; import com.android.internal.logging.UiEventLogger; import com.android.systemui.Prefs; import com.android.systemui.R; +import com.android.systemui.accessibility.floatingmenu.AnnotationLinkSpan; import com.android.systemui.dagger.SysUISingleton; +import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.statusbar.phone.SystemUIDialog; import com.android.wifitrackerlib.WifiEntry; import java.util.List; +import java.util.concurrent.Executor; /** * Dialog for showing mobile network, connected Wi-Fi network and Wi-Fi networks. @@ -82,6 +86,7 @@ public class InternetDialog extends SystemUIDialog implements static final long PROGRESS_DELAY_MS = 2000L; private final Handler mHandler; + private final Executor mBackgroundExecutor; private final LinearLayoutManager mLayoutManager; @VisibleForTesting @@ -110,6 +115,8 @@ public class InternetDialog extends SystemUIDialog implements private LinearLayout mTurnWifiOnLayout; private LinearLayout mEthernetLayout; private TextView mWifiToggleTitleText; + private LinearLayout mWifiScanNotifyLayout; + private TextView mWifiScanNotifyText; private LinearLayout mSeeAllLayout; private RecyclerView mWifiRecyclerView; private ImageView mConnectedWifiIcon; @@ -154,13 +161,14 @@ public class InternetDialog extends SystemUIDialog implements public InternetDialog(Context context, InternetDialogFactory internetDialogFactory, InternetDialogController internetDialogController, boolean canConfigMobileData, boolean canConfigWifi, boolean aboveStatusBar, UiEventLogger uiEventLogger, - @Main Handler handler) { + @Main Handler handler, @Background Executor executor) { super(context, R.style.Theme_SystemUI_Dialog_Internet); if (DEBUG) { Log.d(TAG, "Init InternetDialog"); } mContext = context; mHandler = handler; + mBackgroundExecutor = executor; mInternetDialogFactory = internetDialogFactory; mInternetDialogController = internetDialogController; mSubscriptionManager = mInternetDialogController.getSubscriptionManager(); @@ -220,6 +228,8 @@ public class InternetDialog extends SystemUIDialog implements mMobileNetworkLayout = mDialogView.requireViewById(R.id.mobile_network_layout); mTurnWifiOnLayout = mDialogView.requireViewById(R.id.turn_on_wifi_layout); mWifiToggleTitleText = mDialogView.requireViewById(R.id.wifi_toggle_title); + mWifiScanNotifyLayout = mDialogView.requireViewById(R.id.wifi_scan_notify_layout); + mWifiScanNotifyText = mDialogView.requireViewById(R.id.wifi_scan_notify_text); mConnectedWifListLayout = mDialogView.requireViewById(R.id.wifi_connected_layout); mConnectedWifiIcon = mDialogView.requireViewById(R.id.wifi_connected_icon); mConnectedWifiTitleText = mDialogView.requireViewById(R.id.wifi_connected_title); @@ -293,7 +303,13 @@ public class InternetDialog extends SystemUIDialog implements dismiss(); } - void updateDialog() { + /** + * Update the internet dialog when receiving the callback. + * + * @param shouldUpdateMobileNetwork {@code true} for update the mobile network layout, + * otherwise {@code false}. + */ + void updateDialog(boolean shouldUpdateMobileNetwork) { if (DEBUG) { Log.d(TAG, "updateDialog"); } @@ -303,8 +319,10 @@ public class InternetDialog extends SystemUIDialog implements mInternetDialogSubTitle.setText(getSubtitleText()); } updateEthernet(); - setMobileDataLayout(mInternetDialogController.activeNetworkIsCellular() - || mInternetDialogController.isCarrierNetworkActive()); + if (shouldUpdateMobileNetwork) { + setMobileDataLayout(mInternetDialogController.activeNetworkIsCellular() + || mInternetDialogController.isCarrierNetworkActive()); + } if (!mCanConfigWifi) { return; @@ -313,8 +331,10 @@ public class InternetDialog extends SystemUIDialog implements showProgressBar(); final boolean isDeviceLocked = mInternetDialogController.isDeviceLocked(); final boolean isWifiEnabled = mWifiManager.isWifiEnabled(); + final boolean isWifiScanEnabled = mWifiManager.isScanAlwaysAvailable(); updateWifiToggle(isWifiEnabled, isDeviceLocked); updateConnectedWifi(isWifiEnabled, isDeviceLocked); + updateWifiScanNotify(isWifiEnabled, isWifiScanEnabled, isDeviceLocked); final int visibility = (isDeviceLocked || !isWifiEnabled || mWifiEntriesCount <= 0) ? View.GONE : View.VISIBLE; @@ -371,7 +391,13 @@ public class InternetDialog extends SystemUIDialog implements } else { mMobileSummaryText.setVisibility(View.GONE); } - mSignalIcon.setImageDrawable(getSignalStrengthDrawable()); + + mBackgroundExecutor.execute(() -> { + Drawable drawable = getSignalStrengthDrawable(); + mHandler.post(() -> { + mSignalIcon.setImageDrawable(drawable); + }); + }); mMobileTitleText.setTextAppearance(isCarrierNetworkConnected ? R.style.TextAppearance_InternetDialog_Active : R.style.TextAppearance_InternetDialog); @@ -411,6 +437,24 @@ public class InternetDialog extends SystemUIDialog implements mContext.getColor(R.color.connected_network_primary_color)); } + @MainThread + private void updateWifiScanNotify(boolean isWifiEnabled, boolean isWifiScanEnabled, + boolean isDeviceLocked) { + if (isWifiEnabled || !isWifiScanEnabled || isDeviceLocked) { + mWifiScanNotifyLayout.setVisibility(View.GONE); + return; + } + if (TextUtils.isEmpty(mWifiScanNotifyText.getText())) { + final AnnotationLinkSpan.LinkInfo linkInfo = new AnnotationLinkSpan.LinkInfo( + AnnotationLinkSpan.LinkInfo.DEFAULT_ANNOTATION, + v -> mInternetDialogController.launchWifiScanningSetting()); + mWifiScanNotifyText.setText(AnnotationLinkSpan.linkify( + getContext().getText(R.string.wifi_scan_notify_message), linkInfo)); + mWifiScanNotifyText.setMovementMethod(LinkMovementMethod.getInstance()); + } + mWifiScanNotifyLayout.setVisibility(View.VISIBLE); + } + void onClickConnectedWifi() { if (mConnectedWifiEntry == null) { return; @@ -508,52 +552,57 @@ public class InternetDialog extends SystemUIDialog implements @Override public void onRefreshCarrierInfo() { - mHandler.post(() -> updateDialog()); + mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */)); } @Override public void onSimStateChanged() { - mHandler.post(() -> updateDialog()); + mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */)); } @Override @WorkerThread public void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) { - mHandler.post(() -> updateDialog()); + mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */)); } @Override @WorkerThread public void onLost(Network network) { - mHandler.post(() -> updateDialog()); + mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */)); } @Override public void onSubscriptionsChanged(int defaultDataSubId) { mDefaultDataSubId = defaultDataSubId; mTelephonyManager = mTelephonyManager.createForSubscriptionId(mDefaultDataSubId); - mHandler.post(() -> updateDialog()); + mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */)); + } + + @Override + public void onUserMobileDataStateChanged(boolean enabled) { + mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */)); } @Override public void onServiceStateChanged(ServiceState serviceState) { - mHandler.post(() -> updateDialog()); + mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */)); } @Override @WorkerThread public void onDataConnectionStateChanged(int state, int networkType) { - mHandler.post(() -> updateDialog()); + mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */)); } @Override public void onSignalStrengthsChanged(SignalStrength signalStrength) { - mHandler.post(() -> updateDialog()); + mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */)); } @Override public void onDisplayInfoChanged(TelephonyDisplayInfo telephonyDisplayInfo) { - mHandler.post(() -> updateDialog()); + mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */)); } @Override @@ -565,7 +614,7 @@ public class InternetDialog extends SystemUIDialog implements mAdapter.setWifiEntries(wifiEntries, mWifiEntriesCount); mHandler.post(() -> { mAdapter.notifyDataSetChanged(); - updateDialog(); + updateDialog(false /* shouldUpdateMobileNetwork */); }); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java index b9cd08e8ac77..1ade5ce39c27 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java @@ -103,6 +103,8 @@ public class InternetDialogController implements WifiEntry.DisconnectCallback, private static final String TAG = "InternetDialogController"; private static final String ACTION_NETWORK_PROVIDER_SETTINGS = "android.settings.NETWORK_PROVIDER_SETTINGS"; + private static final String ACTION_WIFI_SCANNING_SETTINGS = + "android.settings.WIFI_SCANNING_SETTINGS"; private static final String EXTRA_CHOSEN_WIFI_ENTRY_KEY = "key_chosen_wifientry_key"; public static final Drawable EMPTY_DRAWABLE = new ColorDrawable(Color.TRANSPARENT); public static final int NO_CELL_DATA_TYPE_ICON = 0; @@ -147,6 +149,7 @@ public class InternetDialogController implements WifiEntry.DisconnectCallback, private ConnectivityManager.NetworkCallback mConnectivityManagerNetworkCallback; private WindowManager mWindowManager; private ToastFactory mToastFactory; + private SignalDrawable mSignalDrawable; @VisibleForTesting static final float TOAST_PARAMS_HORIZONTAL_WEIGHT = 1.0f; @@ -223,6 +226,7 @@ public class InternetDialogController implements WifiEntry.DisconnectCallback, mConnectivityManagerNetworkCallback = new DataConnectivityListener(); mWindowManager = windowManager; mToastFactory = toastFactory; + mSignalDrawable = new SignalDrawable(mContext); } void onStart(@NonNull InternetDialogCallback callback, boolean canConfigWifi) { @@ -429,10 +433,7 @@ public class InternetDialogController implements WifiEntry.DisconnectCallback, Drawable getSignalStrengthIcon(Context context, int level, int numLevels, int iconType, boolean cutOut) { - Log.d(TAG, "getSignalStrengthIcon"); - final SignalDrawable signalDrawable = new SignalDrawable(context); - signalDrawable.setLevel( - SignalDrawable.getState(level, numLevels, cutOut)); + mSignalDrawable.setLevel(SignalDrawable.getState(level, numLevels, cutOut)); // Make the network type drawable final Drawable networkDrawable = @@ -441,7 +442,7 @@ public class InternetDialogController implements WifiEntry.DisconnectCallback, : context.getResources().getDrawable(iconType, context.getTheme()); // Overlay the two drawables - final Drawable[] layers = {networkDrawable, signalDrawable}; + final Drawable[] layers = {networkDrawable, mSignalDrawable}; final int iconSize = context.getResources().getDimensionPixelSize(R.dimen.signal_strength_icon_size); @@ -603,6 +604,13 @@ public class InternetDialogController implements WifiEntry.DisconnectCallback, } } + void launchWifiScanningSetting() { + mCallback.dismissDialog(); + final Intent intent = new Intent(ACTION_WIFI_SCANNING_SETTINGS); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + mActivityStarter.postStartActivityDismissingKeyguard(intent, 0); + } + void connectCarrierNetwork() { final MergedCarrierEntry mergedCarrierEntry = mAccessPointController.getMergedCarrierEntry(); @@ -883,7 +891,8 @@ public class InternetDialogController implements WifiEntry.DisconnectCallback, TelephonyCallback.DataConnectionStateListener, TelephonyCallback.DisplayInfoListener, TelephonyCallback.ServiceStateListener, - TelephonyCallback.SignalStrengthsListener { + TelephonyCallback.SignalStrengthsListener, + TelephonyCallback.UserMobileDataStateListener { @Override public void onServiceStateChanged(@NonNull ServiceState serviceState) { @@ -905,6 +914,11 @@ public class InternetDialogController implements WifiEntry.DisconnectCallback, mTelephonyDisplayInfo = telephonyDisplayInfo; mCallback.onDisplayInfoChanged(telephonyDisplayInfo); } + + @Override + public void onUserMobileDataStateChanged(boolean enabled) { + mCallback.onUserMobileDataStateChanged(enabled); + } } private class InternetOnSubscriptionChangedListener @@ -1009,6 +1023,8 @@ public class InternetDialogController implements WifiEntry.DisconnectCallback, void onSignalStrengthsChanged(SignalStrength signalStrength); + void onUserMobileDataStateChanged(boolean enabled); + void onDisplayInfoChanged(TelephonyDisplayInfo telephonyDisplayInfo); void dismissDialog(); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt index 11c6980678b1..ea5df17bca58 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt @@ -20,7 +20,9 @@ import android.os.Handler import android.util.Log import com.android.internal.logging.UiEventLogger import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main +import java.util.concurrent.Executor import javax.inject.Inject private const val TAG = "InternetDialogFactory" @@ -32,6 +34,7 @@ private val DEBUG = Log.isLoggable(TAG, Log.DEBUG) @SysUISingleton class InternetDialogFactory @Inject constructor( @Main private val handler: Handler, + @Background private val executor: Executor, private val internetDialogController: InternetDialogController, private val context: Context, private val uiEventLogger: UiEventLogger @@ -49,7 +52,8 @@ class InternetDialogFactory @Inject constructor( return } else { internetDialog = InternetDialog(context, this, internetDialogController, - canConfigMobileData, canConfigWifi, aboveStatusBar, uiEventLogger, handler) + canConfigMobileData, canConfigWifi, aboveStatusBar, uiEventLogger, handler, + executor) internetDialog?.show() } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt index d4f54e1cd7b1..5648741e3caf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt @@ -32,6 +32,7 @@ import androidx.dynamicanimation.animation.SpringAnimation import androidx.dynamicanimation.animation.SpringForce import com.android.systemui.Dumpable import com.android.systemui.animation.Interpolators +import com.android.systemui.animation.ShadeInterpolation import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dump.DumpManager import com.android.systemui.plugins.statusbar.StatusBarStateController @@ -184,12 +185,12 @@ class NotificationShadeDepthController @Inject constructor( val animationRadius = MathUtils.constrain(shadeAnimation.radius, blurUtils.minBlurRadius.toFloat(), blurUtils.maxBlurRadius.toFloat()) val expansionRadius = blurUtils.blurRadiusOfRatio( - Interpolators.getNotificationScrimAlpha( - if (shouldApplyShadeBlur()) shadeExpansion else 0f, false)) + ShadeInterpolation.getNotificationScrimAlpha( + if (shouldApplyShadeBlur()) shadeExpansion else 0f)) var combinedBlur = (expansionRadius * INTERACTION_BLUR_FRACTION + animationRadius * ANIMATION_BLUR_FRACTION) - val qsExpandedRatio = Interpolators.getNotificationScrimAlpha(qsPanelExpansion, - false /* notification */) * shadeExpansion + val qsExpandedRatio = ShadeInterpolation.getNotificationScrimAlpha(qsPanelExpansion) * + shadeExpansion combinedBlur = max(combinedBlur, blurUtils.blurRadiusOfRatio(qsExpandedRatio)) combinedBlur = max(combinedBlur, blurUtils.blurRadiusOfRatio(transitionToFullShadeProgress)) var shadeRadius = max(combinedBlur, wakeAndUnlockBlurRadius) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java index 3bd7dd339a9e..51a66aad39fb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java @@ -30,8 +30,9 @@ import android.view.animation.Interpolator; import android.view.animation.PathInterpolator; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.policy.SystemBarUtils; import com.android.systemui.R; -import com.android.systemui.animation.Interpolators; +import com.android.systemui.animation.ShadeInterpolation; import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener; import com.android.systemui.statusbar.notification.NotificationUtils; import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; @@ -114,7 +115,7 @@ public class NotificationShelf extends ActivatableNotificationView implements private void initDimens() { Resources res = getResources(); - mStatusBarHeight = res.getDimensionPixelOffset(R.dimen.status_bar_height); + mStatusBarHeight = SystemBarUtils.getStatusBarHeight(mContext); mPaddingBetweenElements = res.getDimensionPixelSize(R.dimen.notification_divider_height); ViewGroup.LayoutParams layoutParams = getLayoutParams(); @@ -168,8 +169,8 @@ public class NotificationShelf extends ActivatableNotificationView implements viewState.clipTopAmount = 0; if (ambientState.isExpansionChanging() && !ambientState.isOnKeyguard()) { - viewState.alpha = Interpolators.getNotificationScrimAlpha( - ambientState.getExpansionFraction(), true /* notification */); + float expansion = ambientState.getExpansionFraction(); + viewState.alpha = ShadeInterpolation.getContentAlpha(expansion); } else { viewState.alpha = 1f - ambientState.getHideAmount(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java index cbb3aba5cc64..6da981b72428 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java @@ -28,6 +28,7 @@ import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.os.SystemProperties; +import android.os.Trace; import android.text.format.DateFormat; import android.util.FloatProperty; import android.util.Log; @@ -181,6 +182,7 @@ public class StatusBarStateControllerImpl implements } synchronized (mListeners) { + Trace.beginSection(TAG + "#setState(" + StatusBarState.toShortString(state) + ")"); String tag = getClass().getSimpleName() + "#setState(" + state + ")"; DejankUtils.startDetectingBlockingIpcs(tag); for (RankedListener rl : new ArrayList<>(mListeners)) { @@ -198,6 +200,7 @@ public class StatusBarStateControllerImpl implements rl.mListener.onStatePostChange(); } DejankUtils.stopDetectingBlockingIpcs(tag); + Trace.endSection(); } return true; @@ -262,12 +265,14 @@ public class StatusBarStateControllerImpl implements mIsDozing = isDozing; synchronized (mListeners) { + Trace.beginSection(TAG + "#setDozing(" + isDozing + ")"); String tag = getClass().getSimpleName() + "#setIsDozing"; DejankUtils.startDetectingBlockingIpcs(tag); for (RankedListener rl : new ArrayList<>(mListeners)) { rl.mListener.onDozingChanged(isDozing); } DejankUtils.stopDetectingBlockingIpcs(tag); + Trace.endSection(); } return true; @@ -333,12 +338,14 @@ public class StatusBarStateControllerImpl implements mDozeAmount = dozeAmount; float interpolatedAmount = mDozeInterpolator.getInterpolation(dozeAmount); synchronized (mListeners) { + Trace.beginSection(TAG + "#setDozeAmount"); String tag = getClass().getSimpleName() + "#setDozeAmount"; DejankUtils.startDetectingBlockingIpcs(tag); for (RankedListener rl : new ArrayList<>(mListeners)) { rl.mListener.onDozeAmountChanged(mDozeAmount, interpolatedAmount); } DejankUtils.stopDetectingBlockingIpcs(tag); + Trace.endSection(); } } @@ -469,11 +476,13 @@ public class StatusBarStateControllerImpl implements public void setPulsing(boolean pulsing) { if (mPulsing != pulsing) { mPulsing = pulsing; + Trace.beginSection(TAG + "#setPulsing(" + pulsing + ")"); synchronized (mListeners) { for (RankedListener rl : new ArrayList<>(mListeners)) { rl.mListener.onPulsingChanged(pulsing); } } + Trace.endSection(); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java index d9b0ee7e9921..f72178f0c8b0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java @@ -332,8 +332,7 @@ public class NetworkControllerImpl extends BroadcastReceiver deviceProvisionedController.addCallback(new DeviceProvisionedListener() { @Override public void onUserSetupChanged() { - setUserSetupComplete(deviceProvisionedController.isUserSetup( - deviceProvisionedController.getCurrentUser())); + setUserSetupComplete(deviceProvisionedController.isCurrentUserSetup()); } }); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt index 1037e576f263..b97bac261ff0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt @@ -24,7 +24,6 @@ import android.util.Log import android.view.Gravity import android.view.View import android.widget.FrameLayout - import com.android.internal.annotations.GuardedBy import com.android.systemui.animation.Interpolators import com.android.systemui.R @@ -44,7 +43,6 @@ import com.android.systemui.util.leak.RotationUtils.ROTATION_SEASCAPE import com.android.systemui.util.leak.RotationUtils.ROTATION_UPSIDE_DOWN import com.android.systemui.util.leak.RotationUtils.Rotation -import java.lang.IllegalStateException import java.util.concurrent.Executor import javax.inject.Inject @@ -71,9 +69,6 @@ class PrivacyDotViewController @Inject constructor( private val contentInsetsProvider: StatusBarContentInsetsProvider, private val animationScheduler: SystemStatusAnimationScheduler ) { - private var sbHeightPortrait = 0 - private var sbHeightLandscape = 0 - private lateinit var tl: View private lateinit var tr: View private lateinit var bl: View @@ -156,16 +151,12 @@ class PrivacyDotViewController @Inject constructor( val newCorner = selectDesignatedCorner(rot, isRtl) val index = newCorner.cornerIndex() + val paddingTop = contentInsetsProvider.getStatusBarPaddingTop(rot) - val h = when (rot) { - 0, 2 -> sbHeightPortrait - 1, 3 -> sbHeightLandscape - else -> 0 - } synchronized(lock) { nextViewState = nextViewState.copy( rotation = rot, - height = h, + paddingTop = paddingTop, designatedCorner = newCorner, cornerIndex = index) } @@ -203,26 +194,17 @@ class PrivacyDotViewController @Inject constructor( } } - @UiThread - private fun updateHeights(rot: Int) { - val height = when (rot) { - 0, 2 -> sbHeightPortrait - 1, 3 -> sbHeightLandscape - else -> 0 - } - - views.forEach { it.layoutParams.height = height } - } - // Update the gravity and margins of the privacy views @UiThread - private fun updateRotations(rotation: Int) { + private fun updateRotations(rotation: Int, paddingTop: Int) { // To keep a view in the corner, its gravity is always the description of its current corner // Therefore, just figure out which view is in which corner. This turns out to be something // like (myCorner - rot) mod 4, where topLeft = 0, topRight = 1, etc. and portrait = 0, and // rotating the device counter-clockwise increments rotation by 1 views.forEach { corner -> + corner.setPadding(0, paddingTop, 0, 0) + val rotatedCorner = rotatedCorner(cornerForView(corner), rotation) (corner.layoutParams as FrameLayout.LayoutParams).apply { gravity = rotatedCorner.toGravity() @@ -265,6 +247,7 @@ class PrivacyDotViewController @Inject constructor( var rot = activeRotationForCorner(tl, rtl) var contentInsets = state.contentRectForRotation(rot) + tl.setPadding(0, state.paddingTop, 0, 0) (tl.layoutParams as FrameLayout.LayoutParams).apply { height = contentInsets.height() if (rtl) { @@ -276,6 +259,7 @@ class PrivacyDotViewController @Inject constructor( rot = activeRotationForCorner(tr, rtl) contentInsets = state.contentRectForRotation(rot) + tr.setPadding(0, state.paddingTop, 0, 0) (tr.layoutParams as FrameLayout.LayoutParams).apply { height = contentInsets.height() if (rtl) { @@ -287,6 +271,7 @@ class PrivacyDotViewController @Inject constructor( rot = activeRotationForCorner(br, rtl) contentInsets = state.contentRectForRotation(rot) + br.setPadding(0, state.paddingTop, 0, 0) (br.layoutParams as FrameLayout.LayoutParams).apply { height = contentInsets.height() if (rtl) { @@ -298,6 +283,7 @@ class PrivacyDotViewController @Inject constructor( rot = activeRotationForCorner(bl, rtl) contentInsets = state.contentRectForRotation(rot) + bl.setPadding(0, state.paddingTop, 0, 0) (bl.layoutParams as FrameLayout.LayoutParams).apply { height = contentInsets.height() if (rtl) { @@ -412,6 +398,7 @@ class PrivacyDotViewController @Inject constructor( val right = contentInsetsProvider.getStatusBarContentInsetsForRotation(ROTATION_LANDSCAPE) val bottom = contentInsetsProvider .getStatusBarContentInsetsForRotation(ROTATION_UPSIDE_DOWN) + val paddingTop = contentInsetsProvider.getStatusBarPaddingTop() synchronized(lock) { nextViewState = nextViewState.copy( @@ -422,20 +409,12 @@ class PrivacyDotViewController @Inject constructor( portraitRect = top, landscapeRect = right, upsideDownRect = bottom, + paddingTop = paddingTop, layoutRtl = rtl ) } } - /** - * Set the status bar height in portrait and landscape, in pixels. If they are the same you can - * pass the same value twice - */ - fun setStatusBarHeights(portrait: Int, landscape: Int) { - sbHeightPortrait = portrait - sbHeightLandscape = landscape - } - private fun updateStatusBarState() { synchronized(lock) { nextViewState = nextViewState.copy(shadeExpanded = isShadeInQs()) @@ -488,7 +467,7 @@ class PrivacyDotViewController @Inject constructor( if (state.rotation != currentViewState.rotation) { // A rotation has started, hide the views to avoid flicker - updateRotations(state.rotation) + updateRotations(state.rotation, state.paddingTop) } if (state.needsLayout(currentViewState)) { @@ -627,7 +606,7 @@ private data class ViewState( val layoutRtl: Boolean = false, val rotation: Int = 0, - val height: Int = 0, + val paddingTop: Int = 0, val cornerIndex: Int = -1, val designatedCorner: View? = null, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java index acb0e82c24f2..2eb20654716d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java @@ -22,7 +22,6 @@ import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Canvas; import android.graphics.Point; -import android.graphics.RectF; import android.util.AttributeSet; import android.util.MathUtils; import android.view.MotionEvent; @@ -111,7 +110,6 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView private Interpolator mCurrentAppearInterpolator; NotificationBackgroundView mBackgroundNormal; - private RectF mAppearAnimationRect = new RectF(); private float mAnimationTranslationY; private boolean mDrawingAppearAnimation; private ValueAnimator mAppearAnimator; @@ -123,13 +121,6 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView private long mLastActionUpTime; private float mNormalBackgroundVisibilityAmount; - private ValueAnimator.AnimatorUpdateListener mBackgroundVisibilityUpdater - = new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - setNormalBackgroundVisibilityAmount(mBackgroundNormal.getAlpha()); - } - }; private FakeShadowView mFakeShadow; private int mCurrentBackgroundTint; private int mTargetTint; @@ -138,11 +129,8 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView private float mOverrideAmount; private boolean mShadowHidden; private boolean mIsHeadsUpAnimation; - private int mHeadsUpAddStartLocation; - private float mHeadsUpLocation; /* In order to track headsup longpress coorindate. */ protected Point mTargetPoint; - private boolean mIsAppearing; private boolean mDismissed; private boolean mRefocusOnDismiss; private AccessibilityManager mAccessibilityManager; @@ -154,7 +142,6 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView setClipChildren(false); setClipToPadding(false); updateColors(); - initDimens(); } private void updateColors() { @@ -166,17 +153,6 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView R.color.notification_ripple_untinted_color); } - private void initDimens() { - mHeadsUpAddStartLocation = getResources().getDimensionPixelSize( - com.android.internal.R.dimen.notification_content_margin_start); - } - - @Override - public void onDensityOrFontScaleChanged() { - super.onDensityOrFontScaleChanged(); - initDimens(); - } - /** * Reload background colors from resources and invalidate views. */ @@ -438,7 +414,6 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView Runnable onFinishedRunnable, AnimatorListenerAdapter animationListener) { enableAppearDrawing(true); mIsHeadsUpAnimation = isHeadsUpAnimation; - mHeadsUpLocation = endLocation; if (mDrawingAppearAnimation) { startAppearAnimation(false /* isAppearing */, translationDirection, delay, duration, onFinishedRunnable, animationListener); @@ -452,7 +427,6 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView public void performAddAnimation(long delay, long duration, boolean isHeadsUpAppear) { enableAppearDrawing(true); mIsHeadsUpAnimation = isHeadsUpAppear; - mHeadsUpLocation = mHeadsUpAddStartLocation; if (mDrawingAppearAnimation) { startAppearAnimation(true /* isAppearing */, isHeadsUpAppear ? 0.0f : -1.0f, delay, duration, null, null); @@ -474,7 +448,6 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView mAppearAnimationTranslation = 0; } } - mIsAppearing = isAppearing; float targetValue; if (isAppearing) { @@ -782,8 +755,4 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView void onActivated(ActivatableNotificationView view); void onActivationReset(ActivatableNotificationView view); } - - interface OnDimmedListener { - void onSetDimmed(boolean dimmed); - } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java index c3dc7001f5e8..d59318e45e7e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java @@ -41,8 +41,11 @@ import android.widget.FrameLayout; import android.widget.FrameLayout.LayoutParams; import com.android.internal.annotations.VisibleForTesting; +import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.animation.Interpolators; +import com.android.systemui.flags.FeatureFlags; +import com.android.systemui.flags.Flags; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.statusbar.AlphaOptimizedImageView; import com.android.systemui.statusbar.notification.collection.NotificationEntry; @@ -306,7 +309,7 @@ public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnCl final int showDismissSetting = Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.SHOW_NEW_NOTIF_DISMISS, -1); final boolean newFlowHideShelf = showDismissSetting == -1 - ? mContext.getResources().getBoolean(R.bool.flag_notif_updates) + ? Dependency.get(FeatureFlags.class).isEnabled(Flags.NOTIFICATION_UPDATES) : showDismissSetting == 1; if (newFlowHideShelf) { return; 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 45fd5efd00f5..a9cc3237d719 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 @@ -72,7 +72,6 @@ public class AmbientState { private boolean mPanelFullWidth; private boolean mPulsing; private boolean mUnlockHintRunning; - private int mIntrinsicPadding; private float mHideAmount; private boolean mAppearing; private float mPulseHeight = MAX_PULSE_HEIGHT; @@ -82,6 +81,7 @@ public class AmbientState { private float mAppearFraction; private boolean mIsShadeOpening; private float mOverExpansion; + private int mStackTopMargin; /** Distance of top of notifications panel from top of screen. */ private float mStackY = 0; @@ -94,7 +94,6 @@ public class AmbientState { /** Height of the notifications panel without top padding when expansion completes. */ private float mStackEndHeight; - private float mTransitionToFullShadeAmount; /** * @return Height of the notifications panel without top padding when expansion completes. @@ -493,14 +492,6 @@ public class AmbientState { return mUnlockHintRunning; } - public void setIntrinsicPadding(int intrinsicPadding) { - mIntrinsicPadding = intrinsicPadding; - } - - public int getIntrinsicPadding() { - return mIntrinsicPadding; - } - /** * @return whether a view is dozing and not pulsing right now */ @@ -577,30 +568,11 @@ public class AmbientState { mOnPulseHeightChangedListener = onPulseHeightChangedListener; } - public Runnable getOnPulseHeightChangedListener() { - return mOnPulseHeightChangedListener; - } - public void setTrackedHeadsUpRow(ExpandableNotificationRow row) { mTrackedHeadsUpRow = row; } /** - * Set the amount of pixels we have currently dragged down if we're transitioning to the full - * shade. 0.0f means we're not transitioning yet. - */ - public void setTransitionToFullShadeAmount(float transitionToFullShadeAmount) { - mTransitionToFullShadeAmount = transitionToFullShadeAmount; - } - - /** - * get - */ - public float getTransitionToFullShadeAmount() { - return mTransitionToFullShadeAmount; - } - - /** * Returns the currently tracked heads up row, if there is one and it is currently above the * shelf (still appearing). */ @@ -622,4 +594,12 @@ public class AmbientState { public void setHasAlertEntries(boolean hasAlertEntries) { mHasAlertEntries = hasAlertEntries; } + + public void setStackTopMargin(int stackTopMargin) { + mStackTopMargin = stackTopMargin; + } + + public int getStackTopMargin() { + return mStackTopMargin; + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java index 594afceab63a..faf0fdfa0c8d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java @@ -21,6 +21,8 @@ import android.util.MathUtils; import com.android.systemui.R; import com.android.systemui.dagger.SysUISingleton; +import com.android.systemui.flags.FeatureFlags; +import com.android.systemui.flags.Flags; import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.ExpandableView; @@ -41,6 +43,7 @@ public class NotificationRoundnessManager { private final ExpandableView[] mTmpFirstInSectionViews; private final ExpandableView[] mTmpLastInSectionViews; private final KeyguardBypassController mBypassController; + private final FeatureFlags mFeatureFlags; private boolean mExpanded; private HashSet<ExpandableView> mAnimatedChildren; private Runnable mRoundingChangedCallback; @@ -55,7 +58,9 @@ public class NotificationRoundnessManager { @Inject NotificationRoundnessManager( KeyguardBypassController keyguardBypassController, - NotificationSectionsFeatureManager sectionsFeatureManager) { + NotificationSectionsFeatureManager sectionsFeatureManager, + FeatureFlags featureFlags) { + mFeatureFlags = featureFlags; int numberOfSections = sectionsFeatureManager.getNumberOfBuckets(); mFirstInSectionViews = new ExpandableView[numberOfSections]; mLastInSectionViews = new ExpandableView[numberOfSections]; @@ -122,9 +127,8 @@ public class NotificationRoundnessManager { void setViewsAffectedBySwipe( ExpandableView viewBefore, ExpandableView viewSwiped, - ExpandableView viewAfter, - boolean cornerAnimationsEnabled) { - if (!cornerAnimationsEnabled) { + ExpandableView viewAfter) { + if (!mFeatureFlags.isEnabled(Flags.NOTIFICATION_UPDATES)) { return; } final boolean animate = true; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index 278f09b45b4c..7213b2fb46f9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -19,7 +19,6 @@ package com.android.systemui.statusbar.notification.stack; import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_SCROLL_FLING; import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_SILENT; import static com.android.systemui.statusbar.notification.stack.StackStateAnimator.ANIMATION_DURATION_SWIPE; -import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT; import static com.android.systemui.util.Utils.shouldUseSplitNotificationShade; import static java.lang.annotation.RetentionPolicy.SOURCE; @@ -72,8 +71,10 @@ import android.widget.ScrollView; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.graphics.ColorUtils; import com.android.internal.jank.InteractionJankMonitor; +import com.android.internal.policy.SystemBarUtils; import com.android.keyguard.KeyguardSliceView; import com.android.settingslib.Utils; +import com.android.systemui.Dependency; import com.android.systemui.Dumpable; import com.android.systemui.ExpandHelper; import com.android.systemui.R; @@ -120,9 +121,6 @@ import java.util.List; import java.util.function.BiConsumer; import java.util.function.Consumer; -import javax.inject.Inject; -import javax.inject.Named; - /** * A layout which handles a dynamic amount of notifications and presents them in a scrollable stack. */ @@ -566,24 +564,17 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable @Nullable private OnClickListener mManageButtonClickListener; - @Inject - public NotificationStackScrollLayout( - @Named(VIEW_CONTEXT) Context context, - AttributeSet attrs, - NotificationSectionsManager notificationSectionsManager, - GroupMembershipManager groupMembershipManager, - GroupExpansionManager groupExpansionManager, - AmbientState ambientState, - UnlockedScreenOffAnimationController unlockedScreenOffAnimationController) { + public NotificationStackScrollLayout(Context context, AttributeSet attrs) { super(context, attrs, 0, 0); Resources res = getResources(); - mSectionsManager = notificationSectionsManager; - mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController; + mSectionsManager = Dependency.get(NotificationSectionsManager.class); + mUnlockedScreenOffAnimationController = + Dependency.get(UnlockedScreenOffAnimationController.class); updateSplitNotificationShade(); mSectionsManager.initialize(this, LayoutInflater.from(context)); mSections = mSectionsManager.createSectionsForBuckets(); - mAmbientState = ambientState; + mAmbientState = Dependency.get(AmbientState.class); mBgColor = Utils.getColorAttr(mContext, android.R.attr.colorBackgroundFloating) .getDefaultColor(); int minHeight = res.getDimensionPixelSize(R.dimen.notification_min_height); @@ -609,8 +600,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable mDebugPaint.setTextSize(25f); } mClearAllEnabled = res.getBoolean(R.bool.config_enableNotificationsClearAll); - mGroupMembershipManager = groupMembershipManager; - mGroupExpansionManager = groupExpansionManager; + mGroupMembershipManager = Dependency.get(GroupMembershipManager.class); + mGroupExpansionManager = Dependency.get(GroupExpansionManager.class); setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); } @@ -947,7 +938,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable res.getDimensionPixelSize(R.dimen.notification_divider_height)); mMinTopOverScrollToEscape = res.getDimensionPixelSize( R.dimen.min_top_overscroll_to_qs); - mStatusBarHeight = res.getDimensionPixelSize(R.dimen.status_bar_height); + mStatusBarHeight = SystemBarUtils.getStatusBarHeight(mContext); mBottomMargin = res.getDimensionPixelSize(R.dimen.notification_panel_margin_bottom); mMinimumPaddings = res.getDimensionPixelSize(R.dimen.notification_side_paddings); mQsTilePadding = res.getDimensionPixelOffset(R.dimen.qs_tile_margin_horizontal); @@ -958,8 +949,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable mCornerRadius = res.getDimensionPixelSize(R.dimen.notification_corner_radius); mHeadsUpInset = mStatusBarHeight + res.getDimensionPixelSize( R.dimen.heads_up_status_bar_padding); - mQsScrollBoundaryPosition = res.getDimensionPixelSize( - com.android.internal.R.dimen.quick_qs_offset_height); + mQsScrollBoundaryPosition = SystemBarUtils.getQuickQsOffsetHeight(mContext); } void updateSidePadding(int viewWidth) { @@ -1717,7 +1707,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable super.onConfigurationChanged(newConfig); Resources res = getResources(); updateSplitNotificationShade(); - mStatusBarHeight = res.getDimensionPixelOffset(R.dimen.status_bar_height); + mStatusBarHeight = SystemBarUtils.getStatusBarHeight(mContext); float densityScale = res.getDisplayMetrics().density; mSwipeHelper.setDensityScale(densityScale); float pagingTouchSlop = ViewConfiguration.get(getContext()).getScaledPagingTouchSlop(); @@ -4287,7 +4277,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable @ShadeViewRefactor(RefactorComponent.COORDINATOR) void setIntrinsicPadding(int intrinsicPadding) { mIntrinsicPadding = intrinsicPadding; - mAmbientState.setIntrinsicPadding(intrinsicPadding); } @ShadeViewRefactor(RefactorComponent.COORDINATOR) @@ -5279,10 +5268,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable mController.getNoticationRoundessManager().setAnimatedChildren(mChildrenToAddAnimated); } - public NotificationStackScrollLayoutController getController() { - return mController; - } - void addSwipedOutView(View v) { mSwipedOutViews.add(v); } @@ -5312,10 +5297,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable } } mController.getNoticationRoundessManager() - .setViewsAffectedBySwipe((ExpandableView) viewBefore, + .setViewsAffectedBySwipe( + (ExpandableView) viewBefore, (ExpandableView) viewSwiped, - (ExpandableView) viewAfter, - getResources().getBoolean(R.bool.flag_notif_updates)); + (ExpandableView) viewAfter); updateFirstAndLastBackgroundViews(); requestDisallowInterceptTouchEvent(true); @@ -5327,8 +5312,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable void onSwipeEnd() { updateFirstAndLastBackgroundViews(); mController.getNoticationRoundessManager() - .setViewsAffectedBySwipe(null, null, null, - getResources().getBoolean(R.bool.flag_notif_updates)); + .setViewsAffectedBySwipe(null, null, null); // Round bottom corners for notification right before shelf. mShelf.updateAppearance(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java index 8be5de7ae56e..afe0bbafbd31 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java @@ -24,8 +24,11 @@ import android.util.MathUtils; import android.view.View; import android.view.ViewGroup; +import androidx.annotation.VisibleForTesting; + +import com.android.internal.policy.SystemBarUtils; import com.android.systemui.R; -import com.android.systemui.animation.Interpolators; +import com.android.systemui.animation.ShadeInterpolation; import com.android.systemui.statusbar.NotificationShelf; import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; @@ -54,8 +57,7 @@ public class StackScrollAlgorithm { private StackScrollAlgorithmState mTempAlgorithmState = new StackScrollAlgorithmState(); private boolean mIsExpanded; private boolean mClipNotificationScrollToTop; - private int mStatusBarHeight; - private float mHeadsUpInset; + @VisibleForTesting float mHeadsUpInset; private int mPinnedZTranslationExtra; private float mNotificationScrimPadding; @@ -75,9 +77,9 @@ public class StackScrollAlgorithm { mPaddingBetweenElements = res.getDimensionPixelSize( R.dimen.notification_divider_height); mCollapsedSize = res.getDimensionPixelSize(R.dimen.notification_min_height); - mStatusBarHeight = res.getDimensionPixelSize(R.dimen.status_bar_height); mClipNotificationScrollToTop = res.getBoolean(R.bool.config_clipNotificationScrollToTop); - mHeadsUpInset = mStatusBarHeight + res.getDimensionPixelSize( + int statusBarHeight = SystemBarUtils.getStatusBarHeight(context); + mHeadsUpInset = statusBarHeight + res.getDimensionPixelSize( R.dimen.heads_up_status_bar_padding); mPinnedZTranslationExtra = res.getDimensionPixelSize( R.dimen.heads_up_pinned_elevation); @@ -407,8 +409,8 @@ public class StackScrollAlgorithm { viewState.alpha = 1f - ambientState.getHideAmount(); } else if (ambientState.isExpansionChanging()) { // Adjust alpha for shade open & close. - viewState.alpha = Interpolators.getNotificationScrimAlpha( - ambientState.getExpansionFraction(), true /* notification */); + float expansion = ambientState.getExpansionFraction(); + viewState.alpha = ShadeInterpolation.getContentAlpha(expansion); } if (ambientState.isShadeExpanded() && view.mustStayOnScreen() @@ -562,13 +564,14 @@ public class StackScrollAlgorithm { // Move the tracked heads up into position during the appear animation, by interpolating // between the HUN inset (where it will appear as a HUN) and the end position in the shade + float headsUpTranslation = mHeadsUpInset - ambientState.getStackTopMargin(); ExpandableNotificationRow trackedHeadsUpRow = ambientState.getTrackedHeadsUpRow(); if (trackedHeadsUpRow != null) { ExpandableViewState childState = trackedHeadsUpRow.getViewState(); if (childState != null) { float endPosition = childState.yTranslation - ambientState.getStackTranslation(); childState.yTranslation = MathUtils.lerp( - mHeadsUpInset, endPosition, ambientState.getAppearFraction()); + headsUpTranslation, endPosition, ambientState.getAppearFraction()); } } @@ -602,7 +605,7 @@ public class StackScrollAlgorithm { } } if (row.isPinned()) { - childState.yTranslation = Math.max(childState.yTranslation, mHeadsUpInset); + childState.yTranslation = Math.max(childState.yTranslation, headsUpTranslation); childState.height = Math.max(row.getIntrinsicHeight(), childState.height); childState.hidden = false; ExpandableViewState topState = diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java index e12009e655b5..111cbbe81755 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java @@ -172,4 +172,23 @@ public class AutoHideController { return false; } + + /** + * Injectable factory for creating a {@link AutoHideController}. + */ + public static class Factory { + private final Handler mHandler; + private final IWindowManager mIWindowManager; + + @Inject + public Factory(@Main Handler handler, IWindowManager iWindowManager) { + mHandler = handler; + mIWindowManager = iWindowManager; + } + + /** Create an {@link AutoHideController} */ + public AutoHideController create(Context context) { + return new AutoHideController(context, mHandler, mIWindowManager); + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java index 5bf982b908cd..49e3fe7df2be 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java @@ -283,14 +283,12 @@ public class DozeParameters implements } /** - * Sensor to use for brightness changes. + * Gets the brightness string array per posture. Brightness names along with + * doze_brightness_sensor_type is used to determine the brightness sensor to use for + * the current posture. */ - public String brightnessName(@DevicePostureController.DevicePostureInt int posture) { - return AmbientDisplayConfiguration.getSensorFromPostureMapping( - mResources.getStringArray(R.array.doze_brightness_sensor_name_posture_mapping), - null /* defaultValue */, - posture - ); + public String[] brightnessNames() { + return mResources.getStringArray(R.array.doze_brightness_sensor_name_posture_mapping); } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java index f289b9f20211..57b9c03ce576 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java @@ -226,11 +226,11 @@ public final class DozeServiceHost implements DozeHost { return; } - if (reason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN) { + if (reason == DozeLog.PULSE_REASON_SENSOR_WAKE_REACH) { mScrimController.setWakeLockScreenSensorActive(true); } - boolean passiveAuthInterrupt = reason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN + boolean passiveAuthInterrupt = reason == DozeLog.PULSE_REASON_SENSOR_WAKE_REACH && mWakeLockScreenPerformsAuth; // Set the state to pulsing, so ScrimController will know what to do once we ask it to // execute the transition. The pulse callback will then be invoked when the scrims @@ -329,7 +329,7 @@ public final class DozeServiceHost implements DozeHost { @Override public void extendPulse(int reason) { - if (reason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN) { + if (reason == DozeLog.PULSE_REASON_SENSOR_WAKE_REACH) { mScrimController.setWakeLockScreenSensorActive(true); } if (mDozeScrimController.isPulsing() && mHeadsUpManagerPhone.hasNotifications()) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java index 878fbbf39627..927b4c8cc919 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java @@ -163,7 +163,6 @@ public class HeadsUpAppearanceController implements OnHeadsUpChangedListener, mHeadsUpStatusBarView.setOnDrawingRectChangedListener(null); mWakeUpCoordinator.removeListener(this); mNotificationPanelViewController.removeTrackingHeadsUpListener(mSetTrackingHeadsUp); - mNotificationPanelViewController.setVerticalTranslationListener(null); mNotificationPanelViewController.setHeadsUpAppearanceController(null); mStackScrollerController.removeOnExpandedHeightChangedListener(mSetExpandedHeight); mDarkIconDispatcher.removeDarkReceiver(this); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java index 5f402d0d861d..c81196d7a0f9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java @@ -26,6 +26,7 @@ import android.util.Pools; import androidx.collection.ArraySet; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.policy.SystemBarUtils; import com.android.systemui.Dumpable; import com.android.systemui.R; import com.android.systemui.plugins.statusbar.StatusBarStateController; @@ -137,9 +138,8 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable, private void updateResources() { Resources resources = mContext.getResources(); - mHeadsUpInset = - resources.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height) - + resources.getDimensionPixelSize(R.dimen.heads_up_status_bar_padding); + mHeadsUpInset = SystemBarUtils.getStatusBarHeight(mContext) + + resources.getDimensionPixelSize(R.dimen.heads_up_status_bar_padding); } /////////////////////////////////////////////////////////////////////////////////////////////// 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 a090ac35070e..b9b663c33a45 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java @@ -30,6 +30,7 @@ import android.view.View; import android.view.ViewGroup; import android.view.WindowInsets; +import com.android.internal.policy.SystemBarUtils; import com.android.keyguard.KeyguardHostViewController; import com.android.keyguard.KeyguardRootViewController; import com.android.keyguard.KeyguardSecurityModel; @@ -467,8 +468,7 @@ public class KeyguardBouncer { mKeyguardViewController.init(); mContainer.addView(mRoot, mContainer.getChildCount()); - mStatusBarHeight = mRoot.getResources().getDimensionPixelOffset( - com.android.systemui.R.dimen.status_bar_height); + mStatusBarHeight = SystemBarUtils.getStatusBarHeight(mContext); setVisibility(View.INVISIBLE); final WindowInsets rootInsets = mRoot.getRootWindowInsets(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java index fe154d232a88..03f3b0cab65c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java @@ -18,6 +18,7 @@ package com.android.systemui.statusbar.phone; import static com.android.systemui.DejankUtils.whitelistIpcs; import static com.android.systemui.ScreenDecorations.DisplayCutoutView.boundsFromDirection; +import static com.android.systemui.util.Utils.getStatusBarHeaderHeightKeyguard; import android.annotation.ColorInt; import android.content.Context; @@ -162,11 +163,8 @@ public class KeyguardStatusBarView extends RelativeLayout { } private void updateKeyguardStatusBarHeight() { - final int waterfallTop = - mDisplayCutout == null ? 0 : mDisplayCutout.getWaterfallInsets().top; MarginLayoutParams lp = (MarginLayoutParams) getLayoutParams(); - lp.height = getResources().getDimensionPixelSize( - R.dimen.status_bar_header_height_keyguard) + waterfallTop; + lp.height = getStatusBarHeaderHeightKeyguard(mContext); setLayoutParams(lp); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java index abee7a51f91f..570b0ca3564c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.phone; +import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS; import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS; @@ -101,7 +102,9 @@ public class LightBarController implements BatteryController.BatteryStateChangeC mNavigationMode = mode; }); - dumpManager.registerDumpable(getClass().getSimpleName(), this); + if (ctx.getDisplayId() == DEFAULT_DISPLAY) { + dumpManager.registerDumpable(getClass().getSimpleName(), this); + } } public void setNavigationBar(LightBarTransitionsController navigationBar) { @@ -298,4 +301,33 @@ public class LightBarController implements BatteryController.BatteryStateChangeC pw.println(); } } + + /** + * Injectable factory for creating a {@link LightBarController}. + */ + public static class Factory { + private final DarkIconDispatcher mDarkIconDispatcher; + private final BatteryController mBatteryController; + private final NavigationModeController mNavModeController; + private final DumpManager mDumpManager; + + @Inject + public Factory( + DarkIconDispatcher darkIconDispatcher, + BatteryController batteryController, + NavigationModeController navModeController, + DumpManager dumpManager) { + + mDarkIconDispatcher = darkIconDispatcher; + mBatteryController = batteryController; + mNavModeController = navModeController; + mDumpManager = dumpManager; + } + + /** Create an {@link LightBarController} */ + public LightBarController create(Context context) { + return new LightBarController(context, mDarkIconDispatcher, mBatteryController, + mNavModeController, mDumpManager); + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java index a7a249db5a83..233acfe601a7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java @@ -94,6 +94,7 @@ import com.android.internal.jank.InteractionJankMonitor; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.policy.ScreenDecorationsUtils; +import com.android.internal.policy.SystemBarUtils; import com.android.internal.util.LatencyTracker; import com.android.keyguard.KeyguardStatusView; import com.android.keyguard.KeyguardStatusViewController; @@ -443,7 +444,6 @@ public class NotificationPanelViewController extends PanelViewController { private ArrayList<Consumer<ExpandableNotificationRow>> mTrackingHeadsUpListeners = new ArrayList<>(); - private Runnable mVerticalTranslationListener; private HeadsUpAppearanceController mHeadsUpAppearanceController; private int mPanelAlpha; @@ -891,10 +891,8 @@ public class NotificationPanelViewController extends PanelViewController { super.loadDimens(); mFlingAnimationUtils = mFlingAnimationUtilsBuilder.get() .setMaxLengthSeconds(0.4f).build(); - mStatusBarMinHeight = mResources.getDimensionPixelSize( - com.android.internal.R.dimen.status_bar_height); - mStatusBarHeaderHeightKeyguard = mResources.getDimensionPixelSize( - R.dimen.status_bar_header_height_keyguard); + mStatusBarMinHeight = SystemBarUtils.getStatusBarHeight(mView.getContext()); + mStatusBarHeaderHeightKeyguard = Utils.getStatusBarHeaderHeightKeyguard(mView.getContext()); mQsPeekHeight = mResources.getDimensionPixelSize(R.dimen.qs_peek_height); mClockPositionAlgorithm.loadDimens(mResources); mQsFalsingThreshold = mResources.getDimensionPixelSize(R.dimen.qs_falsing_threshold); @@ -904,8 +902,7 @@ public class NotificationPanelViewController extends PanelViewController { R.dimen.keyguard_indication_bottom_padding); mShelfHeight = mResources.getDimensionPixelSize(R.dimen.notification_shelf_height); mDarkIconSize = mResources.getDimensionPixelSize(R.dimen.status_bar_icon_drawing_size_dark); - int statusbarHeight = mResources.getDimensionPixelSize( - com.android.internal.R.dimen.status_bar_height); + int statusbarHeight = SystemBarUtils.getStatusBarHeight(mView.getContext()); mHeadsUpInset = statusbarHeight + mResources.getDimensionPixelSize( R.dimen.heads_up_status_bar_padding); mDistanceForQSFullShadeTransition = mResources.getDimensionPixelSize( @@ -974,10 +971,8 @@ public class NotificationPanelViewController extends PanelViewController { } public void updateResources() { - mQuickQsOffsetHeight = mResources.getDimensionPixelSize( - com.android.internal.R.dimen.quick_qs_offset_height); - mSplitShadeStatusBarHeight = - mResources.getDimensionPixelSize(R.dimen.split_shade_header_height); + mQuickQsOffsetHeight = SystemBarUtils.getQuickQsOffsetHeight(mView.getContext()); + mSplitShadeStatusBarHeight = Utils.getSplitShadeStatusBarHeight(mView.getContext()); int qsWidth = mResources.getDimensionPixelSize(R.dimen.qs_panel_width); int panelWidth = mResources.getDimensionPixelSize(R.dimen.notification_panel_width); mShouldUseSplitNotificationShade = @@ -1003,6 +998,7 @@ public class NotificationPanelViewController extends PanelViewController { constraintSet.connect( R.id.notification_stack_scroller, START, R.id.qs_edge_guideline, START); + constraintSet.constrainHeight(R.id.split_shade_status_bar, mSplitShadeStatusBarHeight); } else { constraintSet.connect(R.id.qs_frame, END, PARENT_ID, END); constraintSet.connect(R.id.notification_stack_scroller, START, PARENT_ID, START); @@ -1012,6 +1008,7 @@ public class NotificationPanelViewController extends PanelViewController { constraintSet.setMargin(R.id.notification_stack_scroller, TOP, topMargin); constraintSet.setMargin(R.id.qs_frame, TOP, topMargin); constraintSet.applyTo(mNotificationContainerParent); + mAmbientState.setStackTopMargin(topMargin); mNotificationsQSContainerController.setSplitShadeEnabled(mShouldUseSplitNotificationShade); updateKeyguardStatusViewAlignment(/* animate= */false); @@ -1247,6 +1244,7 @@ public class NotificationPanelViewController extends PanelViewController { stackScrollerPadding = mClockPositionResult.stackScrollerPaddingExpanded; } + mSplitShadeHeaderController.setShadeExpandedFraction(getExpandedFraction()); mNotificationStackScrollLayoutController.setIntrinsicPadding(stackScrollerPadding); mKeyguardBottomArea.setAntiBurnInOffsetX(mClockPositionResult.clockX); @@ -1525,6 +1523,24 @@ public class NotificationPanelViewController extends PanelViewController { mNotificationStackScrollLayoutController.resetScrollPosition(); } + /** Collapses the panel. */ + public void collapsePanel(boolean animate, boolean delayed, float speedUpFactor) { + boolean waiting = false; + if (animate && !isFullyCollapsed()) { + collapse(delayed, speedUpFactor); + waiting = true; + } else { + resetViews(false /* animate */); + setExpandedFraction(0); // just in case + } + if (!waiting) { + // it's possible that nothing animated, so we replicate the termination + // conditions of panelExpansionChanged here + // TODO(b/200063118): This can likely go away in a future refactor CL. + mBar.updateState(STATE_CLOSED); + } + } + @Override public void collapse(boolean delayed, float speedUpFactor) { if (!canPanelBeCollapsed()) { @@ -2966,7 +2982,7 @@ public class NotificationPanelViewController extends PanelViewController { @Override protected void onExpandingFinished() { - super.onExpandingFinished(); + mScrimController.onExpandingFinished(); mNotificationStackScrollLayoutController.onExpansionStopped(); mHeadsUpManager.onExpandingFinished(); mConversationNotificationManager.onNotificationPanelExpandStateChanged(isFullyCollapsed()); @@ -3041,6 +3057,7 @@ public class NotificationPanelViewController extends PanelViewController { protected void onTrackingStarted() { mFalsingCollector.onTrackingStarted(!mKeyguardStateController.canDismissLockScreen()); super.onTrackingStarted(); + mScrimController.onTrackingStarted(); if (mQsFullyExpanded) { mQsExpandImmediate = true; if (!mShouldUseSplitNotificationShade) { @@ -3051,6 +3068,7 @@ public class NotificationPanelViewController extends PanelViewController { mAffordanceHelper.animateHideLeftRightIcon(); } mNotificationStackScrollLayoutController.onPanelTrackingStarted(); + cancelPendingPanelCollapse(); } @Override @@ -3240,8 +3258,7 @@ public class NotificationPanelViewController extends PanelViewController { @Override protected void onClosingFinished() { - super.onClosingFinished(); - resetHorizontalPanelPosition(); + mStatusBar.onClosingFinished(); setClosingWithAlphaFadeout(false); mMediaHierarchyManager.closeGuts(); } @@ -3251,47 +3268,6 @@ public class NotificationPanelViewController extends PanelViewController { mNotificationStackScrollLayoutController.forceNoOverlappingRendering(closing); } - /** - * Updates the horizontal position of the panel so it is positioned closer to the touch - * responsible for opening the panel. - * - * @param x the x-coordinate the touch event - */ - protected void updateHorizontalPanelPosition(float x) { - if (mNotificationStackScrollLayoutController.getWidth() * 1.75f > mView.getWidth() - || mShouldUseSplitNotificationShade) { - resetHorizontalPanelPosition(); - return; - } - float leftMost = mPositionMinSideMargin - + mNotificationStackScrollLayoutController.getWidth() / 2; - float - rightMost = - mView.getWidth() - mPositionMinSideMargin - - mNotificationStackScrollLayoutController.getWidth() / 2; - if (Math.abs(x - mView.getWidth() / 2) - < mNotificationStackScrollLayoutController.getWidth() / 4) { - x = mView.getWidth() / 2; - } - x = Math.min(rightMost, Math.max(leftMost, x)); - float - center = mNotificationStackScrollLayoutController.getLeft() - + mNotificationStackScrollLayoutController.getWidth() / 2; - setHorizontalPanelTranslation(x - center); - } - - private void resetHorizontalPanelPosition() { - setHorizontalPanelTranslation(0f); - } - - protected void setHorizontalPanelTranslation(float translation) { - mNotificationStackScrollLayoutController.setTranslationX(translation); - mQsFrame.setTranslationX(translation); - if (mVerticalTranslationListener != null) { - mVerticalTranslationListener.run(); - } - } - protected void updateExpandedHeight(float expandedHeight) { if (mTracking) { mNotificationStackScrollLayoutController @@ -3604,10 +3580,6 @@ public class NotificationPanelViewController extends PanelViewController { mTrackingHeadsUpListeners.remove(listener); } - public void setVerticalTranslationListener(Runnable verticalTranslationListener) { - mVerticalTranslationListener = verticalTranslationListener; - } - public void setHeadsUpAppearanceController( HeadsUpAppearanceController headsUpAppearanceController) { mHeadsUpAppearanceController = headsUpAppearanceController; @@ -3716,13 +3688,27 @@ public class NotificationPanelViewController extends PanelViewController { mNotificationStackScrollLayoutController.setScrollingEnabled(b); } + private Runnable mHideExpandedRunnable; + private final Runnable mMaybeHideExpandedRunnable = new Runnable() { + @Override + public void run() { + if (getExpansionFraction() == 0.0f) { + mView.post(mHideExpandedRunnable); + } + } + }; + /** * Initialize objects instead of injecting to avoid circular dependencies. + * + * @param hideExpandedRunnable a runnable to run when we need to hide the expanded panel. */ public void initDependencies( StatusBar statusBar, + Runnable hideExpandedRunnable, NotificationShelfController notificationShelfController) { setStatusBar(statusBar); + mHideExpandedRunnable = hideExpandedRunnable; mNotificationStackScrollLayoutController.setShelfController(notificationShelfController); mNotificationShelfController = notificationShelfController; mLockscreenShadeTransitionController.bindController(notificationShelfController); @@ -3779,6 +3765,45 @@ public class NotificationPanelViewController extends PanelViewController { private long mLastTouchDownTime = -1L; @Override + public boolean onTouchForwardedFromStatusBar(MotionEvent event) { + // TODO(b/202981994): Move the touch debugging in this method to a central location. + // (Right now, it's split between StatusBar and here.) + + // If panels aren't enabled, ignore the gesture and don't pass it down to the + // panel view. + if (!mCommandQueue.panelsEnabled()) { + if (event.getAction() == MotionEvent.ACTION_DOWN) { + Log.v( + TAG, + String.format( + "onTouchForwardedFromStatusBar: " + + "panel disabled, ignoring touch at (%d,%d)", + (int) event.getX(), + (int) event.getY() + ) + ); + } + return false; + } + + // If the view that would receive the touch is disabled, just have status bar eat + // the gesture. + if (event.getAction() == MotionEvent.ACTION_DOWN && !mView.isEnabled()) { + Log.v(TAG, + String.format( + "onTouchForwardedFromStatusBar: " + + "panel view disabled, eating touch at (%d,%d)", + (int) event.getX(), + (int) event.getY() + ) + ); + return true; + } + + return mView.dispatchTouchEvent(event); + } + + @Override public boolean onInterceptTouchEvent(MotionEvent event) { if (mBlockTouches || mQs.disallowPanelTouches()) { return false; @@ -3789,7 +3814,7 @@ public class NotificationPanelViewController extends PanelViewController { if (mStatusBar.isBouncerShowing()) { return true; } - if (mBar.panelEnabled() + if (mCommandQueue.panelsEnabled() && !mNotificationStackScrollLayoutController.isLongPressInProgress() && mHeadsUpTouchHelper.onInterceptTouchEvent(event)) { mMetricsLogger.count(COUNTER_PANEL_OPEN, 1); @@ -3875,7 +3900,6 @@ public class NotificationPanelViewController extends PanelViewController { } if (event.getActionMasked() == MotionEvent.ACTION_DOWN && isFullyCollapsed()) { mMetricsLogger.count(COUNTER_PANEL_OPEN, 1); - updateHorizontalPanelPosition(event.getX()); handled = true; } @@ -4353,9 +4377,16 @@ public class NotificationPanelViewController extends PanelViewController { } } } else { - mKeyguardStatusBarViewController.updateViewState( - /* alpha= */ 1f, - keyguardShowing ? View.VISIBLE : View.INVISIBLE); + final boolean animatingUnlockedShadeToKeyguard = oldState == SHADE + && statusBarState == KEYGUARD + && mUnlockedScreenOffAnimationController.isScreenOffAnimationPlaying(); + if (!animatingUnlockedShadeToKeyguard) { + // Only make the status bar visible if we're not animating the screen off, since + // we only want to be showing the clock/notifications during the animation. + mKeyguardStatusBarViewController.updateViewState( + /* alpha= */ 1f, + keyguardShowing ? View.VISIBLE : View.INVISIBLE); + } if (keyguardShowing && oldState != mBarState) { if (mQs != null) { mQs.hideImmediately(); @@ -4371,7 +4402,6 @@ public class NotificationPanelViewController extends PanelViewController { // The update needs to happen after the headerSlide in above, otherwise the translation // would reset maybeAnimateBottomAreaAlpha(); - resetHorizontalPanelPosition(); updateQsState(); mSplitShadeHeaderController.setShadeExpanded( mBarState == SHADE || mBarState == SHADE_LOCKED); @@ -4597,9 +4627,6 @@ public class NotificationPanelViewController extends PanelViewController { public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); mAffordanceHelper.onConfigurationChanged(); - if (newConfig.orientation != mLastOrientation) { - resetHorizontalPanelPosition(); - } mLastOrientation = newConfig.orientation; } } @@ -4618,6 +4645,11 @@ public class NotificationPanelViewController extends PanelViewController { } } + /** Removes any pending runnables that would collapse the panel. */ + public void cancelPendingPanelCollapse() { + mView.removeCallbacks(mMaybeHideExpandedRunnable); + } + private final PanelBar.PanelStateChangeListener mPanelStateChangeListener = new PanelBar.PanelStateChangeListener() { @@ -4632,6 +4664,14 @@ public class NotificationPanelViewController extends PanelViewController { if (state == STATE_OPEN && mCurrentState != state) { mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); } + if (state == STATE_OPENING) { + mStatusBar.makeExpandedVisible(false); + } + if (state == STATE_CLOSED) { + // Close the status bar in the next frame so we can show the end of the + // animation. + mView.post(mMaybeHideExpandedRunnable); + } mCurrentState = state; } }; @@ -4639,4 +4679,10 @@ public class NotificationPanelViewController extends PanelViewController { public PanelBar.PanelStateChangeListener getPanelStateChangeListener() { return mPanelStateChangeListener; } + + + /** Returns the handler that the status bar should forward touches to. */ + public PhoneStatusBarView.TouchEventHandler getStatusBarTouchEventHandler() { + return getTouchHandler()::onTouchForwardedFromStatusBar; + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java index 9d06d2bae8cb..36bd31b2efe3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java @@ -56,7 +56,6 @@ import com.android.systemui.statusbar.notification.stack.NotificationStackScroll import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.tuner.TunerService; -import com.android.systemui.util.InjectionInflationController; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -68,7 +67,6 @@ import javax.inject.Inject; */ public class NotificationShadeWindowViewController { private static final String TAG = "NotifShadeWindowVC"; - private final InjectionInflationController mInjectionInflationController; private final NotificationWakeUpCoordinator mCoordinator; private final PulseExpansionHandler mPulseExpansionHandler; private final DynamicPrivacyController mDynamicPrivacyController; @@ -116,7 +114,6 @@ public class NotificationShadeWindowViewController { @Inject public NotificationShadeWindowViewController( - InjectionInflationController injectionInflationController, NotificationWakeUpCoordinator coordinator, PulseExpansionHandler pulseExpansionHandler, DynamicPrivacyController dynamicPrivacyController, @@ -141,7 +138,6 @@ public class NotificationShadeWindowViewController { NotificationStackScrollLayoutController notificationStackScrollLayoutController, StatusBarKeyguardViewManager statusBarKeyguardViewManager, LockIconViewController lockIconViewController) { - mInjectionInflationController = injectionInflationController; mCoordinator = coordinator; mPulseExpansionHandler = pulseExpansionHandler; mDynamicPrivacyController = dynamicPrivacyController; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java index 310fe73df1ea..e90258db8571 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java @@ -25,7 +25,6 @@ import android.os.Bundle; import android.os.Parcelable; import android.util.AttributeSet; import android.util.Log; -import android.view.MotionEvent; import android.widget.FrameLayout; import androidx.annotation.Nullable; @@ -53,11 +52,18 @@ public abstract class PanelBar extends FrameLayout { public static final int STATE_OPENING = 1; public static final int STATE_OPEN = 2; - private PanelViewController mPanel; @Nullable private PanelStateChangeListener mPanelStateChangeListener; private int mState = STATE_CLOSED; private boolean mTracking; + /** Updates the panel state if necessary. */ + public void updateState(@PanelState int state) { + if (DEBUG) LOG("update state: %d -> %d", mState, state); + if (mState != state) { + go(state); + } + } + private void go(@PanelState int state) { if (DEBUG) LOG("go state: %d -> %d", mState, state); mState = state; @@ -97,54 +103,11 @@ public abstract class PanelBar extends FrameLayout { super.onFinishInflate(); } - /** Set the PanelViewController */ - public void setPanel(PanelViewController pv) { - mPanel = pv; - pv.setBar(this); - } - /** Sets the listener that will be notified of panel state changes. */ public void setPanelStateChangeListener(PanelStateChangeListener listener) { mPanelStateChangeListener = listener; } - public boolean panelEnabled() { - return true; - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - // Allow subclasses to implement enable/disable semantics - if (!panelEnabled()) { - if (event.getAction() == MotionEvent.ACTION_DOWN) { - Log.v(TAG, String.format("onTouch: all panels disabled, ignoring touch at (%d,%d)", - (int) event.getX(), (int) event.getY())); - } - return false; - } - - if (event.getAction() == MotionEvent.ACTION_DOWN) { - final PanelViewController panel = mPanel; - if (panel == null) { - // panel is not there, so we'll eat the gesture - Log.v(TAG, String.format("onTouch: no panel for touch at (%d,%d)", - (int) event.getX(), (int) event.getY())); - return true; - } - boolean enabled = panel.isEnabled(); - if (DEBUG) LOG("PanelBar.onTouch: state=%d ACTION_DOWN: panel %s %s", mState, panel, - (enabled ? "" : " (disabled)")); - if (!enabled) { - // panel is disabled, so we'll eat the gesture - Log.v(TAG, String.format( - "onTouch: panel (%s) is disabled, ignoring touch at (%d,%d)", - panel, (int) event.getX(), (int) event.getY())); - return true; - } - } - return mPanel == null || mPanel.getView().dispatchTouchEvent(event); - } - /** * @param frac the fraction from the expansion in [0, 1] * @param expanded whether the panel is currently expanded; this is independent from the @@ -162,7 +125,6 @@ public abstract class PanelBar extends FrameLayout { if (expanded) { if (mState == STATE_CLOSED) { go(STATE_OPENING); - onPanelPeeked(); } fullyClosed = false; fullyOpened = frac >= 1f; @@ -171,44 +133,16 @@ public abstract class PanelBar extends FrameLayout { go(STATE_OPEN); } else if (fullyClosed && !mTracking && mState != STATE_CLOSED) { go(STATE_CLOSED); - onPanelCollapsed(); } if (SPEW) LOG("panelExpansionChanged: end state=%d [%s%s ]", mState, fullyOpened?" fullyOpened":"", fullyClosed?" fullyClosed":""); } - public void collapsePanel(boolean animate, boolean delayed, float speedUpFactor) { - boolean waiting = false; - PanelViewController pv = mPanel; - if (animate && !pv.isFullyCollapsed()) { - pv.collapse(delayed, speedUpFactor); - waiting = true; - } else { - pv.resetViews(false /* animate */); - pv.setExpandedFraction(0); // just in case - } - if (DEBUG) LOG("collapsePanel: animate=%s waiting=%s", animate, waiting); - if (!waiting && mState != STATE_CLOSED) { - // it's possible that nothing animated, so we replicate the termination - // conditions of panelExpansionChanged here - go(STATE_CLOSED); - onPanelCollapsed(); - } - } - - public void onPanelPeeked() { - if (DEBUG) LOG("onPanelPeeked"); - } - public boolean isClosed() { return mState == STATE_CLOSED; } - public void onPanelCollapsed() { - if (DEBUG) LOG("onPanelCollapsed"); - } - public void onTrackingStarted() { mTracking = true; } @@ -217,14 +151,6 @@ public abstract class PanelBar extends FrameLayout { mTracking = false; } - public void onExpandingFinished() { - if (DEBUG) LOG("onExpandingFinished"); - } - - public void onClosingFinished() { - - } - /** An interface that will be notified of panel state changes. */ public interface PanelStateChangeListener { /** Called when the state changes. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java index c23577c523e3..e5296af86b81 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java @@ -185,10 +185,9 @@ public abstract class PanelViewController { protected final SysuiStatusBarStateController mStatusBarStateController; protected final AmbientState mAmbientState; protected final LockscreenGestureLogger mLockscreenGestureLogger; + private final TouchHandler mTouchHandler; - protected void onExpandingFinished() { - mBar.onExpandingFinished(); - } + protected abstract void onExpandingFinished(); protected void onExpandingStarted() { } @@ -226,6 +225,7 @@ public abstract class PanelViewController { mView = view; mStatusBarKeyguardViewManager = statusBarKeyguardViewManager; mLockscreenGestureLogger = lockscreenGestureLogger; + mTouchHandler = createTouchHandler(); mView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() { @Override public void onViewAttachedToWindow(View v) { @@ -238,7 +238,7 @@ public abstract class PanelViewController { }); mView.addOnLayoutChangeListener(createLayoutChangeListener()); - mView.setOnTouchListener(createTouchHandler()); + mView.setOnTouchListener(mTouchHandler); mView.setOnConfigurationChangedListener(createOnConfigurationChangedListener()); mResources = mView.getResources(); @@ -289,6 +289,10 @@ public abstract class PanelViewController { : mTouchSlop; } + protected TouchHandler getTouchHandler() { + return mTouchHandler; + } + private void addMovement(MotionEvent event) { // Add movement to velocity tracker using raw screen X and Y coordinates instead // of window coordinates because the window frame may be moving at the same time. @@ -392,6 +396,12 @@ public abstract class PanelViewController { expand = false; } else if (onKeyguard) { expand = true; + } else if (mKeyguardStateController.isKeyguardFadingAway()) { + // If we're in the middle of dismissing the keyguard, don't expand due to the + // cancelled gesture. Gesture cancellation during an unlock is expected in some + // situations, such keeping your finger down while swiping to unlock to an app + // that is locked in landscape (the rotation will cancel the touch event). + expand = false; } else { // If we get a cancel, put the shade back to the state it was in when the // gesture started @@ -448,6 +458,7 @@ public abstract class PanelViewController { protected void onTrackingStopped(boolean expand) { mTracking = false; mBar.onTrackingStopped(expand); + mStatusBar.onTrackingStopped(expand); updatePanelExpansionAndVisibility(); } @@ -455,6 +466,7 @@ public abstract class PanelViewController { endClosing(); mTracking = true; mBar.onTrackingStarted(); + mStatusBar.onTrackingStarted(); notifyExpandingStarted(); updatePanelExpansionAndVisibility(); } @@ -927,10 +939,7 @@ public abstract class PanelViewController { mView.removeCallbacks(mFlingCollapseRunnable); } - protected void onClosingFinished() { - mBar.onClosingFinished(); - } - + protected abstract void onClosingFinished(); protected void startUnlockHintAnimation() { @@ -1153,23 +1162,28 @@ public abstract class PanelViewController { return mView; } - public boolean isEnabled() { - return mView.isEnabled(); - } - public OnLayoutChangeListener createLayoutChangeListener() { return new OnLayoutChangeListener(); } - protected TouchHandler createTouchHandler() { - return new TouchHandler(); - } + protected abstract TouchHandler createTouchHandler(); protected OnConfigurationChangedListener createOnConfigurationChangedListener() { return new OnConfigurationChangedListener(); } - public class TouchHandler implements View.OnTouchListener { + public abstract class TouchHandler implements View.OnTouchListener { + /** + * Method called when a touch has occurred on {@link PhoneStatusBarView}. + * + * Touches that occur on the status bar view may have ramifications for the notification + * panel (e.g. a touch that pulls down the shade could start on the status bar), so we need + * to notify the panel controller when these touches occur. + * + * Returns true if the event was handled and false otherwise. + */ + public abstract boolean onTouchForwardedFromStatusBar(MotionEvent event); + public boolean onInterceptTouchEvent(MotionEvent event) { if (mInstantExpanding || !mNotificationsDragEnabled || mTouchDisabled || (mMotionAborted && event.getActionMasked() != MotionEvent.ACTION_DOWN)) { @@ -1435,4 +1449,8 @@ public abstract class PanelViewController { private void cancelJankMonitoring(int cuj) { InteractionJankMonitor.getInstance().cancel(cuj); } + + protected float getExpansionFraction() { + return mExpandedFraction; + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java index 7b110a0ec01f..d19ed28bd823 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java @@ -604,8 +604,7 @@ public class PhoneStatusBarPolicy @Override public void onUserSetupChanged() { - boolean userSetup = mProvisionedController.isUserSetup( - mProvisionedController.getCurrentUser()); + boolean userSetup = mProvisionedController.isCurrentUserSetup(); if (mCurrentUserSetup == userSetup) return; mCurrentUserSetup = userSetup; updateAlarm(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java index 150d9c8fcce6..883313bdc096 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java @@ -24,7 +24,6 @@ import android.content.res.Configuration; import android.graphics.Point; import android.graphics.Rect; import android.util.AttributeSet; -import android.util.EventLog; import android.util.Log; import android.util.Pair; import android.view.DisplayCutout; @@ -36,8 +35,8 @@ import android.view.WindowInsets; import android.view.accessibility.AccessibilityEvent; import android.widget.LinearLayout; +import com.android.internal.policy.SystemBarUtils; import com.android.systemui.Dependency; -import com.android.systemui.EventLogTags; import com.android.systemui.R; import com.android.systemui.plugins.DarkIconDispatcher; import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver; @@ -55,14 +54,6 @@ public class PhoneStatusBarView extends PanelBar { StatusBar mBar; private ScrimController mScrimController; - private Runnable mHideExpandedRunnable = new Runnable() { - @Override - public void run() { - if (mPanelFraction == 0.0f) { - mBar.makeExpandedInvisible(); - } - } - }; private DarkReceiver mBattery; private DarkReceiver mClock; private int mRotationOrientation = -1; @@ -76,15 +67,12 @@ public class PhoneStatusBarView extends PanelBar { @Nullable private List<StatusBar.ExpansionChangedListener> mExpansionChangedListeners; @Nullable - private PanelExpansionStateChangedListener mPanelExpansionStateChangedListener; - - private PanelEnabledProvider mPanelEnabledProvider; + private TouchEventHandler mTouchEventHandler; /** * Draw this many pixels into the left/right side of the cutout to optimally use the space */ private int mCutoutSideNudge = 0; - private boolean mHeadsUpVisible; public PhoneStatusBarView(Context context, AttributeSet attrs) { super(context, attrs); @@ -100,8 +88,8 @@ public class PhoneStatusBarView extends PanelBar { mExpansionChangedListeners = listeners; } - void setPanelExpansionStateChangedListener(PanelExpansionStateChangedListener listener) { - mPanelExpansionStateChangedListener = listener; + void setTouchEventHandler(TouchEventHandler handler) { + mTouchEventHandler = handler; } public void setScrimController(ScrimController scrimController) { @@ -178,15 +166,6 @@ public class PhoneStatusBarView extends PanelBar { } @Override - public boolean panelEnabled() { - if (mPanelEnabledProvider == null) { - Log.e(TAG, "panelEnabledProvider is null; defaulting to super class."); - return super.panelEnabled(); - } - return mPanelEnabledProvider.panelEnabled(); - } - - @Override public boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) { if (super.onRequestSendAccessibilityEventInternal(child, event)) { // The status bar is very small so augment the view that the user is touching @@ -202,79 +181,31 @@ public class PhoneStatusBarView extends PanelBar { } @Override - public void onPanelPeeked() { - super.onPanelPeeked(); - mBar.makeExpandedVisible(false); - } - - @Override - public void onPanelCollapsed() { - super.onPanelCollapsed(); - // Close the status bar in the next frame so we can show the end of the animation. - post(mHideExpandedRunnable); - } - - public void removePendingHideExpandedRunnables() { - removeCallbacks(mHideExpandedRunnable); - } - - @Override public boolean onTouchEvent(MotionEvent event) { - boolean barConsumedEvent = mBar.interceptTouchEvent(event); - - if (DEBUG_GESTURES) { - if (event.getActionMasked() != MotionEvent.ACTION_MOVE) { - EventLog.writeEvent(EventLogTags.SYSUI_PANELBAR_TOUCH, - event.getActionMasked(), (int) event.getX(), (int) event.getY(), - barConsumedEvent ? 1 : 0); - } + mBar.onTouchEvent(event); + if (mTouchEventHandler == null) { + Log.w( + TAG, + String.format( + "onTouch: No touch handler provided; eating gesture at (%d,%d)", + (int) event.getX(), + (int) event.getY() + ) + ); + return true; } - - return barConsumedEvent || super.onTouchEvent(event); - } - - @Override - public void onTrackingStarted() { - super.onTrackingStarted(); - mBar.onTrackingStarted(); - mScrimController.onTrackingStarted(); - removePendingHideExpandedRunnables(); - } - - @Override - public void onClosingFinished() { - super.onClosingFinished(); - mBar.onClosingFinished(); - } - - @Override - public void onTrackingStopped(boolean expand) { - super.onTrackingStopped(expand); - mBar.onTrackingStopped(expand); - } - - @Override - public void onExpandingFinished() { - super.onExpandingFinished(); - mScrimController.onExpandingFinished(); + return mTouchEventHandler.handleTouchEvent(event); } @Override public boolean onInterceptTouchEvent(MotionEvent event) { - return mBar.interceptTouchEvent(event) || super.onInterceptTouchEvent(event); + mBar.onTouchEvent(event); + return super.onInterceptTouchEvent(event); } @Override public void panelExpansionChanged(float frac, boolean expanded) { super.panelExpansionChanged(frac, expanded); - if ((frac == 0 || frac == 1)) { - if (mPanelExpansionStateChangedListener != null) { - mPanelExpansionStateChangedListener.onPanelExpansionStateChanged(); - } else { - Log.w(TAG, "No PanelExpansionStateChangedListener provided."); - } - } - if (mExpansionChangedListeners != null) { for (StatusBar.ExpansionChangedListener listener : mExpansionChangedListeners) { listener.onExpansionChanged(frac, expanded); @@ -282,11 +213,6 @@ public class PhoneStatusBarView extends PanelBar { } } - /** Set the {@link PanelEnabledProvider} to use. */ - public void setPanelEnabledProvider(PanelEnabledProvider panelEnabledProvider) { - mPanelEnabledProvider = panelEnabledProvider; - } - public void updateResources() { mCutoutSideNudge = getResources().getDimensionPixelSize( R.dimen.display_cutout_margin_consumption); @@ -298,7 +224,7 @@ public class PhoneStatusBarView extends PanelBar { final int waterfallTopInset = mDisplayCutout == null ? 0 : mDisplayCutout.getWaterfallInsets().top; ViewGroup.LayoutParams layoutParams = getLayoutParams(); - mStatusBarHeight = getResources().getDimensionPixelSize(R.dimen.status_bar_height); + mStatusBarHeight = SystemBarUtils.getStatusBarHeight(mContext); layoutParams.height = mStatusBarHeight - waterfallTopInset; int statusBarPaddingTop = getResources().getDimensionPixelSize( @@ -366,15 +292,14 @@ public class PhoneStatusBarView extends PanelBar { getPaddingBottom()); } - /** An interface that will provide whether panel is enabled. */ - interface PanelEnabledProvider { - /** Returns true if the panel is enabled and false otherwise. */ - boolean panelEnabled(); - } - - /** A listener that will be notified when a panel's expansion state may have changed. */ - public interface PanelExpansionStateChangedListener { - /** Called when a panel's expansion state may have changed. */ - void onPanelExpansionStateChanged(); + /** + * A handler repsonsible for all touch event handling on the status bar. + * + * The handler will be notified each time {@link this#onTouchEvent} is called, and the return + * value from the handler will be returned from {@link this#onTouchEvent}. + **/ + public interface TouchEventHandler { + /** Called each time {@link this#onTouchEvent} is called. */ + boolean handleTouchEvent(MotionEvent event); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt index 4c0332a75df1..de21e73f8100 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt @@ -18,29 +18,28 @@ package com.android.systemui.statusbar.phone import android.graphics.Point import android.view.View import android.view.ViewGroup +import android.view.ViewTreeObserver import com.android.systemui.R import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator import com.android.systemui.statusbar.CommandQueue +import com.android.systemui.unfold.UNFOLD_STATUS_BAR +import com.android.systemui.unfold.config.UnfoldTransitionConfig +import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider import com.android.systemui.util.ViewController +import javax.inject.Inject +import javax.inject.Named +import dagger.Lazy /** Controller for [PhoneStatusBarView]. */ -class PhoneStatusBarViewController( +class PhoneStatusBarViewController private constructor( view: PhoneStatusBarView, - commandQueue: CommandQueue, - statusBarMoveFromCenterAnimationController: StatusBarMoveFromCenterAnimationController?, - panelExpansionStateChangedListener: PhoneStatusBarView.PanelExpansionStateChangedListener, + @Named(UNFOLD_STATUS_BAR) private val progressProvider: ScopedUnfoldTransitionProgressProvider?, + private val moveFromCenterAnimationController: StatusBarMoveFromCenterAnimationController?, + touchEventHandler: PhoneStatusBarView.TouchEventHandler, ) : ViewController<PhoneStatusBarView>(view) { - override fun onViewAttached() {} - override fun onViewDetached() {} - - init { - mView.setPanelEnabledProvider { - commandQueue.panelsEnabled() - } - mView.setPanelExpansionStateChangedListener(panelExpansionStateChangedListener) - - statusBarMoveFromCenterAnimationController?.let { animationController -> + override fun onViewAttached() { + moveFromCenterAnimationController?.let { animationController -> val statusBarLeftSide: View = mView.findViewById(R.id.status_bar_left_side) val systemIconArea: ViewGroup = mView.findViewById(R.id.system_icon_area) @@ -50,15 +49,33 @@ class PhoneStatusBarViewController( systemIconArea ) - animationController.init(viewsToAnimate, viewCenterProvider) + mView.viewTreeObserver.addOnPreDrawListener(object : + ViewTreeObserver.OnPreDrawListener { + override fun onPreDraw(): Boolean { + animationController.onViewsReady(viewsToAnimate, viewCenterProvider) + mView.viewTreeObserver.removeOnPreDrawListener(this) + return true + } + }) mView.addOnLayoutChangeListener { _, left, _, right, _, oldLeft, _, oldRight, _ -> val widthChanged = right - left != oldRight - oldLeft if (widthChanged) { - statusBarMoveFromCenterAnimationController.onStatusBarWidthChanged() + moveFromCenterAnimationController.onStatusBarWidthChanged() } } } + + progressProvider?.setReadyToHandleTransition(true) + } + + override fun onViewDetached() { + progressProvider?.setReadyToHandleTransition(false) + moveFromCenterAnimationController?.onViewDetached() + } + + init { + mView.setTouchEventHandler(touchEventHandler) } fun setImportantForAccessibility(mode: Int) { @@ -96,4 +113,23 @@ class PhoneStatusBarViewController( outPoint.y = viewY + view.height / 2 } } + + class Factory @Inject constructor( + @Named(UNFOLD_STATUS_BAR) + private val progressProvider: Lazy<ScopedUnfoldTransitionProgressProvider>, + private val moveFromCenterController: Lazy<StatusBarMoveFromCenterAnimationController>, + private val unfoldConfig: UnfoldTransitionConfig, + ) { + fun create( + view: PhoneStatusBarView, + touchEventHandler: PhoneStatusBarView.TouchEventHandler + ): PhoneStatusBarViewController { + return PhoneStatusBarViewController( + view, + if (unfoldConfig.isEnabled) progressProvider.get() else null, + if (unfoldConfig.isEnabled) moveFromCenterController.get() else null, + touchEventHandler + ) + } + } } 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 a5cea06ad893..1921357ddf7c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -47,7 +47,7 @@ import com.android.settingslib.Utils; import com.android.systemui.DejankUtils; import com.android.systemui.Dumpable; import com.android.systemui.R; -import com.android.systemui.animation.Interpolators; +import com.android.systemui.animation.ShadeInterpolation; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dock.DockManager; @@ -579,8 +579,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump if (isNaN(expansionFraction)) { return; } - expansionFraction = Interpolators - .getNotificationScrimAlpha(expansionFraction, false /* notification */); + expansionFraction = ShadeInterpolation.getNotificationScrimAlpha(expansionFraction); boolean qsBottomVisible = qsPanelBottomY > 0; if (mQsExpansion != expansionFraction || mQsBottomVisible != qsBottomVisible) { mQsExpansion = expansionFraction; @@ -675,6 +674,12 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump } mInFrontAlpha = 0; } + } else if (mState == ScrimState.AUTH_SCRIMMED_SHADE) { + float behindFraction = getInterpolatedFraction(); + behindFraction = (float) Math.pow(behindFraction, 0.8f); + + mBehindAlpha = behindFraction * mDefaultScrimAlpha; + mNotificationsAlpha = mBehindAlpha; } else if (mState == ScrimState.KEYGUARD || mState == ScrimState.SHADE_LOCKED || mState == ScrimState.PULSING) { Pair<Integer, Float> result = calculateBackStateForState(mState); @@ -915,8 +920,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump } private float getInterpolatedFraction() { - return Interpolators.getNotificationScrimAlpha( - mPanelExpansionFraction, false /* notification */); + return ShadeInterpolation.getNotificationScrimAlpha(mPanelExpansionFraction); } private void setScrimAlpha(ScrimView scrim, float alpha) { 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 850b98691e1b..9246c0e73289 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java @@ -87,6 +87,17 @@ public enum ScrimState { } }, + AUTH_SCRIMMED_SHADE { + @Override + public void prepare(ScrimState previousState) { + // notif & behind scrim alpha values are determined by ScrimController#applyState + // based on the shade expansion + + mFrontTint = Color.BLACK; + mFrontAlpha = .66f; + } + }, + AUTH_SCRIMMED { @Override public void prepare(ScrimState previousState) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeControllerImpl.java index 768222d34862..a54251a46901 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeControllerImpl.java @@ -128,7 +128,8 @@ public class ShadeControllerImpl implements ShadeController { mNotificationShadeWindowController.setNotificationShadeFocusable(false); getStatusBar().getNotificationShadeWindowViewController().cancelExpandHelper(); - getStatusBarView().collapsePanel(true /* animate */, delayed, speedUpFactor); + getNotificationPanelViewController() + .collapsePanel(true /* animate */, delayed, speedUpFactor); } else if (mBubblesOptional.isPresent()) { mBubblesOptional.get().collapseStack(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt index 4b7fe4e7ea29..a7ecd0619d26 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt @@ -18,6 +18,7 @@ package com.android.systemui.statusbar.phone import android.view.View import com.android.systemui.R +import com.android.systemui.animation.ShadeInterpolation import com.android.systemui.battery.BatteryMeterView import com.android.systemui.battery.BatteryMeterViewController import com.android.systemui.flags.FeatureFlags @@ -53,6 +54,14 @@ class SplitShadeHeaderController @Inject constructor( updateVisibility() } + var shadeExpandedFraction = -1f + set(value) { + if (visible && field != value) { + statusBar.alpha = ShadeInterpolation.getContentAlpha(value) + field = value + } + } + init { batteryMeterViewController.init() val batteryIcon: BatteryMeterView = statusBar.findViewById(R.id.batteryRemainingIcon) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 16f67bcf5f90..bc50893d9a64 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -233,6 +233,7 @@ import com.android.systemui.tuner.TunerService; import com.android.systemui.unfold.UnfoldLightRevealOverlayAnimation; import com.android.systemui.unfold.UnfoldTransitionWallpaperController; import com.android.systemui.unfold.config.UnfoldTransitionConfig; +import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider; import com.android.systemui.util.WallpaperController; import com.android.systemui.util.concurrency.DelayableExecutor; import com.android.systemui.util.concurrency.MessageRouter; @@ -525,6 +526,7 @@ public class StatusBar extends SystemUI implements private QSPanelController mQSPanelController; private final OperatorNameViewController.Factory mOperatorNameViewControllerFactory; + private final PhoneStatusBarViewController.Factory mPhoneStatusBarViewControllerFactory; KeyguardIndicationController mKeyguardIndicationController; private View mReportRejectedTouch; @@ -543,8 +545,8 @@ public class StatusBar extends SystemUI implements private final FeatureFlags mFeatureFlags; private final UnfoldTransitionConfig mUnfoldTransitionConfig; private final Lazy<UnfoldLightRevealOverlayAnimation> mUnfoldLightRevealOverlayAnimation; + private final Lazy<NaturalRotationUnfoldProgressProvider> mNaturalUnfoldProgressProvider; private final Lazy<UnfoldTransitionWallpaperController> mUnfoldWallpaperController; - private final Lazy<StatusBarMoveFromCenterAnimationController> mMoveFromCenterAnimation; private final WallpaperController mWallpaperController; private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController; private final MessageRouter mMessageRouter; @@ -772,6 +774,7 @@ public class StatusBar extends SystemUI implements ExtensionController extensionController, UserInfoControllerImpl userInfoControllerImpl, OperatorNameViewController.Factory operatorNameViewControllerFactory, + PhoneStatusBarViewController.Factory phoneStatusBarViewControllerFactory, PhoneStatusBarPolicy phoneStatusBarPolicy, KeyguardIndicationController keyguardIndicationController, DemoModeController demoModeController, @@ -782,7 +785,7 @@ public class StatusBar extends SystemUI implements UnfoldTransitionConfig unfoldTransitionConfig, Lazy<UnfoldLightRevealOverlayAnimation> unfoldLightRevealOverlayAnimation, Lazy<UnfoldTransitionWallpaperController> unfoldTransitionWallpaperController, - Lazy<StatusBarMoveFromCenterAnimationController> statusBarUnfoldAnimationController, + Lazy<NaturalRotationUnfoldProgressProvider> naturalRotationUnfoldProgressProvider, WallpaperController wallpaperController, OngoingCallController ongoingCallController, SystemStatusAnimationScheduler animationScheduler, @@ -812,6 +815,7 @@ public class StatusBar extends SystemUI implements mKeyguardStateController = keyguardStateController; mHeadsUpManager = headsUpManagerPhone; mOperatorNameViewControllerFactory = operatorNameViewControllerFactory; + mPhoneStatusBarViewControllerFactory = phoneStatusBarViewControllerFactory; mKeyguardIndicationController = keyguardIndicationController; mStatusBarTouchableRegionManager = statusBarTouchableRegionManager; mDynamicPrivacyController = dynamicPrivacyController; @@ -879,9 +883,9 @@ public class StatusBar extends SystemUI implements mBrightnessSliderFactory = brightnessSliderFactory; mUnfoldTransitionConfig = unfoldTransitionConfig; mUnfoldLightRevealOverlayAnimation = unfoldLightRevealOverlayAnimation; + mNaturalUnfoldProgressProvider = naturalRotationUnfoldProgressProvider; mUnfoldWallpaperController = unfoldTransitionWallpaperController; mWallpaperController = wallpaperController; - mMoveFromCenterAnimation = statusBarUnfoldAnimationController; mOngoingCallController = ongoingCallController; mAnimationScheduler = animationScheduler; mStatusBarLocationPublisher = locationPublisher; @@ -902,6 +906,7 @@ public class StatusBar extends SystemUI implements mExpansionChangedListeners = new ArrayList<>(); addExpansionChangedListener( (expansion, expanded) -> mScrimController.setRawPanelExpansionFraction(expansion)); + addExpansionChangedListener(this::onPanelExpansionChanged); mBubbleExpandListener = (isExpanding, key) -> mContext.getMainExecutor().execute(() -> { @@ -1076,6 +1081,7 @@ public class StatusBar extends SystemUI implements if (mUnfoldTransitionConfig.isEnabled()) { mUnfoldLightRevealOverlayAnimation.get().init(); mUnfoldWallpaperController.get().init(); + mNaturalUnfoldProgressProvider.get().init(); } mPluginManager.addPluginListener( @@ -1167,7 +1173,6 @@ public class StatusBar extends SystemUI implements PhoneStatusBarView oldStatusBarView = mStatusBarView; mStatusBarView = (PhoneStatusBarView) statusBarFragment.getView(); mStatusBarView.setBar(this); - mStatusBarView.setPanel(mNotificationPanelViewController); mStatusBarView.setPanelStateChangeListener( mNotificationPanelViewController.getPanelStateChangeListener()); mStatusBarView.setScrimController(mScrimController); @@ -1176,16 +1181,11 @@ public class StatusBar extends SystemUI implements sendInitialExpansionAmount(listener); } - StatusBarMoveFromCenterAnimationController moveFromCenterAnimation = null; - if (mUnfoldTransitionConfig.isEnabled()) { - moveFromCenterAnimation = mMoveFromCenterAnimation.get(); - } - mPhoneStatusBarViewController = - new PhoneStatusBarViewController( - mStatusBarView, - mCommandQueue, - moveFromCenterAnimation, - this::onPanelExpansionStateChanged); + mNotificationPanelViewController.setBar(mStatusBarView); + + mPhoneStatusBarViewController = mPhoneStatusBarViewControllerFactory + .create(mStatusBarView, mNotificationPanelViewController + .getStatusBarTouchEventHandler()); mPhoneStatusBarViewController.init(); mBatteryMeterViewController = new BatteryMeterViewController( @@ -1216,7 +1216,7 @@ public class StatusBar extends SystemUI implements // TODO (b/136993073) Separate notification shade and status bar mHeadsUpAppearanceController = new HeadsUpAppearanceController( mNotificationIconAreaController, mHeadsUpManager, - mStackScroller.getController(), + mStackScrollerController, mStatusBarStateController, mKeyguardBypassController, mKeyguardStateController, mWakeUpCoordinator, mCommandQueue, mNotificationPanelViewController, mStatusBarView); @@ -1316,6 +1316,7 @@ public class StatusBar extends SystemUI implements mNotificationPanelViewController.initDependencies( this, + this::makeExpandedInvisible, mNotificationShelfController); BackDropView backdrop = mNotificationShadeWindowView.findViewById(R.id.backdrop); @@ -1453,12 +1454,14 @@ public class StatusBar extends SystemUI implements } } - private void onPanelExpansionStateChanged() { - if (getNavigationBarView() != null) { - getNavigationBarView().onStatusBarPanelStateChanged(); - } - if (getNotificationPanelViewController() != null) { - getNotificationPanelViewController().updateSystemUiStateFlags(); + private void onPanelExpansionChanged(float frac, boolean expanded) { + if (frac == 0 || frac == 1) { + if (getNavigationBarView() != null) { + getNavigationBarView().onStatusBarPanelStateChanged(); + } + if (getNotificationPanelViewController() != null) { + getNotificationPanelViewController().updateSystemUiStateFlags(); + } } } @@ -2157,7 +2160,8 @@ public class StatusBar extends SystemUI implements public void animateCollapseQuickSettings() { if (mState == StatusBarState.SHADE) { - mStatusBarView.collapsePanel(true, false /* delayed */, 1.0f /* speedUpFactor */); + mNotificationPanelViewController.collapsePanel( + true, false /* delayed */, 1.0f /* speedUpFactor */); } } @@ -2170,7 +2174,7 @@ public class StatusBar extends SystemUI implements } // Ensure the panel is fully collapsed (just in case; bug 6765842, 7260868) - mStatusBarView.collapsePanel(/*animate=*/ false, false /* delayed*/, + mNotificationPanelViewController.collapsePanel(/*animate=*/ false, false /* delayed*/, 1.0f /* speedUpFactor */); mNotificationPanelViewController.closeQs(); @@ -2204,7 +2208,10 @@ public class StatusBar extends SystemUI implements } } - public boolean interceptTouchEvent(MotionEvent event) { + /** Called when a touch event occurred on {@link PhoneStatusBarView}. */ + public void onTouchEvent(MotionEvent event) { + // TODO(b/202981994): Move this touch debugging to a central location. (Right now, it's + // split between NotificationPanelViewController and here.) if (DEBUG_GESTURES) { if (event.getActionMasked() != MotionEvent.ACTION_MOVE) { EventLog.writeEvent(EventLogTags.SYSUI_STATUSBAR_TOUCH, @@ -2236,7 +2243,6 @@ public class StatusBar extends SystemUI implements event.getAction() == MotionEvent.ACTION_CANCEL; setInteracting(StatusBarManager.WINDOW_STATUS_BAR, !upOrCancel || mExpandedVisible); } - return false; } boolean isSameStatusBarState(int state) { @@ -3292,6 +3298,9 @@ public class StatusBar extends SystemUI implements final boolean lockDarkText = mColorExtractor.getNeutralColors().supportsDarkText(); final int themeResId = lockDarkText ? R.style.Theme_SystemUI_LightWallpaper : R.style.Theme_SystemUI; + if (mContext.getThemeResId() == themeResId) { + return; + } mContext.setTheme(themeResId); mConfigurationController.notifyThemeChanged(); } @@ -3834,7 +3843,11 @@ public class StatusBar extends SystemUI implements mScrimController.setLaunchingAffordanceWithPreview(launchingAffordanceWithPreview); if (mStatusBarKeyguardViewManager.isShowingAlternateAuth()) { - mScrimController.transitionTo(ScrimState.AUTH_SCRIMMED); + if (mState == StatusBarState.SHADE || mState == StatusBarState.SHADE_LOCKED) { + mScrimController.transitionTo(ScrimState.AUTH_SCRIMMED_SHADE); + } else { + mScrimController.transitionTo(ScrimState.AUTH_SCRIMMED); + } } else if (mBouncerShowing) { // Bouncer needs the front scrim when it's on top of an activity, // tapping on a notification, editing QS or being dismissed by @@ -4325,10 +4338,9 @@ public class StatusBar extends SystemUI implements private final DeviceProvisionedListener mUserSetupObserver = new DeviceProvisionedListener() { @Override public void onUserSetupChanged() { - final boolean userSetup = mDeviceProvisionedController.isUserSetup( - mDeviceProvisionedController.getCurrentUser()); - Log.d(TAG, "mUserSetupObserver - DeviceProvisionedListener called for user " - + mDeviceProvisionedController.getCurrentUser()); + final boolean userSetup = mDeviceProvisionedController.isCurrentUserSetup(); + Log.d(TAG, "mUserSetupObserver - DeviceProvisionedListener called for " + + "current user"); if (MULTIUSER_DEBUG) { Log.d(TAG, String.format("User setup changed: userSetup=%s mUserSetup=%s", userSetup, mUserSetup)); @@ -4457,7 +4469,7 @@ public class StatusBar extends SystemUI implements mNavigationBarController.touchAutoDim(mDisplayId); Trace.beginSection("StatusBar#updateKeyguardState"); if (mState == StatusBarState.KEYGUARD && mStatusBarView != null) { - mStatusBarView.removePendingHideExpandedRunnables(); + mNotificationPanelViewController.cancelPendingPanelCollapse(); } updateDozingState(); checkBarModes(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacks.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacks.java index 5301b2571534..bb1daa252cdf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacks.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacks.java @@ -536,7 +536,7 @@ public class StatusBarCommandQueueCallbacks implements CommandQueue.Callbacks { } if (mStatusBar.getStatusBarView() != null) { if (!showing && mStatusBarStateController.getState() == StatusBarState.SHADE) { - mStatusBar.getStatusBarView().collapsePanel( + mNotificationPanelViewController.collapsePanel( false /* animate */, false /* delayed */, 1.0f /* speedUpFactor */); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt index 98be77dfa421..16d7f983d0f3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt @@ -25,6 +25,7 @@ import android.view.DisplayCutout import android.view.View.LAYOUT_DIRECTION_RTL import android.view.WindowMetrics import androidx.annotation.VisibleForTesting +import com.android.internal.policy.SystemBarUtils import com.android.systemui.Dumpable import com.android.systemui.R import com.android.systemui.dagger.SysUISingleton @@ -174,11 +175,16 @@ class StatusBarContentInsetsProvider @Inject constructor( targetRotation, dc, context.resources.configuration.windowConfiguration.maxBounds, - rotatedResources.getDimensionPixelSize(R.dimen.status_bar_height), + SystemBarUtils.getStatusBarHeight(context), minLeft, minRight) } + fun getStatusBarPaddingTop(@Rotation rotation: Int? = null): Int { + val res = rotation?.let { it -> getResourcesForRotation(it, context) } ?: context.resources + return res.getDimensionPixelSize(R.dimen.status_bar_padding_top) + } + override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) { insetsCache.snapshot().forEach { (key, rect) -> pw.println("$key -> $rect") diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationController.kt index 8af03aa2a3be..8ef186c316f9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationController.kt @@ -20,43 +20,54 @@ import android.view.WindowManager import com.android.systemui.dagger.SysUISingleton import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator.ViewCenterProvider -import com.android.systemui.unfold.UnfoldTransitionProgressProvider +import com.android.systemui.unfold.UNFOLD_STATUS_BAR import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener +import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider import javax.inject.Inject +import javax.inject.Named @SysUISingleton class StatusBarMoveFromCenterAnimationController @Inject constructor( - private val unfoldTransitionProgressProvider: UnfoldTransitionProgressProvider, - private val windowManager: WindowManager + @Named(UNFOLD_STATUS_BAR) private val progressProvider: ScopedUnfoldTransitionProgressProvider, + private val windowManager: WindowManager, ) { - private lateinit var moveFromCenterAnimator: UnfoldMoveFromCenterAnimator + private val transitionListener = TransitionListener() + private var moveFromCenterAnimator: UnfoldMoveFromCenterAnimator? = null - fun init(viewsToAnimate: Array<View>, viewCenterProvider: ViewCenterProvider) { + fun onViewsReady(viewsToAnimate: Array<View>, viewCenterProvider: ViewCenterProvider) { moveFromCenterAnimator = UnfoldMoveFromCenterAnimator(windowManager, viewCenterProvider = viewCenterProvider) - unfoldTransitionProgressProvider.addCallback(object : TransitionProgressListener { - override fun onTransitionStarted() { - moveFromCenterAnimator.updateDisplayProperties() + moveFromCenterAnimator?.updateDisplayProperties() - viewsToAnimate.forEach { - moveFromCenterAnimator.registerViewForAnimation(it) - } - } + viewsToAnimate.forEach { + moveFromCenterAnimator?.registerViewForAnimation(it) + } - override fun onTransitionFinished() { - moveFromCenterAnimator.onTransitionFinished() - moveFromCenterAnimator.clearRegisteredViews() - } + progressProvider.addCallback(transitionListener) + } - override fun onTransitionProgress(progress: Float) { - moveFromCenterAnimator.onTransitionProgress(progress) - } - }) + fun onViewDetached() { + progressProvider.removeCallback(transitionListener) + moveFromCenterAnimator?.clearRegisteredViews() + moveFromCenterAnimator = null } fun onStatusBarWidthChanged() { - moveFromCenterAnimator.updateViewPositions() + moveFromCenterAnimator?.updateDisplayProperties() + moveFromCenterAnimator?.updateViewPositions() + } + + private inner class TransitionListener : TransitionProgressListener { + override fun onTransitionProgress(progress: Float) { + moveFromCenterAnimator?.onTransitionProgress(progress) + } + + override fun onTransitionFinished() { + // Reset translations when transition is stopped/cancelled + // (e.g. the transition could be cancelled mid-way when rotating the screen) + moveFromCenterAnimator?.onTransitionProgress(1f) + } } } 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 eb405e9bdea3..b742394b18a5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java @@ -29,6 +29,7 @@ import android.view.ViewTreeObserver; import android.view.ViewTreeObserver.OnComputeInternalInsetsListener; import android.view.WindowInsets; +import com.android.internal.policy.SystemBarUtils; import com.android.systemui.Dumpable; import com.android.systemui.R; import com.android.systemui.ScreenDecorations; @@ -172,8 +173,7 @@ public final class StatusBarTouchableRegionManager implements Dumpable { Resources resources = mContext.getResources(); mDisplayCutoutTouchableRegionSize = resources.getDimensionPixelSize( com.android.internal.R.dimen.display_cutout_touchable_region_size); - mStatusBarHeight = - resources.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height); + mStatusBarHeight = SystemBarUtils.getStatusBarHeight(mContext); } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java index 235a8e85a223..9d2dbc12c97d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java @@ -40,6 +40,7 @@ import android.view.Surface; import android.view.ViewGroup; import android.view.WindowManager; +import com.android.internal.policy.SystemBarUtils; import com.android.systemui.R; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; @@ -86,8 +87,7 @@ public class StatusBarWindowController { mResources = resources; if (mBarHeight < 0) { - mBarHeight = mResources.getDimensionPixelSize( - com.android.internal.R.dimen.status_bar_height); + mBarHeight = SystemBarUtils.getStatusBarHeight(mContext); } } @@ -96,12 +96,11 @@ public class StatusBarWindowController { } /** - * Rereads the status_bar_height from configuration and reapplys the current state if the height + * Rereads the status bar height and reapplys the current state if the height * is different. */ public void refreshStatusBarHeight() { - int heightFromConfig = mResources.getDimensionPixelSize( - com.android.internal.R.dimen.status_bar_height); + int heightFromConfig = SystemBarUtils.getStatusBarHeight(mContext); if (mBarHeight != heightFromConfig) { mBarHeight = heightFromConfig; @@ -139,29 +138,20 @@ public class StatusBarWindowController { private WindowManager.LayoutParams getBarLayoutParamsForRotation(int rotation) { int height = mBarHeight; if (INSETS_LAYOUT_GENERALIZATION) { - Rect displayBounds = mWindowManager.getCurrentWindowMetrics().getBounds(); - int defaultAndUpsideDownHeight; - int theOtherHeight; - if (displayBounds.width() > displayBounds.height()) { - defaultAndUpsideDownHeight = mContext.getResources().getDimensionPixelSize( - com.android.internal.R.dimen.status_bar_height_landscape); - theOtherHeight = mContext.getResources().getDimensionPixelSize( - com.android.internal.R.dimen.status_bar_height_portrait); - } else { - defaultAndUpsideDownHeight = mContext.getResources().getDimensionPixelSize( - com.android.internal.R.dimen.status_bar_height_portrait); - theOtherHeight = mContext.getResources().getDimensionPixelSize( - com.android.internal.R.dimen.status_bar_height_landscape); - } switch (rotation) { case ROTATION_UNDEFINED: case Surface.ROTATION_0: case Surface.ROTATION_180: - height = defaultAndUpsideDownHeight; + height = SystemBarUtils.getStatusBarHeightForRotation( + mContext, Surface.ROTATION_0); break; case Surface.ROTATION_90: + height = SystemBarUtils.getStatusBarHeightForRotation( + mContext, Surface.ROTATION_90); + break; case Surface.ROTATION_270: - height = theOtherHeight; + height = SystemBarUtils.getStatusBarHeightForRotation( + mContext, Surface.ROTATION_270); break; } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt index f3f3325f49d7..e2332e923aa4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt @@ -145,22 +145,24 @@ class UnlockedScreenOffAnimationController @Inject constructor( .setDuration(duration.toLong()) .setInterpolator(Interpolators.FAST_OUT_SLOW_IN) .alpha(1f) - .withEndAction { - aodUiAnimationPlaying = false + .setListener(object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animation: Animator?) { + aodUiAnimationPlaying = false - // Lock the keyguard if it was waiting for the screen off animation to end. - keyguardViewMediatorLazy.get().maybeHandlePendingLock() + // Lock the keyguard if it was waiting for the screen off animation to end. + keyguardViewMediatorLazy.get().maybeHandlePendingLock() - // Tell the StatusBar to become keyguard for real - we waited on that since it - // is slow and would have caused the animation to jank. - statusBar.updateIsKeyguard() + // Tell the StatusBar to become keyguard for real - we waited on that since + // it is slow and would have caused the animation to jank. + statusBar.updateIsKeyguard() - // Run the callback given to us by the KeyguardVisibilityHelper. - after.run() + // Run the callback given to us by the KeyguardVisibilityHelper. + after.run() - // Done going to sleep, reset this flag. - decidedToAnimateGoingToSleep = null - } + // Done going to sleep, reset this flag. + decidedToAnimateGoingToSleep = null + } + }) .start() } @@ -226,6 +228,12 @@ class UnlockedScreenOffAnimationController @Inject constructor( return false } + // If animations are disabled system-wide, don't play this one either. + if (Settings.Global.getString( + context.contentResolver, Settings.Global.ANIMATOR_DURATION_SCALE) == "0") { + return false + } + // We only play the unlocked screen off animation if we are... unlocked. if (statusBarStateControllerImpl.state != StatusBarState.SHADE) { return false diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java index 568970790a18..c452a486cbe1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java @@ -88,6 +88,7 @@ import com.android.systemui.statusbar.phone.LockscreenGestureLogger; import com.android.systemui.statusbar.phone.LockscreenWallpaper; import com.android.systemui.statusbar.phone.NotificationIconAreaController; import com.android.systemui.statusbar.phone.PhoneStatusBarPolicy; +import com.android.systemui.statusbar.phone.PhoneStatusBarViewController; import com.android.systemui.statusbar.phone.ScrimController; import com.android.systemui.statusbar.phone.ShadeController; import com.android.systemui.statusbar.phone.StatusBar; @@ -111,6 +112,7 @@ import com.android.systemui.tuner.TunerService; import com.android.systemui.unfold.UnfoldLightRevealOverlayAnimation; import com.android.systemui.unfold.UnfoldTransitionWallpaperController; import com.android.systemui.unfold.config.UnfoldTransitionConfig; +import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider; import com.android.systemui.util.WallpaperController; import com.android.systemui.util.concurrency.DelayableExecutor; import com.android.systemui.util.concurrency.MessageRouter; @@ -211,6 +213,7 @@ public interface StatusBarPhoneModule { ExtensionController extensionController, UserInfoControllerImpl userInfoControllerImpl, OperatorNameViewController.Factory operatorNameViewControllerFactory, + PhoneStatusBarViewController.Factory phoneStatusBarViewControllerFactory, PhoneStatusBarPolicy phoneStatusBarPolicy, KeyguardIndicationController keyguardIndicationController, DemoModeController demoModeController, @@ -220,6 +223,7 @@ public interface StatusBarPhoneModule { BrightnessSlider.Factory brightnessSliderFactory, UnfoldTransitionConfig unfoldTransitionConfig, Lazy<UnfoldLightRevealOverlayAnimation> unfoldLightRevealOverlayAnimation, + Lazy<NaturalRotationUnfoldProgressProvider> naturalRotationUnfoldProgressProvider, Lazy<UnfoldTransitionWallpaperController> unfoldTransitionWallpaperController, Lazy<StatusBarMoveFromCenterAnimationController> statusBarMoveFromCenterAnimation, WallpaperController wallpaperController, @@ -311,6 +315,7 @@ public interface StatusBarPhoneModule { extensionController, userInfoControllerImpl, operatorNameViewControllerFactory, + phoneStatusBarViewControllerFactory, phoneStatusBarPolicy, keyguardIndicationController, demoModeController, @@ -321,7 +326,7 @@ public interface StatusBarPhoneModule { unfoldTransitionConfig, unfoldLightRevealOverlayAnimation, unfoldTransitionWallpaperController, - statusBarMoveFromCenterAnimation, + naturalRotationUnfoldProgressProvider, wallpaperController, ongoingCallController, animationScheduler, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java index 2791678c3b4c..9de0c46ff078 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java @@ -17,7 +17,6 @@ package com.android.systemui.statusbar.phone.dagger; import android.annotation.Nullable; -import android.content.Context; import android.view.LayoutInflater; import android.view.View; @@ -33,7 +32,6 @@ import com.android.systemui.statusbar.phone.NotificationPanelView; import com.android.systemui.statusbar.phone.NotificationShadeWindowView; import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer; import com.android.systemui.statusbar.phone.TapAgainView; -import com.android.systemui.util.InjectionInflationController; import javax.inject.Named; @@ -49,12 +47,9 @@ public abstract class StatusBarViewModule { @Provides @StatusBarComponent.StatusBarScope public static NotificationShadeWindowView providesNotificationShadeWindowView( - InjectionInflationController injectionInflationController, - Context context) { + LayoutInflater layoutInflater) { NotificationShadeWindowView notificationShadeWindowView = (NotificationShadeWindowView) - injectionInflationController.injectable( - LayoutInflater.from(context)).inflate(R.layout.super_notification_shade, - /* root= */ null); + layoutInflater.inflate(R.layout.super_notification_shade, /* root= */ null); if (notificationShadeWindowView == null) { throw new IllegalStateException( "R.layout.super_notification_shade could not be properly inflated"); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessibilityManagerWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessibilityManagerWrapper.java index d38284a26a07..479ca8f1ff96 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessibilityManagerWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessibilityManagerWrapper.java @@ -14,7 +14,6 @@ package com.android.systemui.statusbar.policy; -import android.content.Context; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener; @@ -35,8 +34,8 @@ public class AccessibilityManagerWrapper implements private final AccessibilityManager mAccessibilityManager; @Inject - public AccessibilityManagerWrapper(Context context) { - mAccessibilityManager = context.getSystemService(AccessibilityManager.class); + public AccessibilityManagerWrapper(AccessibilityManager accessibilityManager) { + mAccessibilityManager = accessibilityManager; } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedController.java index 7b4c35a8d25a..3944c8c77f49 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedController.java @@ -14,23 +14,60 @@ package com.android.systemui.statusbar.policy; +import android.provider.Settings; + import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener; +/** + * Controller to cache in process the state of the device provisioning. + * <p> + * This controller keeps track of the values of device provisioning and user setup complete + */ public interface DeviceProvisionedController extends CallbackController<DeviceProvisionedListener> { + /** + * @return whether the device is provisioned + * @see Settings.Global#DEVICE_PROVISIONED + */ boolean isDeviceProvisioned(); - boolean isUserSetup(int currentUser); + + /** + * @deprecated use {@link com.android.systemui.settings.UserTracker} + */ + @Deprecated int getCurrentUser(); - default boolean isCurrentUserSetup() { - return isUserSetup(getCurrentUser()); - } + /** + * @param user the user to query + * @return whether that user has completed the user setup + * @see Settings.Secure#USER_SETUP_COMPLETE + */ + boolean isUserSetup(int user); + /** + * @see DeviceProvisionedController#isUserSetup + */ + boolean isCurrentUserSetup(); + + /** + * Interface to provide calls when the values tracked change + */ interface DeviceProvisionedListener { + /** + * Call when the device changes from not provisioned to provisioned + */ default void onDeviceProvisionedChanged() { } + + /** + * Call on user switched + */ default void onUserSwitched() { onUserSetupChanged(); } + + /** + * Call when some user changes from not provisioned to provisioned + */ default void onUserSetupChanged() { } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java deleted file mode 100644 index 485b1b109eb4..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java +++ /dev/null @@ -1,149 +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.statusbar.policy; - -import android.app.ActivityManager; -import android.database.ContentObserver; -import android.net.Uri; -import android.os.Handler; -import android.provider.Settings.Global; -import android.provider.Settings.Secure; -import android.util.Log; - -import androidx.annotation.NonNull; - -import com.android.systemui.broadcast.BroadcastDispatcher; -import com.android.systemui.dagger.SysUISingleton; -import com.android.systemui.dagger.qualifiers.Main; -import com.android.systemui.settings.CurrentUserTracker; -import com.android.systemui.util.settings.GlobalSettings; -import com.android.systemui.util.settings.SecureSettings; - -import java.util.ArrayList; - -import javax.inject.Inject; - -/** - */ -@SysUISingleton -public class DeviceProvisionedControllerImpl extends CurrentUserTracker implements - DeviceProvisionedController { - - protected static final String TAG = DeviceProvisionedControllerImpl.class.getSimpleName(); - protected final ArrayList<DeviceProvisionedListener> mListeners = new ArrayList<>(); - private final GlobalSettings mGlobalSettings; - private final SecureSettings mSecureSettings; - private final Uri mDeviceProvisionedUri; - private final Uri mUserSetupUri; - protected final ContentObserver mSettingsObserver; - - /** - */ - @Inject - public DeviceProvisionedControllerImpl(@Main Handler mainHandler, - BroadcastDispatcher broadcastDispatcher, GlobalSettings globalSettings, - SecureSettings secureSettings) { - super(broadcastDispatcher); - mGlobalSettings = globalSettings; - mSecureSettings = secureSettings; - mDeviceProvisionedUri = mGlobalSettings.getUriFor(Global.DEVICE_PROVISIONED); - mUserSetupUri = mSecureSettings.getUriFor(Secure.USER_SETUP_COMPLETE); - mSettingsObserver = new ContentObserver(mainHandler) { - @Override - public void onChange(boolean selfChange, Uri uri, int flags) { - Log.d(TAG, "Setting change: " + uri); - if (mUserSetupUri.equals(uri)) { - notifySetupChanged(); - } else { - notifyProvisionedChanged(); - } - } - }; - } - - @Override - public boolean isDeviceProvisioned() { - return mGlobalSettings.getInt(Global.DEVICE_PROVISIONED, 0) != 0; - } - - @Override - public boolean isUserSetup(int currentUser) { - return mSecureSettings.getIntForUser(Secure.USER_SETUP_COMPLETE, 0, currentUser) != 0; - } - - @Override - public int getCurrentUser() { - return ActivityManager.getCurrentUser(); - } - - @Override - public void addCallback(@NonNull DeviceProvisionedListener listener) { - mListeners.add(listener); - if (mListeners.size() == 1) { - startListening(getCurrentUser()); - } - listener.onUserSetupChanged(); - listener.onDeviceProvisionedChanged(); - } - - @Override - public void removeCallback(@NonNull DeviceProvisionedListener listener) { - mListeners.remove(listener); - if (mListeners.size() == 0) { - stopListening(); - } - } - - protected void startListening(int user) { - mGlobalSettings.registerContentObserverForUser(mDeviceProvisionedUri, true, - mSettingsObserver, 0); - mSecureSettings.registerContentObserverForUser(mUserSetupUri, true, - mSettingsObserver, user); - startTracking(); - } - - protected void stopListening() { - stopTracking(); - mGlobalSettings.unregisterContentObserver(mSettingsObserver); - } - - @Override - public void onUserSwitched(int newUserId) { - mGlobalSettings.unregisterContentObserver(mSettingsObserver); - mGlobalSettings.registerContentObserverForUser(mDeviceProvisionedUri, true, - mSettingsObserver, 0); - mSecureSettings.registerContentObserverForUser(mUserSetupUri, true, - mSettingsObserver, newUserId); - notifyUserChanged(); - } - - private void notifyUserChanged() { - for (int i = mListeners.size() - 1; i >= 0; --i) { - mListeners.get(i).onUserSwitched(); - } - } - - private void notifySetupChanged() { - for (int i = mListeners.size() - 1; i >= 0; --i) { - mListeners.get(i).onUserSetupChanged(); - } - } - - private void notifyProvisionedChanged() { - for (int i = mListeners.size() - 1; i >= 0; --i) { - mListeners.get(i).onDeviceProvisionedChanged(); - } - } -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.kt new file mode 100644 index 000000000000..acc12141796e --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.kt @@ -0,0 +1,230 @@ +/* + * 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.statusbar.policy + +import android.content.Context +import android.content.pm.UserInfo +import android.database.ContentObserver +import android.net.Uri +import android.os.Handler +import android.os.HandlerExecutor +import android.os.UserHandle +import android.provider.Settings +import android.util.ArraySet +import android.util.SparseBooleanArray +import androidx.annotation.GuardedBy +import androidx.annotation.WorkerThread +import com.android.systemui.Dumpable +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.dump.DumpManager +import com.android.systemui.settings.UserTracker +import com.android.systemui.util.settings.GlobalSettings +import com.android.systemui.util.settings.SecureSettings +import java.io.FileDescriptor +import java.io.PrintWriter +import java.util.concurrent.Executor +import java.util.concurrent.atomic.AtomicBoolean +import javax.inject.Inject + +@SysUISingleton +open class DeviceProvisionedControllerImpl @Inject constructor( + private val secureSettings: SecureSettings, + private val globalSettings: GlobalSettings, + private val userTracker: UserTracker, + private val dumpManager: DumpManager, + @Background private val backgroundHandler: Handler, + @Main private val mainExecutor: Executor +) : DeviceProvisionedController, + DeviceProvisionedController.DeviceProvisionedListener, + Dumpable { + + companion object { + private const val ALL_USERS = -1 + private const val NO_USERS = -2 + protected const val TAG = "DeviceProvisionedControllerImpl" + } + + private val deviceProvisionedUri = globalSettings.getUriFor(Settings.Global.DEVICE_PROVISIONED) + private val userSetupUri = secureSettings.getUriFor(Settings.Secure.USER_SETUP_COMPLETE) + + private val deviceProvisioned = AtomicBoolean(false) + @GuardedBy("lock") + private val userSetupComplete = SparseBooleanArray() + @GuardedBy("lock") + private val listeners = ArraySet<DeviceProvisionedController.DeviceProvisionedListener>() + + private val lock = Any() + + private val backgroundExecutor = HandlerExecutor(backgroundHandler) + + private val initted = AtomicBoolean(false) + + private val _currentUser: Int + get() = userTracker.userId + + override fun getCurrentUser(): Int { + return _currentUser + } + + private val observer = object : ContentObserver(backgroundHandler) { + override fun onChange( + selfChange: Boolean, + uris: MutableCollection<Uri>, + flags: Int, + userId: Int + ) { + val updateDeviceProvisioned = deviceProvisionedUri in uris + val updateUser = if (userSetupUri in uris) userId else NO_USERS + updateValues(updateDeviceProvisioned, updateUser) + if (updateDeviceProvisioned) { + onDeviceProvisionedChanged() + } + if (updateUser != NO_USERS) { + onUserSetupChanged() + } + } + } + + private val userChangedCallback = object : UserTracker.Callback { + @WorkerThread + override fun onUserChanged(newUser: Int, userContext: Context) { + updateValues(updateDeviceProvisioned = false, updateUser = newUser) + onUserSwitched() + } + + override fun onProfilesChanged(profiles: List<UserInfo>) {} + } + + init { + userSetupComplete.put(currentUser, false) + } + + /** + * Call to initialize values and register observers + */ + open fun init() { + if (!initted.compareAndSet(false, true)) { + return + } + dumpManager.registerDumpable(this) + updateValues() + userTracker.addCallback(userChangedCallback, backgroundExecutor) + globalSettings.registerContentObserver(deviceProvisionedUri, observer) + secureSettings.registerContentObserverForUser(userSetupUri, observer, UserHandle.USER_ALL) + } + + @WorkerThread + private fun updateValues(updateDeviceProvisioned: Boolean = true, updateUser: Int = ALL_USERS) { + if (updateDeviceProvisioned) { + deviceProvisioned + .set(globalSettings.getInt(Settings.Global.DEVICE_PROVISIONED, 0) != 0) + } + synchronized(lock) { + if (updateUser == ALL_USERS) { + val N = userSetupComplete.size() + for (i in 0 until N) { + val user = userSetupComplete.keyAt(i) + val value = secureSettings + .getIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 0, user) != 0 + userSetupComplete.put(user, value) + } + } else if (updateUser != NO_USERS) { + val value = secureSettings + .getIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 0, updateUser) != 0 + userSetupComplete.put(updateUser, value) + } + } + } + + /** + * Adds a listener. + * + * The listener will not be called when this happens. + */ + override fun addCallback(listener: DeviceProvisionedController.DeviceProvisionedListener) { + synchronized(lock) { + listeners.add(listener) + } + } + + override fun removeCallback(listener: DeviceProvisionedController.DeviceProvisionedListener) { + synchronized(lock) { + listeners.remove(listener) + } + } + + override fun isDeviceProvisioned(): Boolean { + return deviceProvisioned.get() + } + + override fun isUserSetup(user: Int): Boolean { + val index = synchronized(lock) { + userSetupComplete.indexOfKey(user) + } + return if (index < 0) { + val value = secureSettings + .getIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 0, user) != 0 + synchronized(lock) { + userSetupComplete.put(user, value) + } + value + } else { + synchronized(lock) { + userSetupComplete.get(user, false) + } + } + } + + override fun isCurrentUserSetup(): Boolean { + return isUserSetup(currentUser) + } + + override fun onDeviceProvisionedChanged() { + dispatchChange( + DeviceProvisionedController.DeviceProvisionedListener::onDeviceProvisionedChanged + ) + } + + override fun onUserSetupChanged() { + dispatchChange(DeviceProvisionedController.DeviceProvisionedListener::onUserSetupChanged) + } + + override fun onUserSwitched() { + dispatchChange(DeviceProvisionedController.DeviceProvisionedListener::onUserSwitched) + } + + protected fun dispatchChange( + callback: DeviceProvisionedController.DeviceProvisionedListener.() -> Unit + ) { + val listenersCopy = synchronized(lock) { + ArrayList(listeners) + } + mainExecutor.execute { + listenersCopy.forEach(callback) + } + } + + override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) { + pw.println("Device provisioned: ${deviceProvisioned.get()}") + synchronized(lock) { + pw.println("User setup complete: $userSetupComplete") + pw.println("Listeners: $listeners") + } + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java index dadc01664b4d..b630689567ce 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java @@ -59,6 +59,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.jank.InteractionJankMonitor; import com.android.internal.logging.UiEventLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.internal.util.LatencyTracker; import com.android.settingslib.RestrictedLockUtilsInternal; import com.android.systemui.Dumpable; import com.android.systemui.GuestResumeSessionReceiver; @@ -128,6 +129,7 @@ public class UserSwitcherController implements Dumpable { private final TelephonyListenerManager mTelephonyListenerManager; private final IActivityTaskManager mActivityTaskManager; private final InteractionJankMonitor mInteractionJankMonitor; + private final LatencyTracker mLatencyTracker; private ArrayList<UserRecord> mUsers = new ArrayList<>(); @VisibleForTesting @@ -174,6 +176,7 @@ public class UserSwitcherController implements Dumpable { SecureSettings secureSettings, @Background Executor bgExecutor, InteractionJankMonitor interactionJankMonitor, + LatencyTracker latencyTracker, DumpManager dumpManager) { mContext = context; mActivityManager = activityManager; @@ -184,6 +187,7 @@ public class UserSwitcherController implements Dumpable { mUiEventLogger = uiEventLogger; mFalsingManager = falsingManager; mInteractionJankMonitor = interactionJankMonitor; + mLatencyTracker = latencyTracker; mGuestResumeSessionReceiver = new GuestResumeSessionReceiver( this, mUserTracker, mUiEventLogger, secureSettings); mUserDetailAdapter = userDetailAdapter; @@ -499,6 +503,7 @@ public class UserSwitcherController implements Dumpable { mInteractionJankMonitor.begin(InteractionJankMonitor.Configuration.Builder .withView(InteractionJankMonitor.CUJ_USER_SWITCH, mRootView) .setTimeout(MULTI_USER_JOURNEY_TIMEOUT)); + mLatencyTracker.onActionStart(LatencyTracker.ACTION_USER_SWITCH); pauseRefreshUsers(); mActivityManager.switchUser(id); } catch (RemoteException e) { diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java index 891244823271..923aff1e6b3d 100644 --- a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java @@ -180,9 +180,13 @@ public abstract class TvSystemUIModule { return new Recents(context, recentsImplementation, commandQueue); } - @Binds - abstract DeviceProvisionedController bindDeviceProvisionedController( - DeviceProvisionedControllerImpl deviceProvisionedController); + @SysUISingleton + @Provides + static DeviceProvisionedController providesDeviceProvisionedController( + DeviceProvisionedControllerImpl deviceProvisionedController) { + deviceProvisionedController.init(); + return deviceProvisionedController; + } @Binds abstract KeyguardViewController bindKeyguardViewController( diff --git a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt index 3c3cc64a49cd..f0760d4e2187 100644 --- a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt +++ b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt @@ -19,13 +19,27 @@ import android.content.Context import android.graphics.PixelFormat import android.hardware.devicestate.DeviceStateManager import android.hardware.devicestate.DeviceStateManager.FoldStateListener +import android.hardware.display.DisplayManager +import android.os.Handler +import android.os.Trace +import android.view.Choreographer +import android.view.Display +import android.view.DisplayInfo import android.view.Surface +import android.view.SurfaceControl +import android.view.SurfaceControlViewHost +import android.view.SurfaceSession import android.view.WindowManager +import android.view.WindowlessWindowManager import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Main -import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener +import com.android.systemui.dagger.qualifiers.UiBackground +import com.android.systemui.statusbar.LightRevealEffect import com.android.systemui.statusbar.LightRevealScrim import com.android.systemui.statusbar.LinearLightRevealEffect +import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener +import com.android.wm.shell.displayareahelper.DisplayAreaHelper +import java.util.Optional import java.util.concurrent.Executor import java.util.function.Consumer import javax.inject.Inject @@ -34,53 +48,148 @@ import javax.inject.Inject class UnfoldLightRevealOverlayAnimation @Inject constructor( private val context: Context, private val deviceStateManager: DeviceStateManager, + private val displayManager: DisplayManager, private val unfoldTransitionProgressProvider: UnfoldTransitionProgressProvider, + private val displayAreaHelper: Optional<DisplayAreaHelper>, @Main private val executor: Executor, - private val windowManager: WindowManager + @Main private val handler: Handler, + @UiBackground private val backgroundExecutor: Executor ) { private val transitionListener = TransitionListener() + private val displayListener = DisplayChangeListener() + + private lateinit var wwm: WindowlessWindowManager + private lateinit var unfoldedDisplayInfo: DisplayInfo + private lateinit var overlayContainer: SurfaceControl + + private var root: SurfaceControlViewHost? = null private var scrimView: LightRevealScrim? = null + private var isFolded: Boolean = false + private var isUnfoldHandled: Boolean = true + + private var currentRotation: Int = context.display!!.rotation fun init() { deviceStateManager.registerCallback(executor, FoldListener()) unfoldTransitionProgressProvider.addCallback(transitionListener) - } - private inner class TransitionListener : TransitionProgressListener { + val containerBuilder = SurfaceControl.Builder(SurfaceSession()) + .setContainerLayer() + .setName("unfold-overlay-container") - override fun onTransitionProgress(progress: Float) { - scrimView?.revealAmount = progress - } + displayAreaHelper.get().attachToRootDisplayArea(Display.DEFAULT_DISPLAY, + containerBuilder) { builder -> + executor.execute { + overlayContainer = builder.build() - override fun onTransitionFinished() { - removeOverlayView() + SurfaceControl.Transaction() + .setLayer(overlayContainer, Integer.MAX_VALUE) + .show(overlayContainer) + .apply() + + wwm = WindowlessWindowManager(context.resources.configuration, + overlayContainer, null) + } } - override fun onTransitionStarted() { - // When unfolding the view is added earlier, add view for folding case - if (scrimView == null) { - addOverlayView() + displayManager.registerDisplayListener(displayListener, handler, + DisplayManager.EVENT_FLAG_DISPLAY_CHANGED) + + // Get unfolded display size immediately as 'current display info' might be + // not up-to-date during unfolding + unfoldedDisplayInfo = getUnfoldedDisplayInfo() + } + + /** + * Called when screen starts turning on, the contents of the screen might not be visible yet. + * This method reports back that the overlay is ready in [onOverlayReady] callback. + * + * @param onOverlayReady callback when the overlay is drawn and visible on the screen + * @see [com.android.systemui.keyguard.KeyguardViewMediator] + */ + fun onScreenTurningOn(onOverlayReady: Runnable) { + Trace.beginSection("UnfoldLightRevealOverlayAnimation#onScreenTurningOn") + try { + // Add the view only if we are unfolding and this is the first screen on + if (!isFolded && !isUnfoldHandled) { + addView(onOverlayReady) + isUnfoldHandled = true + } else { + // No unfold transition, immediately report that overlay is ready + ensureOverlayRemoved() + onOverlayReady.run() } + } finally { + Trace.endSection() } } - private inner class FoldListener : FoldStateListener(context, Consumer { isFolded -> - if (isFolded) { - removeOverlayView() - } else { - // Add overlay view before starting the transition as soon as we unfolded the device - addOverlayView() + private fun addView(onOverlayReady: Runnable? = null) { + if (!::wwm.isInitialized) { + // Surface overlay is not created yet on the first SysUI launch + onOverlayReady?.run() + return } - }) - private fun addOverlayView() { + ensureOverlayRemoved() + + val newRoot = SurfaceControlViewHost(context, context.display!!, wwm, false) + val newView = LightRevealScrim(context, null) + .apply { + revealEffect = createLightRevealEffect() + isScrimOpaqueChangedListener = Consumer {} + revealAmount = 0f + } + + val params = getLayoutParams() + newRoot.setView(newView, params) + + onOverlayReady?.let { callback -> + Trace.beginAsyncSection( + "UnfoldLightRevealOverlayAnimation#relayout", 0) + + newRoot.relayout(params) { transaction -> + val vsyncId = Choreographer.getSfInstance().vsyncId + + backgroundExecutor.execute { + // Apply the transaction that contains the first frame of the overlay + // synchronously and apply another empty transaction with + // 'vsyncId + 1' to make sure that it is actually displayed on + // the screen. The second transaction is necessary to remove the screen blocker + // (turn on the brightness) only when the content is actually visible as it + // might be presented only in the next frame. + // See b/197538198 + transaction.setFrameTimelineVsync(vsyncId) + .apply(/* sync */true) + + transaction + .setFrameTimelineVsync(vsyncId + 1) + .apply(/* sync */ true) + + Trace.endAsyncSection( + "UnfoldLightRevealOverlayAnimation#relayout", 0) + callback.run() + } + } + } + + scrimView = newView + root = newRoot + } + + private fun getLayoutParams(): WindowManager.LayoutParams { val params: WindowManager.LayoutParams = WindowManager.LayoutParams() - params.height = WindowManager.LayoutParams.MATCH_PARENT - params.width = WindowManager.LayoutParams.MATCH_PARENT - params.format = PixelFormat.TRANSLUCENT - // TODO(b/193801466): create a separate type for this overlay + val rotation = context.display!!.rotation + val isNatural = rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180 + + params.height = if (isNatural) + unfoldedDisplayInfo.naturalHeight else unfoldedDisplayInfo.naturalWidth + params.width = if (isNatural) + unfoldedDisplayInfo.naturalWidth else unfoldedDisplayInfo.naturalHeight + + params.format = PixelFormat.TRANSLUCENT params.type = WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY params.title = "Unfold Light Reveal Animation" params.layoutInDisplayCutoutMode = @@ -90,41 +199,72 @@ class UnfoldLightRevealOverlayAnimation @Inject constructor( or WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) params.setTrustedOverlay() - val rotation = windowManager.defaultDisplay.rotation - val isVerticalFold = rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180 + val packageName: String = context.opPackageName + params.packageName = packageName - val newScrimView = LightRevealScrim(context, null) - .apply { - revealEffect = LinearLightRevealEffect(isVerticalFold) - isScrimOpaqueChangedListener = Consumer {} - revealAmount = 0f - } + return params + } - val packageName: String = newScrimView.context.opPackageName - params.packageName = packageName - params.hideTimeoutMilliseconds = OVERLAY_HIDE_TIMEOUT_MILLIS + private fun createLightRevealEffect(): LightRevealEffect { + val isVerticalFold = currentRotation == Surface.ROTATION_0 || + currentRotation == Surface.ROTATION_180 + return LinearLightRevealEffect(isVertical = isVerticalFold) + } + + private fun ensureOverlayRemoved() { + root?.release() + root = null + scrimView = null + } - if (scrimView?.parent != null) { - windowManager.removeView(scrimView) + private fun getUnfoldedDisplayInfo(): DisplayInfo = + displayManager.displays + .asSequence() + .map { DisplayInfo().apply { it.getDisplayInfo(this) } } + .filter { it.type == Display.TYPE_INTERNAL } + .maxByOrNull { it.naturalWidth }!! + + private inner class TransitionListener : TransitionProgressListener { + + override fun onTransitionProgress(progress: Float) { + scrimView?.revealAmount = progress } - this.scrimView = newScrimView + override fun onTransitionFinished() { + ensureOverlayRemoved() + } - try { - windowManager.addView(scrimView, params) - } catch (e: WindowManager.BadTokenException) { - e.printStackTrace() + override fun onTransitionStarted() { + // Add view for folding case (when unfolding the view is added earlier) + if (scrimView == null) { + addView() + } } } - private fun removeOverlayView() { - scrimView?.let { - if (it.parent != null) { - windowManager.removeViewImmediate(it) + private inner class DisplayChangeListener : DisplayManager.DisplayListener { + + override fun onDisplayChanged(displayId: Int) { + val newRotation: Int = context.display!!.rotation + if (currentRotation != newRotation) { + currentRotation = newRotation + scrimView?.revealEffect = createLightRevealEffect() + root?.relayout(getLayoutParams()) } - scrimView = null + } + + override fun onDisplayAdded(displayId: Int) { + } + + override fun onDisplayRemoved(displayId: Int) { } } -} -private const val OVERLAY_HIDE_TIMEOUT_MILLIS = 10_000L + private inner class FoldListener : FoldStateListener(context, Consumer { isFolded -> + if (isFolded) { + ensureOverlayRemoved() + isUnfoldHandled = false + } + this.isFolded = isFolded + }) +} diff --git a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt index b23aa20dcaa4..7e4ec67e6e18 100644 --- a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt +++ b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt @@ -20,15 +20,19 @@ import android.content.Context import android.hardware.SensorManager import android.hardware.devicestate.DeviceStateManager import android.os.Handler +import android.view.IWindowManager import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.keyguard.LifecycleScreenStatusProvider import com.android.systemui.unfold.config.UnfoldTransitionConfig +import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider +import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider import com.android.wm.shell.unfold.ShellUnfoldProgressProvider import dagger.Lazy import dagger.Module import dagger.Provides import java.util.Optional import java.util.concurrent.Executor +import javax.inject.Named import javax.inject.Singleton @Module @@ -62,6 +66,27 @@ class UnfoldTransitionModule { @Provides @Singleton + fun provideNaturalRotationProgressProvider( + context: Context, + windowManager: IWindowManager, + unfoldTransitionProgressProvider: UnfoldTransitionProgressProvider + ): NaturalRotationUnfoldProgressProvider = + NaturalRotationUnfoldProgressProvider( + context, + windowManager, + unfoldTransitionProgressProvider + ) + + @Provides + @Named(UNFOLD_STATUS_BAR) + @Singleton + fun provideStatusBarScopedTransitionProvider( + source: NaturalRotationUnfoldProgressProvider + ): ScopedUnfoldTransitionProgressProvider = + ScopedUnfoldTransitionProgressProvider(source) + + @Provides + @Singleton fun provideShellProgressProvider( config: UnfoldTransitionConfig, provider: Lazy<UnfoldTransitionProgressProvider> @@ -72,3 +97,5 @@ class UnfoldTransitionModule { Optional.empty() } } + +const val UNFOLD_STATUS_BAR = "unfold_status_bar"
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionWallpaperController.kt b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionWallpaperController.kt index 8dd3d6beb9c3..4f45aafce416 100644 --- a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionWallpaperController.kt +++ b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionWallpaperController.kt @@ -33,7 +33,14 @@ class UnfoldTransitionWallpaperController @Inject constructor( private inner class TransitionListener : TransitionProgressListener { override fun onTransitionProgress(progress: Float) { - wallpaperController.setUnfoldTransitionZoom(progress) + // Fully zoomed in when fully unfolded + wallpaperController.setUnfoldTransitionZoom(1 - progress) + } + + override fun onTransitionFinished() { + // Resets wallpaper zoom-out to 0f when fully folded + // When fully unfolded it is set to 0f by onTransitionProgress + wallpaperController.setUnfoldTransitionZoom(0f) } } } diff --git a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java deleted file mode 100644 index cdc5d8795b91..000000000000 --- a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java +++ /dev/null @@ -1,120 +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.util; - -import android.content.Context; -import android.util.ArrayMap; -import android.util.AttributeSet; -import android.view.InflateException; -import android.view.LayoutInflater; -import android.view.View; - -import com.android.systemui.dagger.SysUISingleton; -import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; - -import javax.inject.Inject; -import javax.inject.Named; - -import dagger.BindsInstance; -import dagger.Subcomponent; - -/** - * Manages inflation that requires dagger injection. - * See docs/dagger.md for details. - */ -@SysUISingleton -public class InjectionInflationController { - - public static final String VIEW_CONTEXT = "view_context"; - private final ArrayMap<String, Method> mInjectionMap = new ArrayMap<>(); - private final LayoutInflater.Factory2 mFactory = new InjectionFactory(); - private final ViewInstanceCreator.Factory mViewInstanceCreatorFactory; - - @Inject - public InjectionInflationController(ViewInstanceCreator.Factory viewInstanceCreatorFactory) { - mViewInstanceCreatorFactory = viewInstanceCreatorFactory; - initInjectionMap(); - } - - /** - * Wraps a {@link LayoutInflater} to support creating dagger injected views. - * See docs/dagger.md for details. - */ - public LayoutInflater injectable(LayoutInflater inflater) { - LayoutInflater ret = inflater.cloneInContext(inflater.getContext()); - ret.setPrivateFactory(mFactory); - return ret; - } - - private void initInjectionMap() { - for (Method method : ViewInstanceCreator.class.getDeclaredMethods()) { - if (View.class.isAssignableFrom(method.getReturnType()) - && (method.getModifiers() & Modifier.PUBLIC) != 0) { - mInjectionMap.put(method.getReturnType().getName(), method); - } - } - } - - /** - * Subcomponent that actually creates injected views. - */ - @Subcomponent - public interface ViewInstanceCreator { - - /** Factory for creating a ViewInstanceCreator. */ - @Subcomponent.Factory - interface Factory { - ViewInstanceCreator build( - @BindsInstance @Named(VIEW_CONTEXT) Context context, - @BindsInstance AttributeSet attributeSet); - } - - /** - * Creates the NotificationStackScrollLayout. - */ - NotificationStackScrollLayout createNotificationStackScrollLayout(); - } - - - private class InjectionFactory implements LayoutInflater.Factory2 { - - @Override - public View onCreateView(String name, Context context, AttributeSet attrs) { - Method creationMethod = mInjectionMap.get(name); - if (creationMethod != null) { - try { - return (View) creationMethod.invoke( - mViewInstanceCreatorFactory.build(context, attrs)); - } catch (IllegalAccessException e) { - throw new InflateException("Could not inflate " + name, e); - } catch (InvocationTargetException e) { - throw new InflateException("Could not inflate " + name, e); - } - } - return null; - } - - @Override - public View onCreateView(View parent, String name, Context context, AttributeSet attrs) { - return onCreateView(name, context, attrs); - } - } -} diff --git a/packages/SystemUI/src/com/android/systemui/util/Utils.java b/packages/SystemUI/src/com/android/systemui/util/Utils.java index a1cdfd8201c7..407dc5e2787a 100644 --- a/packages/SystemUI/src/com/android/systemui/util/Utils.java +++ b/packages/SystemUI/src/com/android/systemui/util/Utils.java @@ -24,8 +24,10 @@ import android.content.res.Resources; import android.content.res.TypedArray; import android.provider.Settings; import android.view.ContextThemeWrapper; +import android.view.DisplayCutout; import android.view.View; +import com.android.internal.policy.SystemBarUtils; import com.android.systemui.R; import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.statusbar.CommandQueue; @@ -186,4 +188,39 @@ public class Utils { return color; } + /** + * Gets the {@link R.dimen#split_shade_header_height}. + * + * Currently, it's the same as {@link com.android.internal.R.dimen#quick_qs_offset_height}. + */ + public static int getSplitShadeStatusBarHeight(Context context) { + return SystemBarUtils.getQuickQsOffsetHeight(context); + } + + /** + * Gets the {@link R.dimen#qs_header_system_icons_area_height}. + * + * It's the same as {@link com.android.internal.R.dimen#quick_qs_offset_height} except for + * sw600dp-land. + */ + public static int getQsHeaderSystemIconsAreaHeight(Context context) { + final Resources res = context.getResources(); + if (Utils.shouldUseSplitNotificationShade(res)) { + return res.getDimensionPixelSize(R.dimen.qs_header_system_icons_area_height); + } else { + return SystemBarUtils.getQuickQsOffsetHeight(context); + } + } + + /** + * Gets the {@link R.dimen#status_bar_header_height_keyguard}. + */ + public static int getStatusBarHeaderHeightKeyguard(Context context) { + final int statusBarHeight = SystemBarUtils.getStatusBarHeight(context); + final DisplayCutout cutout = context.getDisplay().getCutout(); + final int waterfallInsetTop = cutout == null ? 0 : cutout.getWaterfallInsets().top; + final int statusBarHeaderHeightKeyguard = context.getResources() + .getDimensionPixelSize(R.dimen.status_bar_header_height_keyguard); + return Math.max(statusBarHeight, statusBarHeaderHeightKeyguard + waterfallInsetTop); + } } diff --git a/packages/SystemUI/src/com/android/systemui/util/sensors/SensorModule.java b/packages/SystemUI/src/com/android/systemui/util/sensors/SensorModule.java index 0be6068c22a4..96980b85e410 100644 --- a/packages/SystemUI/src/com/android/systemui/util/sensors/SensorModule.java +++ b/packages/SystemUI/src/com/android/systemui/util/sensors/SensorModule.java @@ -29,6 +29,7 @@ import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.statusbar.policy.DevicePostureController; import com.android.systemui.util.concurrency.DelayableExecutor; +import java.util.Arrays; import java.util.HashMap; import java.util.Map; @@ -177,9 +178,7 @@ public class SensorModule { // length and index of sensorMap correspond to DevicePostureController.DevicePostureInt: final ThresholdSensor[] sensorMap = new ThresholdSensor[DevicePostureController.SUPPORTED_POSTURES_SIZE]; - for (int i = 0; i < DevicePostureController.SUPPORTED_POSTURES_SIZE; i++) { - sensorMap[i] = noProxSensor; - } + Arrays.fill(sensorMap, noProxSensor); if (!hasPostureSupport(sensorTypes)) { Log.e("SensorModule", "config doesn't support postures," diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java index d3581a9fd177..291c64dd6daf 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java @@ -377,10 +377,24 @@ public class BubblesManager implements Dumpable { sysuiMainExecutor.execute(() -> { sysUiState.setFlag(QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED, shouldExpand) .commitUpdate(mContext.getDisplayId()); + if (!shouldExpand) { + sysUiState.setFlag( + QuickStepContract.SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED, + false).commitUpdate(mContext.getDisplayId()); + } }); } @Override + public void onManageMenuExpandChanged(boolean menuExpanded) { + sysuiMainExecutor.execute(() -> { + sysUiState.setFlag(QuickStepContract.SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED, + menuExpanded).commitUpdate(mContext.getDisplayId()); + }); + } + + + @Override public void onUnbubbleConversation(String key) { sysuiMainExecutor.execute(() -> { final NotificationEntry entry = diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java index c776ab9bda1d..74611cce6f87 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java @@ -20,6 +20,7 @@ import static android.view.Display.DEFAULT_DISPLAY; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED; +import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_GLOBAL_ACTIONS_SHOWING; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_ONE_HANDED_ACTIVE; @@ -101,6 +102,7 @@ public final class WMShell extends SystemUI | SYSUI_STATE_BOUNCER_SHOWING | SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED | SYSUI_STATE_BUBBLES_EXPANDED + | SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED | SYSUI_STATE_QUICK_SETTINGS_EXPANDED; // Shell interfaces diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java index 514a9035a9ef..fd9783a392a5 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java @@ -26,8 +26,10 @@ import android.view.WindowManager; import com.android.internal.logging.UiEventLogger; import com.android.internal.statusbar.IStatusBarService; +import com.android.launcher3.icons.IconProvider; import com.android.systemui.dagger.WMComponent; import com.android.systemui.dagger.WMSingleton; +import com.android.wm.shell.RootDisplayAreaOrganizer; import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.ShellCommandHandler; import com.android.wm.shell.ShellCommandHandlerImpl; @@ -54,6 +56,8 @@ import com.android.wm.shell.common.TransactionPool; import com.android.wm.shell.common.annotations.ShellAnimationThread; import com.android.wm.shell.common.annotations.ShellMainThread; import com.android.wm.shell.common.annotations.ShellSplashscreenThread; +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.freeform.FreeformTaskListener; import com.android.wm.shell.fullscreen.FullscreenTaskListener; @@ -166,6 +170,12 @@ public abstract class WMShellBaseModule { return new SystemWindows(displayController, wmService); } + @WMSingleton + @Provides + static IconProvider provideIconProvider(Context context) { + return new IconProvider(context); + } + // We currently dedupe multiple messages, so we use the shell main handler directly @WMSingleton @Provides @@ -342,13 +352,21 @@ public abstract class WMShellBaseModule { return taskSurfaceController.map((controller) -> controller.asTaskSurfaceHelper()); } - @WMSingleton @Provides static Optional<TaskSurfaceHelperController> provideTaskSurfaceHelperController( ShellTaskOrganizer taskOrganizer, @ShellMainThread ShellExecutor mainExecutor) { return Optional.ofNullable(new TaskSurfaceHelperController(taskOrganizer, mainExecutor)); } + @WMSingleton + @Provides + static Optional<DisplayAreaHelper> provideDisplayAreaHelper( + @ShellMainThread ShellExecutor mainExecutor, + RootDisplayAreaOrganizer rootDisplayAreaOrganizer) { + return Optional.ofNullable(new DisplayAreaHelperController(mainExecutor, + rootDisplayAreaOrganizer)); + } + // // Pip (optional feature) // @@ -424,6 +442,13 @@ public abstract class WMShellBaseModule { @WMSingleton @Provides + static RootDisplayAreaOrganizer provideRootDisplayAreaOrganizer( + @ShellMainThread ShellExecutor mainExecutor) { + return new RootDisplayAreaOrganizer(mainExecutor); + } + + @WMSingleton + @Provides static Optional<SplitScreen> provideSplitScreen( Optional<SplitScreenController> splitScreenController) { return splitScreenController.map((controller) -> controller.asSplitScreen()); @@ -486,9 +511,10 @@ public abstract class WMShellBaseModule { @Provides static StartingWindowController provideStartingWindowController(Context context, @ShellSplashscreenThread ShellExecutor splashScreenExecutor, - StartingWindowTypeAlgorithm startingWindowTypeAlgorithm, TransactionPool pool) { + StartingWindowTypeAlgorithm startingWindowTypeAlgorithm, IconProvider iconProvider, + TransactionPool pool) { return new StartingWindowController(context, splashScreenExecutor, - startingWindowTypeAlgorithm, pool); + startingWindowTypeAlgorithm, iconProvider, pool); } // diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java index fe0a2a4bbb14..5e0f427800fc 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java @@ -194,7 +194,7 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase { verifyAttachment(times(1)); listenerArgumentCaptor.getValue().onViewDetachedFromWindow(mView); - + verify(mView).onViewDetached(); verify(mColorExtractor).removeOnColorsChangedListener( any(ColorExtractor.OnColorsChangedListener.class)); } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java index 3edfd03dfc70..e53b450a895e 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java @@ -79,6 +79,7 @@ import androidx.lifecycle.Observer; import com.android.dx.mockito.inline.extended.ExtendedMockito; import com.android.internal.jank.InteractionJankMonitor; import com.android.internal.telephony.TelephonyIntents; +import com.android.internal.util.LatencyTracker; import com.android.internal.widget.ILockSettings; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardUpdateMonitor.BiometricAuthenticated; @@ -172,6 +173,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { private FeatureFlags mFeatureFlags; @Mock private InteractionJankMonitor mInteractionJankMonitor; + @Mock + private LatencyTracker mLatencyTracker; @Captor private ArgumentCaptor<StatusBarStateController.StateListener> mStatusBarStateListenerCaptor; // Direct executor @@ -741,7 +744,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { public void sendResult(Bundle data) {} // do nothing }; mKeyguardUpdateMonitor.handleUserSwitchComplete(10 /* user */); - verify(mInteractionJankMonitor).end(eq(InteractionJankMonitor.CUJ_USER_SWITCH)); + verify(mInteractionJankMonitor).end(InteractionJankMonitor.CUJ_USER_SWITCH); + verify(mLatencyTracker).onActionEnd(LatencyTracker.ACTION_USER_SWITCH); } @Test @@ -1059,7 +1063,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mRingerModeTracker, mBackgroundExecutor, mStatusBarStateController, mLockPatternUtils, mAuthController, mTelephonyListenerManager, mFeatureFlags, - mInteractionJankMonitor); + mInteractionJankMonitor, mLatencyTracker); setStrongAuthTracker(KeyguardUpdateMonitorTest.this.mStrongAuthTracker); } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java index 35fe1ba8f805..ff4412e97c04 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java @@ -17,7 +17,6 @@ package com.android.keyguard.clock; 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.reset; import static org.mockito.Mockito.verify; @@ -40,7 +39,6 @@ import com.android.systemui.dock.DockManagerFake; import com.android.systemui.plugins.ClockPlugin; import com.android.systemui.settings.CurrentUserObservable; import com.android.systemui.shared.plugins.PluginManager; -import com.android.systemui.util.InjectionInflationController; import org.junit.After; import org.junit.Before; @@ -69,7 +67,6 @@ public final class ClockManagerTest extends SysuiTestCase { private ContentObserver mContentObserver; private DockManagerFake mFakeDockManager; private MutableLiveData<Integer> mCurrentUser; - @Mock InjectionInflationController mMockInjectionInflationController; @Mock PluginManager mMockPluginManager; @Mock SysuiColorExtractor mMockColorExtractor; @Mock ContentResolver mMockContentResolver; @@ -83,7 +80,6 @@ public final class ClockManagerTest extends SysuiTestCase { MockitoAnnotations.initMocks(this); LayoutInflater inflater = LayoutInflater.from(getContext()); - when(mMockInjectionInflationController.injectable(any())).thenReturn(inflater); mFakeDockManager = new DockManagerFake(); @@ -91,7 +87,7 @@ public final class ClockManagerTest extends SysuiTestCase { mCurrentUser.setValue(MAIN_USER_ID); when(mMockCurrentUserObserable.getCurrentUser()).thenReturn(mCurrentUser); - mClockManager = new ClockManager(getContext(), mMockInjectionInflationController, + mClockManager = new ClockManager(getContext(), inflater, mMockPluginManager, mMockColorExtractor, mMockContentResolver, mMockCurrentUserObserable, mMockSettingsWrapper, mFakeDockManager); diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/SmallClockPositionTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/clock/SmallClockPositionTest.kt index 456f32b4bd40..3a27e356ed84 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/clock/SmallClockPositionTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/clock/SmallClockPositionTest.kt @@ -43,7 +43,7 @@ class SmallClockPositionTest : SysuiTestCase() { @Test fun loadResources() { // Cover constructor taking Resources object. - position = SmallClockPosition(context.resources) + position = SmallClockPosition(context) position.setDarkAmount(1f) assertThat(position.preferredY).isGreaterThan(0) } 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 c4f480d7e7aa..55ee433c8d9d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineFalsingManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineFalsingManagerTest.java @@ -91,7 +91,7 @@ public class BrightLineFalsingManagerTest extends SysuiTestCase { @Test public void testA11yDisablesGesture() { assertThat(mBrightLineFalsingManager.isFalseTap(1)).isTrue(); - when(mAccessibilityManager.isEnabled()).thenReturn(true); + when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(true); assertThat(mBrightLineFalsingManager.isFalseTap(1)).isFalse(); } @@ -99,7 +99,7 @@ public class BrightLineFalsingManagerTest extends SysuiTestCase { @Test public void testA11yDisablesTap() { assertThat(mBrightLineFalsingManager.isFalseTouch(Classifier.GENERIC)).isTrue(); - when(mAccessibilityManager.isEnabled()).thenReturn(true); + when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(true); assertThat(mBrightLineFalsingManager.isFalseTouch(Classifier.GENERIC)).isFalse(); } @@ -107,7 +107,7 @@ public class BrightLineFalsingManagerTest extends SysuiTestCase { @Test public void testA11yDisablesDoubleTap() { assertThat(mBrightLineFalsingManager.isFalseDoubleTap()).isTrue(); - when(mAccessibilityManager.isEnabled()).thenReturn(true); + when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(true); assertThat(mBrightLineFalsingManager.isFalseDoubleTap()).isFalse(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java index 866791cc24cb..364b5d9be2b3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java @@ -67,7 +67,8 @@ public class DozeConfigurationUtil { when(config.tapGestureEnabled(anyInt())).thenReturn(true); when(config.tapSensorAvailable()).thenReturn(true); - when(config.tapSensorType(anyInt())).thenReturn(FakeSensorManager.TAP_SENSOR_TYPE); + when(config.tapSensorTypeMapping()).thenReturn( + new String[]{FakeSensorManager.TAP_SENSOR_TYPE}); when(config.dozePickupSensorAvailable()).thenReturn(false); when(config.wakeScreenGestureAvailable()).thenReturn(false); diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java index e0520b406a0a..886f84e19e0b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java @@ -51,6 +51,7 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.dock.DockManager; import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.statusbar.phone.DozeParameters; +import com.android.systemui.statusbar.policy.DevicePostureController; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.concurrency.FakeThreadFactory; import com.android.systemui.util.sensors.AsyncSensorManager; @@ -60,6 +61,7 @@ import com.android.systemui.util.time.FakeSystemClock; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -76,6 +78,7 @@ public class DozeScreenBrightnessTest extends SysuiTestCase { private DozeServiceFake mServiceFake; private FakeSensorManager.FakeGenericSensor mSensor; + private FakeSensorManager.FakeGenericSensor mSensorInner; private AsyncSensorManager mSensorManager; private AlwaysOnDisplayPolicy mAlwaysOnDisplayPolicy; @Mock @@ -86,6 +89,10 @@ public class DozeScreenBrightnessTest extends SysuiTestCase { DozeParameters mDozeParameters; @Mock DockManager mDockManager; + @Mock + DevicePostureController mDevicePostureController; + @Mock + DozeLog mDozeLog; private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock()); private FakeThreadFactory mFakeThreadFactory = new FakeThreadFactory(mFakeExecutor); @@ -111,9 +118,19 @@ public class DozeScreenBrightnessTest extends SysuiTestCase { mAlwaysOnDisplayPolicy.dimBrightness = DIM_BRIGHTNESS; mAlwaysOnDisplayPolicy.dimmingScrimArray = SENSOR_TO_OPACITY; mSensor = fakeSensorManager.getFakeLightSensor(); - mScreen = new DozeScreenBrightness(mContext, mServiceFake, mSensorManager, - Optional.of(mSensor.getSensor()), mDozeHost, null /* handler */, - mAlwaysOnDisplayPolicy, mWakefulnessLifecycle, mDozeParameters, mDockManager); + mSensorInner = fakeSensorManager.getFakeLightSensor2(); + mScreen = new DozeScreenBrightness( + mContext, + mServiceFake, + mSensorManager, + new Optional[]{Optional.of(mSensor.getSensor())}, + mDozeHost, + null /* handler */, + mAlwaysOnDisplayPolicy, + mWakefulnessLifecycle, + mDozeParameters, + mDevicePostureController, + mDozeLog); } @Test @@ -151,7 +168,7 @@ public class DozeScreenBrightnessTest extends SysuiTestCase { @Test public void doze_doesNotUseLightSensor() { - // GIVEN the device is docked and the display state changes to ON + // GIVEN the device is DOZE and the display state changes to ON mScreen.transitionTo(UNINITIALIZED, INITIALIZED); mScreen.transitionTo(INITIALIZED, DOZE); waitForSensorManager(); @@ -166,7 +183,7 @@ public class DozeScreenBrightnessTest extends SysuiTestCase { @Test public void aod_usesLightSensor() { - // GIVEN the device is docked and the display state changes to ON + // GIVEN the device is DOZE_AOD and the display state changes to ON mScreen.transitionTo(UNINITIALIZED, INITIALIZED); mScreen.transitionTo(INITIALIZED, DOZE_AOD); waitForSensorManager(); @@ -209,9 +226,17 @@ public class DozeScreenBrightnessTest extends SysuiTestCase { @Test public void testPulsing_withoutLightSensor_setsAoDDimmingScrimTransparent() throws Exception { - mScreen = new DozeScreenBrightness(mContext, mServiceFake, mSensorManager, - Optional.empty() /* sensor */, mDozeHost, null /* handler */, - mAlwaysOnDisplayPolicy, mWakefulnessLifecycle, mDozeParameters, mDockManager); + mScreen = new DozeScreenBrightness( + mContext, + mServiceFake, + mSensorManager, + new Optional[] {Optional.empty()} /* sensor */, + mDozeHost, null /* handler */, + mAlwaysOnDisplayPolicy, + mWakefulnessLifecycle, + mDozeParameters, + mDevicePostureController, + mDozeLog); mScreen.transitionTo(UNINITIALIZED, INITIALIZED); mScreen.transitionTo(INITIALIZED, DOZE); reset(mDozeHost); @@ -238,9 +263,17 @@ public class DozeScreenBrightnessTest extends SysuiTestCase { @Test public void testNullSensor() throws Exception { - mScreen = new DozeScreenBrightness(mContext, mServiceFake, mSensorManager, - Optional.empty() /* sensor */, mDozeHost, null /* handler */, - mAlwaysOnDisplayPolicy, mWakefulnessLifecycle, mDozeParameters, mDockManager); + mScreen = new DozeScreenBrightness( + mContext, + mServiceFake, + mSensorManager, + new Optional[]{Optional.empty()} /* sensor */, + mDozeHost, null /* handler */, + mAlwaysOnDisplayPolicy, + mWakefulnessLifecycle, + mDozeParameters, + mDevicePostureController, + mDozeLog); mScreen.transitionTo(UNINITIALIZED, INITIALIZED); mScreen.transitionTo(INITIALIZED, DOZE_AOD); @@ -249,6 +282,130 @@ public class DozeScreenBrightnessTest extends SysuiTestCase { } @Test + public void testSensorsSupportPostures_closed() throws Exception { + // GIVEN the device is CLOSED + when(mDevicePostureController.getDevicePosture()).thenReturn( + DevicePostureController.DEVICE_POSTURE_CLOSED); + + // GIVEN closed and opened postures use different light sensors + mScreen = new DozeScreenBrightness( + mContext, + mServiceFake, + mSensorManager, + new Optional[]{ + Optional.empty() /* unknown */, + Optional.of(mSensor.getSensor()) /* closed */, + Optional.of(mSensorInner.getSensor()) /* half-opened */, + Optional.of(mSensorInner.getSensor()) /* opened */, + Optional.empty() /* flipped */ + }, + mDozeHost, null /* handler */, + mAlwaysOnDisplayPolicy, + mWakefulnessLifecycle, + mDozeParameters, + mDevicePostureController, + mDozeLog); + + // GIVEN the device is in AOD + mScreen.transitionTo(UNINITIALIZED, INITIALIZED); + mScreen.transitionTo(INITIALIZED, DOZE_AOD); + waitForSensorManager(); + + // WHEN new different events are sent from the inner and outer sensors + mSensor.sendSensorEvent(3); // CLOSED sensor + mSensorInner.sendSensorEvent(4); // OPENED sensor + + // THEN brightness is updated according to the sensor for CLOSED + assertEquals(3, mServiceFake.screenBrightness); + } + + @Test + public void testSensorsSupportPostures_open() throws Exception { + // GIVEN the device is OPENED + when(mDevicePostureController.getDevicePosture()).thenReturn( + DevicePostureController.DEVICE_POSTURE_OPENED); + + // GIVEN closed and opened postures use different light sensors + mScreen = new DozeScreenBrightness( + mContext, + mServiceFake, + mSensorManager, + new Optional[]{ + Optional.empty() /* unknown */, + Optional.of(mSensor.getSensor()) /* closed */, + Optional.of(mSensorInner.getSensor()) /* half-opened */, + Optional.of(mSensorInner.getSensor()) /* opened */, + Optional.empty() /* flipped */ + }, + mDozeHost, null /* handler */, + mAlwaysOnDisplayPolicy, + mWakefulnessLifecycle, + mDozeParameters, + mDevicePostureController, + mDozeLog); + + // GIVEN device is in AOD + mScreen.transitionTo(UNINITIALIZED, INITIALIZED); + mScreen.transitionTo(INITIALIZED, DOZE_AOD); + waitForSensorManager(); + + // WHEN new different events are sent from the inner and outer sensors + mSensorInner.sendSensorEvent(4); // OPENED sensor + mSensor.sendSensorEvent(3); // CLOSED sensor + + // THEN brightness is updated according to the sensor for OPENED + assertEquals(4, mServiceFake.screenBrightness); + } + + @Test + public void testSensorsSupportPostures_swapPostures() throws Exception { + ArgumentCaptor<DevicePostureController.Callback> postureCallbackCaptor = + ArgumentCaptor.forClass(DevicePostureController.Callback.class); + reset(mDevicePostureController); + + // GIVEN the device starts up AOD OPENED + when(mDevicePostureController.getDevicePosture()).thenReturn( + DevicePostureController.DEVICE_POSTURE_OPENED); + + // GIVEN closed and opened postures use different light sensors + mScreen = new DozeScreenBrightness( + mContext, + mServiceFake, + mSensorManager, + new Optional[]{ + Optional.empty() /* unknown */, + Optional.of(mSensor.getSensor()) /* closed */, + Optional.of(mSensorInner.getSensor()) /* half-opened */, + Optional.of(mSensorInner.getSensor()) /* opened */, + Optional.empty() /* flipped */ + }, + mDozeHost, null /* handler */, + mAlwaysOnDisplayPolicy, + mWakefulnessLifecycle, + mDozeParameters, + mDevicePostureController, + mDozeLog); + verify(mDevicePostureController).addCallback(postureCallbackCaptor.capture()); + + // GIVEN device is in AOD + mScreen.transitionTo(UNINITIALIZED, INITIALIZED); + mScreen.transitionTo(INITIALIZED, DOZE_AOD); + waitForSensorManager(); + + // WHEN the posture changes to CLOSED + postureCallbackCaptor.getValue().onPostureChanged( + DevicePostureController.DEVICE_POSTURE_CLOSED); + waitForSensorManager(); + + // WHEN new different events are sent from the inner and outer sensors + mSensor.sendSensorEvent(3); // CLOSED sensor + mSensorInner.sendSensorEvent(4); // OPENED sensor + + // THEN brightness is updated according to the sensor for CLOSED + assertEquals(3, mServiceFake.screenBrightness); + } + + @Test public void testNoBrightnessDeliveredAfterFinish() throws Exception { mScreen.transitionTo(UNINITIALIZED, INITIALIZED); mScreen.transitionTo(INITIALIZED, DOZE_AOD); diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java index 42e34c81a790..f525fee27e20 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java @@ -91,9 +91,9 @@ public class DozeSensorsTest extends SysuiTestCase { @Mock private AuthController mAuthController; @Mock + private DevicePostureController mDevicePostureController; + @Mock private ProximitySensor mProximitySensor; - private @DevicePostureController.DevicePostureInt int mDevicePosture = - DevicePostureController.DEVICE_POSTURE_UNKNOWN; private FakeSettings mFakeSettings = new FakeSettings(); private SensorManagerPlugin.SensorEventListener mWakeLockScreenListener; private TestableLooper mTestableLooper; @@ -104,13 +104,14 @@ public class DozeSensorsTest extends SysuiTestCase { public void setUp() { MockitoAnnotations.initMocks(this); mTestableLooper = TestableLooper.get(this); + when(mAmbientDisplayConfiguration.tapSensorTypeMapping()) + .thenReturn(new String[]{"tapSEnsor"}); when(mAmbientDisplayConfiguration.getWakeLockScreenDebounce()).thenReturn(5000L); when(mAmbientDisplayConfiguration.alwaysOnEnabled(anyInt())).thenReturn(true); doAnswer(invocation -> { ((Runnable) invocation.getArgument(0)).run(); return null; }).when(mWakeLock).wrap(any(Runnable.class)); - mDevicePosture = DevicePostureController.DEVICE_POSTURE_UNKNOWN; mDozeSensors = new TestableDozeSensors(); } @@ -127,14 +128,14 @@ public class DozeSensorsTest extends SysuiTestCase { mWakeLockScreenListener.onSensorChanged(mock(SensorManagerPlugin.SensorEvent.class)); mTestableLooper.processAllMessages(); - verify(mCallback).onSensorPulse(eq(DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN), + verify(mCallback).onSensorPulse(eq(DozeLog.PULSE_REASON_SENSOR_WAKE_REACH), anyFloat(), anyFloat(), eq(null)); mDozeSensors.requestTemporaryDisable(); reset(mCallback); mWakeLockScreenListener.onSensorChanged(mock(SensorManagerPlugin.SensorEvent.class)); mTestableLooper.processAllMessages(); - verify(mCallback, never()).onSensorPulse(eq(DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN), + verify(mCallback, never()).onSensorPulse(eq(DozeLog.PULSE_REASON_SENSOR_WAKE_REACH), anyFloat(), anyFloat(), eq(null)); } @@ -269,15 +270,80 @@ public class DozeSensorsTest extends SysuiTestCase { } @Test - public void testPostureOpen_registersCorrectTapGesture() { - // GIVEN device posture open - mDevicePosture = DevicePostureController.DEVICE_POSTURE_OPENED; + public void testPostureStartStateClosed_registersCorrectSensor() throws Exception { + // GIVEN doze sensor that supports postures + Sensor closedSensor = createSensor(Sensor.TYPE_LIGHT, Sensor.STRING_TYPE_LIGHT); + Sensor openedSensor = createSensor(Sensor.TYPE_PROXIMITY, Sensor.STRING_TYPE_LIGHT); + TriggerSensor triggerSensor = mDozeSensors.createDozeSensor( + new Sensor[] { + null /* unknown */, + closedSensor, + null /* half-opened */, + openedSensor}, + DevicePostureController.DEVICE_POSTURE_CLOSED); + + // WHEN trigger sensor requests listening + triggerSensor.setListening(true); + + // THEN the correct sensor is registered + verify(mSensorManager).requestTriggerSensor(eq(triggerSensor), eq(closedSensor)); + verify(mSensorManager, never()).requestTriggerSensor(eq(triggerSensor), eq(openedSensor)); + } + + @Test + public void testPostureChange_registersCorrectSensor() throws Exception { + // GIVEN doze sensor that supports postures + Sensor closedSensor = createSensor(Sensor.TYPE_LIGHT, Sensor.STRING_TYPE_LIGHT); + Sensor openedSensor = createSensor(Sensor.TYPE_PROXIMITY, Sensor.STRING_TYPE_LIGHT); + TriggerSensor triggerSensor = mDozeSensors.createDozeSensor( + new Sensor[] { + null /* unknown */, + closedSensor, + null /* half-opened */, + openedSensor}, + DevicePostureController.DEVICE_POSTURE_CLOSED); + + // GIVEN sensor is listening + when(mSensorManager.requestTriggerSensor(any(), any())).thenReturn(true); + triggerSensor.setListening(true); + reset(mSensorManager); + assertTrue(triggerSensor.mRegistered); + + // WHEN posture changes + boolean sensorChanged = + triggerSensor.setPosture(DevicePostureController.DEVICE_POSTURE_OPENED); + + // THEN the correct sensor is registered + assertTrue(sensorChanged); + verify(mSensorManager).requestTriggerSensor(eq(triggerSensor), eq(openedSensor)); + verify(mSensorManager, never()).requestTriggerSensor(eq(triggerSensor), eq(closedSensor)); + } + + @Test + public void testPostureChange_noSensorChange() throws Exception { + // GIVEN doze sensor that supports postures + Sensor closedSensor = createSensor(Sensor.TYPE_LIGHT, Sensor.STRING_TYPE_LIGHT); + Sensor openedSensor = createSensor(Sensor.TYPE_PROXIMITY, Sensor.STRING_TYPE_LIGHT); + TriggerSensor triggerSensor = mDozeSensors.createDozeSensor( + new Sensor[] { + null /* unknown */, + closedSensor, + openedSensor /* half-opened uses the same sensor as opened*/, + openedSensor}, + DevicePostureController.DEVICE_POSTURE_HALF_OPENED); + + // GIVEN sensor is listening + when(mSensorManager.requestTriggerSensor(any(), any())).thenReturn(true); + triggerSensor.setListening(true); + reset(mSensorManager); - // WHEN DozeSensors are initialized - new TestableDozeSensors(); + // WHEN posture changes + boolean sensorChanged = + triggerSensor.setPosture(DevicePostureController.DEVICE_POSTURE_OPENED); - // THEN we use the posture to determine which tap sensor to use - verify(mAmbientDisplayConfiguration).tapSensorType(eq(mDevicePosture)); + // THEN no change in sensor + assertFalse(sensorChanged); + verify(mSensorManager, never()).requestTriggerSensor(eq(triggerSensor), any()); } @Test @@ -311,13 +377,12 @@ public class DozeSensorsTest extends SysuiTestCase { private class TestableDozeSensors extends DozeSensors { - TestableDozeSensors() { super(getContext(), mSensorManager, mDozeParameters, mAmbientDisplayConfiguration, mWakeLock, mCallback, mProxCallback, mDozeLog, mProximitySensor, mFakeSettings, mAuthController, - mDevicePosture); - for (TriggerSensor sensor : mSensors) { + mDevicePostureController); + for (TriggerSensor sensor : mTriggerSensors) { if (sensor instanceof PluginSensor && ((PluginSensor) sensor).mPluginSensor.getType() == TYPE_WAKE_LOCK_SCREEN) { @@ -326,7 +391,7 @@ public class DozeSensorsTest extends SysuiTestCase { mSensorTap = sensor; } } - mSensors = new TriggerSensor[] {mTriggerSensor, mSensorTap}; + mTriggerSensors = new TriggerSensor[] {mTriggerSensor, mSensorTap}; } public TriggerSensor createDozeSensor(Sensor sensor, boolean settingEnabled, @@ -337,8 +402,25 @@ public class DozeSensorsTest extends SysuiTestCase { /* configured */ true, /* pulseReason*/ 0, /* reportsTouchCoordinate*/ false, - requiresTouchScreen, - mDozeLog); + /* requiresTouchscreen */ false, + /* ignoresSetting */ false, + requiresTouchScreen); + } + + /** + * create a doze sensor that supports postures and is enabled + */ + public TriggerSensor createDozeSensor(Sensor[] sensors, int posture) { + return new TriggerSensor(/* sensor */ sensors, + /* setting name */ "test_setting", + /* settingDefault */ true, + /* configured */ true, + /* pulseReason*/ 0, + /* reportsTouchCoordinate*/ false, + /* requiresTouchscreen */ false, + /* ignoresSetting */ true, + /* requiresProx */false, + posture); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java index 31fa3f841b19..35dca7ef5fce 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java @@ -204,7 +204,7 @@ public class DozeTriggersTest extends SysuiTestCase { public void testProximitySensorNotAvailablel() { mProximitySensor.setSensorAvailable(false); mTriggers.onSensor(DozeLog.PULSE_REASON_SENSOR_LONG_PRESS, 100, 100, null); - mTriggers.onSensor(DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN, 100, 100, + mTriggers.onSensor(DozeLog.PULSE_REASON_SENSOR_WAKE_REACH, 100, 100, new float[]{1}); mTriggers.onSensor(DozeLog.REASON_SENSOR_TAP, 100, 100, null); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagManagerTest.java new file mode 100644 index 000000000000..172dcda5321f --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagManagerTest.java @@ -0,0 +1,46 @@ +/* + * 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.assertThat; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.SysuiTestCase; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.MockitoAnnotations; + +@SmallTest +public class FeatureFlagManagerTest extends SysuiTestCase { + FeatureFlagManager mFeatureFlagManager; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + + mFeatureFlagManager = new FeatureFlagManager(); + } + + @Test + public void testIsEnabled() { + mFeatureFlagManager.setEnabled(1, true); + // Again, nothing changes. + assertThat(mFeatureFlagManager.isEnabled(1, false)).isFalse(); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java index 0e344a6269b7..3b1c5f32a772 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java @@ -173,14 +173,14 @@ public class GlobalActionsDialogLiteTest extends SysuiTestCase { public void testShouldLogShow() { mGlobalActionsDialogLite.onShow(null); mTestableLooper.processAllMessages(); - verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_POWER_MENU_OPEN); + verifyLogPosted(GlobalActionsDialogLite.GlobalActionsEvent.GA_POWER_MENU_OPEN); } @Test public void testShouldLogDismiss() { mGlobalActionsDialogLite.onDismiss(mGlobalActionsDialogLite.mDialog); mTestableLooper.processAllMessages(); - verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_POWER_MENU_CLOSE); + verifyLogPosted(GlobalActionsDialogLite.GlobalActionsEvent.GA_POWER_MENU_CLOSE); } @Test @@ -190,16 +190,16 @@ public class GlobalActionsDialogLiteTest extends SysuiTestCase { doReturn(true).when(mGlobalActionsDialogLite).shouldDisplayLockdown(any()); doReturn(true).when(mGlobalActionsDialogLite).shouldShowAction(any()); String[] actions = { - GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY, - GlobalActionsDialog.GLOBAL_ACTION_KEY_LOCKDOWN, - GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER, - GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART, + GlobalActionsDialogLite.GLOBAL_ACTION_KEY_EMERGENCY, + GlobalActionsDialogLite.GLOBAL_ACTION_KEY_LOCKDOWN, + GlobalActionsDialogLite.GLOBAL_ACTION_KEY_POWER, + GlobalActionsDialogLite.GLOBAL_ACTION_KEY_RESTART, }; doReturn(actions).when(mGlobalActionsDialogLite).getDefaultActions(); GlobalActionsDialogLite.ActionsDialogLite dialog = mGlobalActionsDialogLite.createDialog(); dialog.onBackPressed(); mTestableLooper.processAllMessages(); - verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_CLOSE_BACK); + verifyLogPosted(GlobalActionsDialogLite.GlobalActionsEvent.GA_CLOSE_BACK); } @Test @@ -209,17 +209,17 @@ public class GlobalActionsDialogLiteTest extends SysuiTestCase { doReturn(true).when(mGlobalActionsDialogLite).shouldDisplayLockdown(any()); doReturn(true).when(mGlobalActionsDialogLite).shouldShowAction(any()); String[] actions = { - GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY, - GlobalActionsDialog.GLOBAL_ACTION_KEY_LOCKDOWN, - GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER, - GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART, + GlobalActionsDialogLite.GLOBAL_ACTION_KEY_EMERGENCY, + GlobalActionsDialogLite.GLOBAL_ACTION_KEY_LOCKDOWN, + GlobalActionsDialogLite.GLOBAL_ACTION_KEY_POWER, + GlobalActionsDialogLite.GLOBAL_ACTION_KEY_RESTART, }; doReturn(actions).when(mGlobalActionsDialogLite).getDefaultActions(); GlobalActionsDialogLite.ActionsDialogLite dialog = mGlobalActionsDialogLite.createDialog(); GestureDetector.SimpleOnGestureListener gestureListener = spy(dialog.mGestureListener); gestureListener.onSingleTapConfirmed(null); - verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_CLOSE_TAP_OUTSIDE); + verifyLogPosted(GlobalActionsDialogLite.GlobalActionsEvent.GA_CLOSE_TAP_OUTSIDE); } @Test @@ -230,10 +230,10 @@ public class GlobalActionsDialogLiteTest extends SysuiTestCase { doReturn(true).when(mGlobalActionsDialogLite).shouldShowAction(any()); doReturn(true).when(mStatusBar).isKeyguardShowing(); String[] actions = { - GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY, - GlobalActionsDialog.GLOBAL_ACTION_KEY_LOCKDOWN, - GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER, - GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART, + GlobalActionsDialogLite.GLOBAL_ACTION_KEY_EMERGENCY, + GlobalActionsDialogLite.GLOBAL_ACTION_KEY_LOCKDOWN, + GlobalActionsDialogLite.GLOBAL_ACTION_KEY_POWER, + GlobalActionsDialogLite.GLOBAL_ACTION_KEY_RESTART, }; doReturn(actions).when(mGlobalActionsDialogLite).getDefaultActions(); GlobalActionsDialogLite.ActionsDialogLite dialog = mGlobalActionsDialogLite.createDialog(); @@ -242,7 +242,7 @@ public class GlobalActionsDialogLiteTest extends SysuiTestCase { MotionEvent start = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0); MotionEvent end = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 500, 0); gestureListener.onFling(start, end, 0, 1000); - verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_CLOSE_TAP_OUTSIDE); + verifyLogPosted(GlobalActionsDialogLite.GlobalActionsEvent.GA_CLOSE_TAP_OUTSIDE); verify(mStatusBar).animateExpandSettingsPanel(null); } @@ -254,10 +254,10 @@ public class GlobalActionsDialogLiteTest extends SysuiTestCase { doReturn(true).when(mGlobalActionsDialogLite).shouldShowAction(any()); doReturn(false).when(mStatusBar).isKeyguardShowing(); String[] actions = { - GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY, - GlobalActionsDialog.GLOBAL_ACTION_KEY_LOCKDOWN, - GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER, - GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART, + GlobalActionsDialogLite.GLOBAL_ACTION_KEY_EMERGENCY, + GlobalActionsDialogLite.GLOBAL_ACTION_KEY_LOCKDOWN, + GlobalActionsDialogLite.GLOBAL_ACTION_KEY_POWER, + GlobalActionsDialogLite.GLOBAL_ACTION_KEY_RESTART, }; doReturn(actions).when(mGlobalActionsDialogLite).getDefaultActions(); GlobalActionsDialogLite.ActionsDialogLite dialog = mGlobalActionsDialogLite.createDialog(); @@ -266,40 +266,40 @@ public class GlobalActionsDialogLiteTest extends SysuiTestCase { MotionEvent start = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0); MotionEvent end = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 500, 0); gestureListener.onFling(start, end, 0, 1000); - verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_CLOSE_TAP_OUTSIDE); + verifyLogPosted(GlobalActionsDialogLite.GlobalActionsEvent.GA_CLOSE_TAP_OUTSIDE); verify(mStatusBar).animateExpandNotificationsPanel(); } @Test public void testShouldLogBugreportPress() throws InterruptedException { - GlobalActionsDialog.BugReportAction bugReportAction = + GlobalActionsDialogLite.BugReportAction bugReportAction = mGlobalActionsDialogLite.makeBugReportActionForTesting(); bugReportAction.onPress(); - verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_BUGREPORT_PRESS); + verifyLogPosted(GlobalActionsDialogLite.GlobalActionsEvent.GA_BUGREPORT_PRESS); } @Test public void testShouldLogBugreportLongPress() { - GlobalActionsDialog.BugReportAction bugReportAction = + GlobalActionsDialogLite.BugReportAction bugReportAction = mGlobalActionsDialogLite.makeBugReportActionForTesting(); bugReportAction.onLongPress(); - verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_BUGREPORT_LONG_PRESS); + verifyLogPosted(GlobalActionsDialogLite.GlobalActionsEvent.GA_BUGREPORT_LONG_PRESS); } @Test public void testShouldLogEmergencyDialerPress() { - GlobalActionsDialog.EmergencyDialerAction emergencyDialerAction = + GlobalActionsDialogLite.EmergencyDialerAction emergencyDialerAction = mGlobalActionsDialogLite.makeEmergencyDialerActionForTesting(); emergencyDialerAction.onPress(); - verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_EMERGENCY_DIALER_PRESS); + verifyLogPosted(GlobalActionsDialogLite.GlobalActionsEvent.GA_EMERGENCY_DIALER_PRESS); } @Test public void testShouldLogScreenshotPress() { - GlobalActionsDialog.ScreenshotAction screenshotAction = + GlobalActionsDialogLite.ScreenshotAction screenshotAction = mGlobalActionsDialogLite.makeScreenshotActionForTesting(); screenshotAction.onPress(); - verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_SCREENSHOT_PRESS); + verifyLogPosted(GlobalActionsDialogLite.GlobalActionsEvent.GA_SCREENSHOT_PRESS); } @Test @@ -308,7 +308,7 @@ public class GlobalActionsDialogLiteTest extends SysuiTestCase { com.android.internal.R.integer.config_navBarInteractionMode, WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON); - GlobalActionsDialog.ScreenshotAction screenshotAction = + GlobalActionsDialogLite.ScreenshotAction screenshotAction = mGlobalActionsDialogLite.makeScreenshotActionForTesting(); assertThat(screenshotAction.shouldShow()).isTrue(); } @@ -319,12 +319,12 @@ public class GlobalActionsDialogLiteTest extends SysuiTestCase { com.android.internal.R.integer.config_navBarInteractionMode, WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON); - GlobalActionsDialog.ScreenshotAction screenshotAction = + GlobalActionsDialogLite.ScreenshotAction screenshotAction = mGlobalActionsDialogLite.makeScreenshotActionForTesting(); assertThat(screenshotAction.shouldShow()).isFalse(); } - private void verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent event) { + private void verifyLogPosted(GlobalActionsDialogLite.GlobalActionsEvent event) { mTestableLooper.processAllMessages(); verify(mUiEventLogger, times(1)) .log(event); @@ -345,19 +345,19 @@ public class GlobalActionsDialogLiteTest extends SysuiTestCase { doReturn(true).when(mGlobalActionsDialogLite).shouldDisplayLockdown(any()); doReturn(true).when(mGlobalActionsDialogLite).shouldShowAction(any()); String[] actions = { - GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY, - GlobalActionsDialog.GLOBAL_ACTION_KEY_LOCKDOWN, - GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER, - GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART, + GlobalActionsDialogLite.GLOBAL_ACTION_KEY_EMERGENCY, + GlobalActionsDialogLite.GLOBAL_ACTION_KEY_LOCKDOWN, + GlobalActionsDialogLite.GLOBAL_ACTION_KEY_POWER, + GlobalActionsDialogLite.GLOBAL_ACTION_KEY_RESTART, }; doReturn(actions).when(mGlobalActionsDialogLite).getDefaultActions(); mGlobalActionsDialogLite.createActionItems(); assertItemsOfType(mGlobalActionsDialogLite.mItems, - GlobalActionsDialog.EmergencyAction.class, - GlobalActionsDialog.LockDownAction.class, - GlobalActionsDialog.ShutDownAction.class, - GlobalActionsDialog.RestartAction.class); + GlobalActionsDialogLite.EmergencyAction.class, + GlobalActionsDialogLite.LockDownAction.class, + GlobalActionsDialogLite.ShutDownAction.class, + GlobalActionsDialogLite.RestartAction.class); assertThat(mGlobalActionsDialogLite.mOverflowItems).isEmpty(); assertThat(mGlobalActionsDialogLite.mPowerItems).isEmpty(); } @@ -369,19 +369,19 @@ public class GlobalActionsDialogLiteTest extends SysuiTestCase { // make sure lockdown action will NOT be shown doReturn(false).when(mGlobalActionsDialogLite).shouldDisplayLockdown(any()); String[] actions = { - GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY, + GlobalActionsDialogLite.GLOBAL_ACTION_KEY_EMERGENCY, // lockdown action not allowed - GlobalActionsDialog.GLOBAL_ACTION_KEY_LOCKDOWN, - GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER, - GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART, + GlobalActionsDialogLite.GLOBAL_ACTION_KEY_LOCKDOWN, + GlobalActionsDialogLite.GLOBAL_ACTION_KEY_POWER, + GlobalActionsDialogLite.GLOBAL_ACTION_KEY_RESTART, }; doReturn(actions).when(mGlobalActionsDialogLite).getDefaultActions(); mGlobalActionsDialogLite.createActionItems(); assertItemsOfType(mGlobalActionsDialogLite.mItems, - GlobalActionsDialog.EmergencyAction.class, - GlobalActionsDialog.ShutDownAction.class, - GlobalActionsDialog.RestartAction.class); + GlobalActionsDialogLite.EmergencyAction.class, + GlobalActionsDialogLite.ShutDownAction.class, + GlobalActionsDialogLite.RestartAction.class); assertThat(mGlobalActionsDialogLite.mOverflowItems).isEmpty(); assertThat(mGlobalActionsDialogLite.mPowerItems).isEmpty(); } @@ -391,7 +391,7 @@ public class GlobalActionsDialogLiteTest extends SysuiTestCase { GlobalActionsDialogLite.LockDownAction lockDownAction = mGlobalActionsDialogLite.new LockDownAction(); lockDownAction.onPress(); - verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_LOCKDOWN_PRESS); + verifyLogPosted(GlobalActionsDialogLite.GlobalActionsEvent.GA_LOCKDOWN_PRESS); } @Test @@ -399,7 +399,7 @@ public class GlobalActionsDialogLiteTest extends SysuiTestCase { GlobalActionsDialogLite.ShutDownAction shutDownAction = mGlobalActionsDialogLite.new ShutDownAction(); shutDownAction.onPress(); - verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_SHUTDOWN_PRESS); + verifyLogPosted(GlobalActionsDialogLite.GlobalActionsEvent.GA_SHUTDOWN_PRESS); } @Test @@ -407,7 +407,7 @@ public class GlobalActionsDialogLiteTest extends SysuiTestCase { GlobalActionsDialogLite.ShutDownAction shutDownAction = mGlobalActionsDialogLite.new ShutDownAction(); shutDownAction.onLongPress(); - verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_SHUTDOWN_LONG_PRESS); + verifyLogPosted(GlobalActionsDialogLite.GlobalActionsEvent.GA_SHUTDOWN_LONG_PRESS); } @Test @@ -415,7 +415,7 @@ public class GlobalActionsDialogLiteTest extends SysuiTestCase { GlobalActionsDialogLite.RestartAction restartAction = mGlobalActionsDialogLite.new RestartAction(); restartAction.onPress(); - verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_REBOOT_PRESS); + verifyLogPosted(GlobalActionsDialogLite.GlobalActionsEvent.GA_REBOOT_PRESS); } @Test @@ -423,7 +423,7 @@ public class GlobalActionsDialogLiteTest extends SysuiTestCase { GlobalActionsDialogLite.RestartAction restartAction = mGlobalActionsDialogLite.new RestartAction(); restartAction.onLongPress(); - verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_REBOOT_LONG_PRESS); + verifyLogPosted(GlobalActionsDialogLite.GlobalActionsEvent.GA_REBOOT_LONG_PRESS); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java deleted file mode 100644 index f8ab42fe3df5..000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java +++ /dev/null @@ -1,576 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.globalactions; - -import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.app.IActivityManager; -import android.app.admin.DevicePolicyManager; -import android.app.trust.TrustManager; -import android.content.pm.PackageManager; -import android.content.pm.UserInfo; -import android.content.res.Resources; -import android.graphics.Color; -import android.media.AudioManager; -import android.os.Handler; -import android.os.RemoteException; -import android.os.UserManager; -import android.service.dreams.IDreamManager; -import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; -import android.view.IWindowManager; -import android.view.View; -import android.view.WindowManagerPolicyConstants; -import android.widget.FrameLayout; - -import androidx.test.filters.SmallTest; - -import com.android.internal.colorextraction.ColorExtractor; -import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.UiEventLogger; -import com.android.internal.statusbar.IStatusBarService; -import com.android.internal.widget.LockPatternUtils; -import com.android.keyguard.KeyguardUpdateMonitor; -import com.android.systemui.SysuiTestCase; -import com.android.systemui.broadcast.BroadcastDispatcher; -import com.android.systemui.colorextraction.SysuiColorExtractor; -import com.android.systemui.model.SysUiState; -import com.android.systemui.plugins.ActivityStarter; -import com.android.systemui.plugins.GlobalActions; -import com.android.systemui.plugins.GlobalActionsPanelPlugin; -import com.android.systemui.settings.UserTracker; -import com.android.systemui.statusbar.NotificationShadeWindowController; -import com.android.systemui.statusbar.phone.StatusBar; -import com.android.systemui.statusbar.policy.ConfigurationController; -import com.android.systemui.statusbar.policy.KeyguardStateController; -import com.android.systemui.telephony.TelephonyListenerManager; -import com.android.systemui.util.RingerModeLiveData; -import com.android.systemui.util.RingerModeTracker; -import com.android.systemui.util.settings.GlobalSettings; -import com.android.systemui.util.settings.SecureSettings; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import java.util.List; -import java.util.Optional; -import java.util.concurrent.Executor; -import java.util.regex.Pattern; - -@SmallTest -@RunWith(AndroidTestingRunner.class) -@TestableLooper.RunWithLooper(setAsMainLooper = true) -public class GlobalActionsDialogTest extends SysuiTestCase { - private static final long UI_TIMEOUT_MILLIS = 5000; // 5 sec - private static final Pattern CANCEL_BUTTON = - Pattern.compile("cancel", Pattern.CASE_INSENSITIVE); - - private GlobalActionsDialog mGlobalActionsDialog; - - @Mock private GlobalActions.GlobalActionsManager mWindowManagerFuncs; - @Mock private AudioManager mAudioManager; - @Mock private IDreamManager mDreamManager; - @Mock private DevicePolicyManager mDevicePolicyManager; - @Mock private LockPatternUtils mLockPatternUtils; - @Mock private BroadcastDispatcher mBroadcastDispatcher; - @Mock private TelephonyListenerManager mTelephonyListenerManager; - @Mock private GlobalSettings mGlobalSettings; - @Mock private Resources mResources; - @Mock private ConfigurationController mConfigurationController; - @Mock private ActivityStarter mActivityStarter; - @Mock private KeyguardStateController mKeyguardStateController; - @Mock private UserManager mUserManager; - @Mock private TrustManager mTrustManager; - @Mock private IActivityManager mActivityManager; - @Mock private MetricsLogger mMetricsLogger; - @Mock private SysuiColorExtractor mColorExtractor; - @Mock private IStatusBarService mStatusBarService; - @Mock private NotificationShadeWindowController mNotificationShadeWindowController; - @Mock private IWindowManager mWindowManager; - @Mock private Executor mBackgroundExecutor; - @Mock private UiEventLogger mUiEventLogger; - @Mock private RingerModeTracker mRingerModeTracker; - @Mock private RingerModeLiveData mRingerModeLiveData; - @Mock private SysUiState mSysUiState; - @Mock GlobalActionsPanelPlugin mWalletPlugin; - @Mock GlobalActionsPanelPlugin.PanelViewController mWalletController; - @Mock private Handler mHandler; - @Mock private UserTracker mUserTracker; - @Mock private PackageManager mPackageManager; - @Mock private SecureSettings mSecureSettings; - @Mock private StatusBar mStatusBar; - @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor; - - private TestableLooper mTestableLooper; - - @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - mTestableLooper = TestableLooper.get(this); - allowTestableLooperAsMainThread(); - - when(mRingerModeTracker.getRingerMode()).thenReturn(mRingerModeLiveData); - when(mResources.getConfiguration()).thenReturn( - getContext().getResources().getConfiguration()); - - mGlobalActionsDialog = new GlobalActionsDialog(mContext, - mWindowManagerFuncs, - mAudioManager, - mDreamManager, - mDevicePolicyManager, - mLockPatternUtils, - mBroadcastDispatcher, - mTelephonyListenerManager, - mGlobalSettings, - mSecureSettings, - null, - mResources, - mConfigurationController, - mActivityStarter, - mKeyguardStateController, - mUserManager, - mTrustManager, - mActivityManager, - null, - mMetricsLogger, - mColorExtractor, - mStatusBarService, - mNotificationShadeWindowController, - mWindowManager, - mBackgroundExecutor, - mUiEventLogger, - mRingerModeTracker, - mSysUiState, - mHandler, - mPackageManager, - Optional.of(mStatusBar), - mKeyguardUpdateMonitor - ); - mGlobalActionsDialog.setZeroDialogPressDelayForTesting(); - - ColorExtractor.GradientColors backdropColors = new ColorExtractor.GradientColors(); - backdropColors.setMainColor(Color.BLACK); - when(mColorExtractor.getNeutralColors()).thenReturn(backdropColors); - when(mSysUiState.setFlag(anyInt(), anyBoolean())).thenReturn(mSysUiState); - } - - @Test - public void testShouldLogShow() { - mGlobalActionsDialog.onShow(null); - mTestableLooper.processAllMessages(); - verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_POWER_MENU_OPEN); - } - - @Test - public void testShouldLogDismiss() { - mGlobalActionsDialog.onDismiss(mGlobalActionsDialog.mDialog); - mTestableLooper.processAllMessages(); - verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_POWER_MENU_CLOSE); - } - - @Test - public void testShouldLogBugreportPress() throws InterruptedException { - GlobalActionsDialog.BugReportAction bugReportAction = - mGlobalActionsDialog.makeBugReportActionForTesting(); - bugReportAction.onPress(); - verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_BUGREPORT_PRESS); - } - - @Test - public void testShouldLogBugreportLongPress() { - GlobalActionsDialog.BugReportAction bugReportAction = - mGlobalActionsDialog.makeBugReportActionForTesting(); - bugReportAction.onLongPress(); - verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_BUGREPORT_LONG_PRESS); - } - - @Test - public void testShouldLogEmergencyDialerPress() { - GlobalActionsDialog.EmergencyDialerAction emergencyDialerAction = - mGlobalActionsDialog.makeEmergencyDialerActionForTesting(); - emergencyDialerAction.onPress(); - verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_EMERGENCY_DIALER_PRESS); - } - - @Test - public void testShouldLogScreenshotPress() { - GlobalActionsDialog.ScreenshotAction screenshotAction = - mGlobalActionsDialog.makeScreenshotActionForTesting(); - screenshotAction.onPress(); - verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_SCREENSHOT_PRESS); - } - - @Test - public void testShouldShowScreenshot() { - mContext.getOrCreateTestableResources().addOverride( - com.android.internal.R.integer.config_navBarInteractionMode, - WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON); - - GlobalActionsDialog.ScreenshotAction screenshotAction = - mGlobalActionsDialog.makeScreenshotActionForTesting(); - assertThat(screenshotAction.shouldShow()).isTrue(); - } - - @Test - public void testShouldNotShowScreenshot() { - mContext.getOrCreateTestableResources().addOverride( - com.android.internal.R.integer.config_navBarInteractionMode, - WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON); - - GlobalActionsDialog.ScreenshotAction screenshotAction = - mGlobalActionsDialog.makeScreenshotActionForTesting(); - assertThat(screenshotAction.shouldShow()).isFalse(); - } - - private void verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent event) { - mTestableLooper.processAllMessages(); - verify(mUiEventLogger, times(1)) - .log(event); - } - - @SafeVarargs - private static <T> void assertItemsOfType(List<T> stuff, Class<? extends T>... classes) { - assertThat(stuff).hasSize(classes.length); - for (int i = 0; i < stuff.size(); i++) { - assertThat(stuff.get(i)).isInstanceOf(classes[i]); - } - } - - @Test - public void testCreateActionItems_maxThree_noOverflow() { - mGlobalActionsDialog = spy(mGlobalActionsDialog); - // allow 3 items to be shown - doReturn(3).when(mGlobalActionsDialog).getMaxShownPowerItems(); - // ensure items are not blocked by keyguard or device provisioning - doReturn(true).when(mGlobalActionsDialog).shouldShowAction(any()); - String[] actions = { - GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY, - GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER, - GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART, - }; - doReturn(actions).when(mGlobalActionsDialog).getDefaultActions(); - mGlobalActionsDialog.createActionItems(); - - assertItemsOfType(mGlobalActionsDialog.mItems, - GlobalActionsDialog.EmergencyAction.class, - GlobalActionsDialog.ShutDownAction.class, - GlobalActionsDialog.RestartAction.class); - assertThat(mGlobalActionsDialog.mOverflowItems).isEmpty(); - assertThat(mGlobalActionsDialog.mPowerItems).isEmpty(); - } - - @Test - public void testCreateActionItems_maxThree_condensePower() { - mGlobalActionsDialog = spy(mGlobalActionsDialog); - // allow 3 items to be shown - doReturn(3).when(mGlobalActionsDialog).getMaxShownPowerItems(); - // ensure items are not blocked by keyguard or device provisioning - doReturn(true).when(mGlobalActionsDialog).shouldShowAction(any()); - // make sure lockdown action will be shown - doReturn(true).when(mGlobalActionsDialog).shouldDisplayLockdown(any()); - String[] actions = { - GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY, - GlobalActionsDialog.GLOBAL_ACTION_KEY_LOCKDOWN, - GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER, - GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART, - }; - doReturn(actions).when(mGlobalActionsDialog).getDefaultActions(); - mGlobalActionsDialog.createActionItems(); - - assertItemsOfType(mGlobalActionsDialog.mItems, - GlobalActionsDialog.EmergencyAction.class, - GlobalActionsDialog.LockDownAction.class, - GlobalActionsDialog.PowerOptionsAction.class); - assertThat(mGlobalActionsDialog.mOverflowItems).isEmpty(); - assertItemsOfType(mGlobalActionsDialog.mPowerItems, - GlobalActionsDialog.ShutDownAction.class, - GlobalActionsDialog.RestartAction.class); - } - - @Test - public void testCreateActionItems_maxThree_condensePower_splitPower() { - mGlobalActionsDialog = spy(mGlobalActionsDialog); - // allow 3 items to be shown - doReturn(3).when(mGlobalActionsDialog).getMaxShownPowerItems(); - // make sure lockdown action will be shown - doReturn(true).when(mGlobalActionsDialog).shouldDisplayLockdown(any()); - // make sure bugreport also shown - doReturn(true).when(mGlobalActionsDialog).shouldDisplayBugReport(any()); - // ensure items are not blocked by keyguard or device provisioning - doReturn(true).when(mGlobalActionsDialog).shouldShowAction(any()); - String[] actions = { - GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY, - GlobalActionsDialog.GLOBAL_ACTION_KEY_LOCKDOWN, - GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER, - GlobalActionsDialog.GLOBAL_ACTION_KEY_BUGREPORT, - GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART, - }; - doReturn(actions).when(mGlobalActionsDialog).getDefaultActions(); - mGlobalActionsDialog.createActionItems(); - - assertItemsOfType(mGlobalActionsDialog.mItems, - GlobalActionsDialog.EmergencyAction.class, - GlobalActionsDialog.LockDownAction.class, - GlobalActionsDialog.PowerOptionsAction.class); - assertItemsOfType(mGlobalActionsDialog.mOverflowItems, - GlobalActionsDialog.BugReportAction.class); - assertItemsOfType(mGlobalActionsDialog.mPowerItems, - GlobalActionsDialog.ShutDownAction.class, - GlobalActionsDialog.RestartAction.class); - } - - @Test - public void testCreateActionItems_maxFour_condensePower() { - mGlobalActionsDialog = spy(mGlobalActionsDialog); - // allow 3 items to be shown - doReturn(4).when(mGlobalActionsDialog).getMaxShownPowerItems(); - // make sure lockdown action will be shown - doReturn(true).when(mGlobalActionsDialog).shouldDisplayLockdown(any()); - // ensure items are not blocked by keyguard or device provisioning - doReturn(true).when(mGlobalActionsDialog).shouldShowAction(any()); - String[] actions = { - GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY, - GlobalActionsDialog.GLOBAL_ACTION_KEY_LOCKDOWN, - GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER, - GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART, - GlobalActionsDialog.GLOBAL_ACTION_KEY_SCREENSHOT - }; - doReturn(actions).when(mGlobalActionsDialog).getDefaultActions(); - mGlobalActionsDialog.createActionItems(); - - assertItemsOfType(mGlobalActionsDialog.mItems, - GlobalActionsDialog.EmergencyAction.class, - GlobalActionsDialog.LockDownAction.class, - GlobalActionsDialog.PowerOptionsAction.class, - GlobalActionsDialog.ScreenshotAction.class); - assertThat(mGlobalActionsDialog.mOverflowItems).isEmpty(); - assertItemsOfType(mGlobalActionsDialog.mPowerItems, - GlobalActionsDialog.ShutDownAction.class, - GlobalActionsDialog.RestartAction.class); - } - - @Test - public void testCreateActionItems_maxThree_doNotCondensePower() { - mGlobalActionsDialog = spy(mGlobalActionsDialog); - // allow 3 items to be shown - doReturn(3).when(mGlobalActionsDialog).getMaxShownPowerItems(); - // make sure lockdown action will be shown - doReturn(true).when(mGlobalActionsDialog).shouldDisplayLockdown(any()); - // make sure bugreport is also shown - doReturn(true).when(mGlobalActionsDialog).shouldDisplayBugReport(any()); - // ensure items are not blocked by keyguard or device provisioning - doReturn(true).when(mGlobalActionsDialog).shouldShowAction(any()); - String[] actions = { - GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY, - GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER, - GlobalActionsDialog.GLOBAL_ACTION_KEY_BUGREPORT, - GlobalActionsDialog.GLOBAL_ACTION_KEY_LOCKDOWN, - }; - doReturn(actions).when(mGlobalActionsDialog).getDefaultActions(); - mGlobalActionsDialog.createActionItems(); - - assertItemsOfType(mGlobalActionsDialog.mItems, - GlobalActionsDialog.EmergencyAction.class, - GlobalActionsDialog.ShutDownAction.class, - GlobalActionsDialog.BugReportAction.class); - assertItemsOfType(mGlobalActionsDialog.mOverflowItems, - GlobalActionsDialog.LockDownAction.class); - assertThat(mGlobalActionsDialog.mPowerItems).isEmpty(); - } - - @Test - public void testCreateActionItems_maxAny() { - mGlobalActionsDialog = spy(mGlobalActionsDialog); - // allow any number of power menu items to be shown - doReturn(Integer.MAX_VALUE).when(mGlobalActionsDialog).getMaxShownPowerItems(); - // ensure items are not blocked by keyguard or device provisioning - doReturn(true).when(mGlobalActionsDialog).shouldShowAction(any()); - // make sure lockdown action will be shown - doReturn(true).when(mGlobalActionsDialog).shouldDisplayLockdown(any()); - String[] actions = { - GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY, - GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER, - GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART, - GlobalActionsDialog.GLOBAL_ACTION_KEY_LOCKDOWN, - }; - doReturn(actions).when(mGlobalActionsDialog).getDefaultActions(); - mGlobalActionsDialog.createActionItems(); - - assertItemsOfType(mGlobalActionsDialog.mItems, - GlobalActionsDialog.EmergencyAction.class, - GlobalActionsDialog.ShutDownAction.class, - GlobalActionsDialog.RestartAction.class, - GlobalActionsDialog.LockDownAction.class); - assertThat(mGlobalActionsDialog.mOverflowItems).isEmpty(); - assertThat(mGlobalActionsDialog.mPowerItems).isEmpty(); - } - - @Test - public void testCreateActionItems_maxThree_lockdownDisabled_doesNotShowLockdown() { - mGlobalActionsDialog = spy(mGlobalActionsDialog); - // allow only 3 items to be shown - doReturn(3).when(mGlobalActionsDialog).getMaxShownPowerItems(); - // make sure lockdown action will NOT be shown - doReturn(false).when(mGlobalActionsDialog).shouldDisplayLockdown(any()); - String[] actions = { - GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY, - // lockdown action not allowed - GlobalActionsDialog.GLOBAL_ACTION_KEY_LOCKDOWN, - GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER, - GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART, - }; - doReturn(actions).when(mGlobalActionsDialog).getDefaultActions(); - mGlobalActionsDialog.createActionItems(); - - assertItemsOfType(mGlobalActionsDialog.mItems, - GlobalActionsDialog.EmergencyAction.class, - GlobalActionsDialog.ShutDownAction.class, - GlobalActionsDialog.RestartAction.class); - assertThat(mGlobalActionsDialog.mOverflowItems).isEmpty(); - assertThat(mGlobalActionsDialog.mPowerItems).isEmpty(); - } - - @Test - public void testCreateActionItems_shouldShowAction_excludeBugReport() { - mGlobalActionsDialog = spy(mGlobalActionsDialog); - // allow only 3 items to be shown - doReturn(3).when(mGlobalActionsDialog).getMaxShownPowerItems(); - doReturn(true).when(mGlobalActionsDialog).shouldDisplayBugReport(any()); - // exclude bugreport in shouldShowAction to demonstrate how any button can be removed - doAnswer( - invocation -> !(invocation.getArgument(0) - instanceof GlobalActionsDialog.BugReportAction)) - .when(mGlobalActionsDialog).shouldShowAction(any()); - - String[] actions = { - GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY, - // bugreport action not allowed - GlobalActionsDialog.GLOBAL_ACTION_KEY_BUGREPORT, - GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER, - GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART, - }; - doReturn(actions).when(mGlobalActionsDialog).getDefaultActions(); - mGlobalActionsDialog.createActionItems(); - - assertItemsOfType(mGlobalActionsDialog.mItems, - GlobalActionsDialog.EmergencyAction.class, - GlobalActionsDialog.ShutDownAction.class, - GlobalActionsDialog.RestartAction.class); - assertThat(mGlobalActionsDialog.mOverflowItems).isEmpty(); - assertThat(mGlobalActionsDialog.mPowerItems).isEmpty(); - } - - @Test - public void testShouldShowLockScreenMessage() throws RemoteException { - mGlobalActionsDialog = spy(mGlobalActionsDialog); - mGlobalActionsDialog.mDialog = null; - when(mKeyguardStateController.isUnlocked()).thenReturn(false); - when(mActivityManager.getCurrentUser()).thenReturn(newUserInfo()); - when(mLockPatternUtils.getStrongAuthForUser(anyInt())).thenReturn(STRONG_AUTH_NOT_REQUIRED); - mGlobalActionsDialog.mShowLockScreenCards = false; - setupDefaultActions(); - when(mWalletPlugin.onPanelShown(any(), anyBoolean())).thenReturn(mWalletController); - when(mWalletController.getPanelContent()).thenReturn(new FrameLayout(mContext)); - - mGlobalActionsDialog.showOrHideDialog(false, true, mWalletPlugin); - - GlobalActionsDialog.ActionsDialog dialog = - (GlobalActionsDialog.ActionsDialog) mGlobalActionsDialog.mDialog; - assertThat(dialog).isNotNull(); - assertThat(dialog.mLockMessageContainer.getVisibility()).isEqualTo(View.VISIBLE); - - // Dismiss the dialog so that it does not pollute other tests - mGlobalActionsDialog.showOrHideDialog(false, true, mWalletPlugin); - } - - @Test - public void testShouldNotShowLockScreenMessage_whenWalletShownOnLockScreen() - throws RemoteException { - mGlobalActionsDialog = spy(mGlobalActionsDialog); - mGlobalActionsDialog.mDialog = null; - when(mKeyguardStateController.isUnlocked()).thenReturn(false); - when(mActivityManager.getCurrentUser()).thenReturn(newUserInfo()); - when(mLockPatternUtils.getStrongAuthForUser(anyInt())).thenReturn(STRONG_AUTH_NOT_REQUIRED); - mGlobalActionsDialog.mShowLockScreenCards = true; - setupDefaultActions(); - when(mWalletPlugin.onPanelShown(any(), anyBoolean())).thenReturn(mWalletController); - when(mWalletController.getPanelContent()).thenReturn(new FrameLayout(mContext)); - - mGlobalActionsDialog.showOrHideDialog(false, true, mWalletPlugin); - - GlobalActionsDialog.ActionsDialog dialog = - (GlobalActionsDialog.ActionsDialog) mGlobalActionsDialog.mDialog; - assertThat(dialog).isNotNull(); - assertThat(dialog.mLockMessageContainer.getVisibility()).isEqualTo(View.GONE); - - // Dismiss the dialog so that it does not pollute other tests - mGlobalActionsDialog.showOrHideDialog(false, true, mWalletPlugin); - } - - @Test - public void testShouldNotShowLockScreenMessage_whenWalletBothDisabled() - throws RemoteException { - mGlobalActionsDialog = spy(mGlobalActionsDialog); - mGlobalActionsDialog.mDialog = null; - when(mKeyguardStateController.isUnlocked()).thenReturn(false); - - when(mActivityManager.getCurrentUser()).thenReturn(newUserInfo()); - when(mLockPatternUtils.getStrongAuthForUser(anyInt())).thenReturn(STRONG_AUTH_NOT_REQUIRED); - mGlobalActionsDialog.mShowLockScreenCards = true; - setupDefaultActions(); - when(mWalletPlugin.onPanelShown(any(), anyBoolean())).thenReturn(mWalletController); - when(mWalletController.getPanelContent()).thenReturn(null); - - mGlobalActionsDialog.showOrHideDialog(false, true, mWalletPlugin); - - GlobalActionsDialog.ActionsDialog dialog = - (GlobalActionsDialog.ActionsDialog) mGlobalActionsDialog.mDialog; - assertThat(dialog).isNotNull(); - assertThat(dialog.mLockMessageContainer.getVisibility()).isEqualTo(View.GONE); - - // Dismiss the dialog so that it does not pollute other tests - mGlobalActionsDialog.showOrHideDialog(false, true, mWalletPlugin); - } - - private UserInfo newUserInfo() { - return new UserInfo(0, null, null, UserInfo.FLAG_PRIMARY, null); - } - - private void setupDefaultActions() { - String[] actions = { - GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY, - GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER, - GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART, - }; - doReturn(actions).when(mGlobalActionsDialog).getDefaultActions(); - } -} 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 31d70f5c811f..1bb660e4cced 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java @@ -34,12 +34,14 @@ import android.app.admin.DevicePolicyManager; import android.app.trust.TrustManager; import android.os.PowerManager; import android.os.PowerManager.WakeLock; +import android.os.RemoteException; import android.telephony.TelephonyManager; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import androidx.test.filters.SmallTest; +import com.android.internal.policy.IKeyguardDrawnCallback; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardDisplayManager; import com.android.keyguard.KeyguardUpdateMonitor; @@ -55,6 +57,8 @@ import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.UserSwitcherController; +import com.android.systemui.unfold.UnfoldLightRevealOverlayAnimation; +import com.android.systemui.unfold.config.UnfoldTransitionConfig; import com.android.systemui.util.DeviceConfigProxy; import com.android.systemui.util.DeviceConfigProxyFake; import com.android.systemui.util.concurrency.FakeExecutor; @@ -63,6 +67,7 @@ import com.android.systemui.util.time.FakeSystemClock; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -85,11 +90,14 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { private @Mock NavigationModeController mNavigationModeController; private @Mock KeyguardDisplayManager mKeyguardDisplayManager; private @Mock DozeParameters mDozeParameters; + private @Mock UnfoldTransitionConfig mUnfoldTransitionConfig; + private @Mock UnfoldLightRevealOverlayAnimation mUnfoldAnimation; private @Mock SysuiStatusBarStateController mStatusBarStateController; private @Mock KeyguardStateController mKeyguardStateController; private @Mock NotificationShadeDepthController mNotificationShadeDepthController; private @Mock KeyguardUnlockAnimationController mKeyguardUnlockAnimationController; private @Mock UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController; + private @Mock IKeyguardDrawnCallback mKeyguardDrawnCallback; private DeviceConfigProxy mDeviceConfig = new DeviceConfigProxyFake(); private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock()); @@ -120,6 +128,8 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { mNavigationModeController, mKeyguardDisplayManager, mDozeParameters, + mUnfoldTransitionConfig, + () -> mUnfoldAnimation, mStatusBarStateController, mKeyguardStateController, () -> mKeyguardUnlockAnimationController, @@ -148,6 +158,33 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { } @Test + @TestableLooper.RunWithLooper(setAsMainLooper = true) + public void testUnfoldTransitionEnabledDrawnTasksReady_onScreenTurningOn_callsDrawnCallback() + throws RemoteException { + when(mUnfoldTransitionConfig.isEnabled()).thenReturn(true); + + mViewMediator.onScreenTurningOn(mKeyguardDrawnCallback); + TestableLooper.get(this).processAllMessages(); + onUnfoldOverlayReady(); + + // Should be called when both unfold overlay and keyguard drawn ready + verify(mKeyguardDrawnCallback).onDrawn(); + } + + @Test + @TestableLooper.RunWithLooper(setAsMainLooper = true) + public void testUnfoldTransitionDisabledDrawnTasksReady_onScreenTurningOn_callsDrawnCallback() + throws RemoteException { + when(mUnfoldTransitionConfig.isEnabled()).thenReturn(false); + + mViewMediator.onScreenTurningOn(mKeyguardDrawnCallback); + TestableLooper.get(this).processAllMessages(); + + // Should be called when only keyguard drawn + verify(mKeyguardDrawnCallback).onDrawn(); + } + + @Test public void testIsAnimatingScreenOff() { when(mDozeParameters.shouldControlUnlockedScreenOff()).thenReturn(true); @@ -187,4 +224,11 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { // then make sure it comes back verify(mStatusBarKeyguardViewManager, atLeast(1)).show(null); } + + private void onUnfoldOverlayReady() { + ArgumentCaptor<Runnable> overlayReadyCaptor = ArgumentCaptor.forClass(Runnable.class); + verify(mUnfoldAnimation).onScreenTurningOn(overlayReadyCaptor.capture()); + overlayReadyCaptor.getValue().run(); + TestableLooper.get(this).processAllMessages(); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java index 90e3db7750bc..5e73dbcbc95d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java @@ -16,6 +16,9 @@ package com.android.systemui.keyguard; +import static com.android.keyguard.LockIconView.ICON_LOCK; +import static com.android.keyguard.LockIconView.ICON_UNLOCK; + import static junit.framework.Assert.assertEquals; import static org.mockito.Mockito.any; @@ -29,7 +32,7 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.content.res.Resources; import android.graphics.PointF; -import android.graphics.drawable.AnimatedVectorDrawable; +import android.graphics.drawable.AnimatedStateListDrawable; import android.hardware.biometrics.BiometricSourceType; import android.hardware.biometrics.SensorLocationInternal; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; @@ -59,7 +62,8 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; -import com.android.systemui.util.concurrency.DelayableExecutor; +import com.android.systemui.util.concurrency.FakeExecutor; +import com.android.systemui.util.time.FakeSystemClock; import com.airbnb.lottie.LottieAnimationView; @@ -81,7 +85,7 @@ public class LockIconViewControllerTest extends SysuiTestCase { private static final String UNLOCKED_LABEL = "unlocked"; private @Mock LockIconView mLockIconView; - private @Mock AnimatedVectorDrawable mIconDrawable; + private @Mock AnimatedStateListDrawable mIconDrawable; private @Mock Context mContext; private @Mock Resources mResources; private @Mock DisplayMetrics mDisplayMetrics; @@ -94,11 +98,11 @@ public class LockIconViewControllerTest extends SysuiTestCase { private @Mock DumpManager mDumpManager; private @Mock AccessibilityManager mAccessibilityManager; private @Mock ConfigurationController mConfigurationController; - private @Mock DelayableExecutor mDelayableExecutor; private @Mock Vibrator mVibrator; private @Mock AuthRippleController mAuthRippleController; private @Mock LottieAnimationView mAodFp; private @Mock LayoutInflater mLayoutInflater; + private FakeExecutor mDelayableExecutor = new FakeExecutor(new FakeSystemClock()); private LockIconViewController mLockIconViewController; @@ -107,6 +111,14 @@ public class LockIconViewControllerTest extends SysuiTestCase { ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class); private View.OnAttachStateChangeListener mAttachListener; + @Captor private ArgumentCaptor<KeyguardStateController.Callback> mKeyguardStateCaptor = + ArgumentCaptor.forClass(KeyguardStateController.Callback.class); + private KeyguardStateController.Callback mKeyguardStateCallback; + + @Captor private ArgumentCaptor<StatusBarStateController.StateListener> mStatusBarStateCaptor = + ArgumentCaptor.forClass(StatusBarStateController.StateListener.class); + private StatusBarStateController.StateListener mStatusBarStateListener; + @Captor private ArgumentCaptor<AuthController.Callback> mAuthControllerCallbackCaptor; private AuthController.Callback mAuthControllerCallback; @@ -212,6 +224,7 @@ public class LockIconViewControllerTest extends SysuiTestCase { // WHEN all authenticators are registered mAuthControllerCallback.onAllAuthenticatorsRegistered(); + mDelayableExecutor.runAllReady(); // THEN lock icon view location is updated with the same coordinates as fpProps verify(mLockIconView).setCenterLocation(mPointCaptor.capture(), eq(udfps.first)); @@ -271,6 +284,86 @@ public class LockIconViewControllerTest extends SysuiTestCase { verify(mLockIconView).setContentDescription(UNLOCKED_LABEL); } + @Test + public void testLockIconStartState() { + // GIVEN lock icon state + setupShowLockIcon(); + + // WHEN lock icon controller is initialized + mLockIconViewController.init(); + captureAttachListener(); + mAttachListener.onViewAttachedToWindow(mLockIconView); + + // THEN the lock icon should show + verify(mLockIconView).updateIcon(ICON_LOCK, false); + } + + @Test + public void testLockIcon_updateToUnlock() { + // GIVEN starting state for the lock icon + setupShowLockIcon(); + + // GIVEN lock icon controller is initialized and view is attached + mLockIconViewController.init(); + captureAttachListener(); + mAttachListener.onViewAttachedToWindow(mLockIconView); + captureKeyguardStateCallback(); + reset(mLockIconView); + + // WHEN the unlocked state changes to canDismissLockScreen=true + when(mKeyguardStateController.canDismissLockScreen()).thenReturn(true); + mKeyguardStateCallback.onUnlockedChanged(); + + // THEN the unlock should show + verify(mLockIconView).updateIcon(ICON_UNLOCK, false); + } + + @Test + public void testLockIcon_clearsIconOnAod_whenUdfpsNotEnrolled() { + // GIVEN udfps not enrolled + setupUdfps(); + when(mKeyguardUpdateMonitor.isUdfpsEnrolled()).thenReturn(false); + + // GIVEN starting state for the lock icon + setupShowLockIcon(); + + // GIVEN lock icon controller is initialized and view is attached + mLockIconViewController.init(); + captureAttachListener(); + mAttachListener.onViewAttachedToWindow(mLockIconView); + captureStatusBarStateListener(); + reset(mLockIconView); + + // WHEN the dozing state changes + mStatusBarStateListener.onDozingChanged(true /* isDozing */); + + // THEN the icon is cleared + verify(mLockIconView).clearIcon(); + } + + @Test + public void testLockIcon_updateToAodLock_whenUdfpsEnrolled() { + // GIVEN udfps enrolled + setupUdfps(); + when(mKeyguardUpdateMonitor.isUdfpsEnrolled()).thenReturn(true); + + // GIVEN starting state for the lock icon + setupShowLockIcon(); + + // GIVEN lock icon controller is initialized and view is attached + mLockIconViewController.init(); + captureAttachListener(); + mAttachListener.onViewAttachedToWindow(mLockIconView); + captureStatusBarStateListener(); + reset(mLockIconView); + + // WHEN the dozing state changes + mStatusBarStateListener.onDozingChanged(true /* isDozing */); + + // THEN the AOD lock icon should show + verify(mLockIconView).updateIcon(ICON_LOCK, true); + } + private Pair<Integer, PointF> setupUdfps() { final PointF udfpsLocation = new PointF(50, 75); final int radius = 33; @@ -290,6 +383,15 @@ public class LockIconViewControllerTest extends SysuiTestCase { return new Pair(radius, udfpsLocation); } + private void setupShowLockIcon() { + when(mKeyguardStateController.isShowing()).thenReturn(true); + when(mKeyguardStateController.isKeyguardGoingAway()).thenReturn(false); + when(mStatusBarStateController.isDozing()).thenReturn(false); + when(mStatusBarStateController.getDozeAmount()).thenReturn(0f); + when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD); + when(mKeyguardStateController.canDismissLockScreen()).thenReturn(false); + } + private void captureAuthControllerCallback() { verify(mAuthController).addCallback(mAuthControllerCallbackCaptor.capture()); mAuthControllerCallback = mAuthControllerCallbackCaptor.getValue(); @@ -300,6 +402,16 @@ public class LockIconViewControllerTest extends SysuiTestCase { mAttachListener = mAttachCaptor.getValue(); } + private void captureKeyguardStateCallback() { + verify(mKeyguardStateController).addCallback(mKeyguardStateCaptor.capture()); + mKeyguardStateCallback = mKeyguardStateCaptor.getValue(); + } + + private void captureStatusBarStateListener() { + verify(mStatusBarStateController).addCallback(mStatusBarStateCaptor.capture()); + mStatusBarStateListener = mStatusBarStateCaptor.getValue(); + } + private void captureKeyguardUpdateMonitorCallback() { verify(mKeyguardUpdateMonitor).registerCallback( mKeyguardUpdateMonitorCallbackCaptor.capture()); diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java index 750600ad1387..52173c13ca6e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java @@ -212,12 +212,14 @@ public class MediaOutputAdapterTest extends SysuiTestCase { mMediaOutputAdapter.onBindViewHolder(mViewHolder, 1); assertThat(mViewHolder.mAddIcon.getVisibility()).isEqualTo(View.GONE); - assertThat(mViewHolder.mTwoLineLayout.getVisibility()).isEqualTo(View.GONE); assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE); assertThat(mViewHolder.mBottomDivider.getVisibility()).isEqualTo(View.GONE); - assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.VISIBLE); - assertThat(mViewHolder.mTitleText.getText().toString()).isEqualTo( - mContext.getString(R.string.media_output_dialog_disconnected, TEST_DEVICE_NAME_2)); + assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.GONE); + assertThat(mViewHolder.mTwoLineLayout.getVisibility()).isEqualTo(View.VISIBLE); + assertThat(mViewHolder.mTwoLineTitleText.getText().toString()).isEqualTo( + TEST_DEVICE_NAME_2); + assertThat(mViewHolder.mSubTitleText.getText().toString()).isEqualTo( + mContext.getString(R.string.media_output_dialog_disconnected)); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java index 2a8840b503ad..4fc329ffc7af 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java @@ -35,43 +35,24 @@ import static org.mockito.Mockito.verify; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper.RunWithLooper; import android.util.SparseArray; -import android.view.WindowManager; -import android.view.accessibility.AccessibilityManager; import androidx.test.filters.SmallTest; -import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.UiEventLogger; import com.android.systemui.Dependency; import com.android.systemui.SysuiTestCase; -import com.android.systemui.accessibility.AccessibilityButtonModeObserver; -import com.android.systemui.accessibility.SystemActions; -import com.android.systemui.assist.AssistManager; -import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dump.DumpManager; import com.android.systemui.model.SysUiState; -import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.recents.OverviewProxyService; -import com.android.systemui.recents.Recents; -import com.android.systemui.settings.UserTracker; import com.android.systemui.statusbar.CommandQueue; -import com.android.systemui.statusbar.NotificationRemoteInputManager; -import com.android.systemui.statusbar.NotificationShadeDepthController; import com.android.systemui.statusbar.phone.AutoHideController; -import com.android.systemui.statusbar.phone.ShadeController; -import com.android.systemui.statusbar.phone.StatusBar; -import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper; import com.android.systemui.statusbar.policy.ConfigurationController; -import com.android.systemui.statusbar.policy.DeviceProvisionedController; -import com.android.wm.shell.legacysplitscreen.LegacySplitScreen; -import com.android.wm.shell.pip.Pip; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; - -import java.util.Optional; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; /** atest NavigationBarControllerTest */ @RunWith(AndroidTestingRunner.class) @@ -79,46 +60,31 @@ import java.util.Optional; @SmallTest public class NavigationBarControllerTest extends SysuiTestCase { + private static final int SECONDARY_DISPLAY = 1; + private NavigationBarController mNavigationBarController; private NavigationBar mDefaultNavBar; private NavigationBar mSecondaryNavBar; - private CommandQueue mCommandQueue = mock(CommandQueue.class); - - private static final int SECONDARY_DISPLAY = 1; + @Mock + private CommandQueue mCommandQueue; + @Mock + private NavigationBar.Factory mNavigationBarFactory; @Before public void setUp() { + MockitoAnnotations.initMocks(this); mNavigationBarController = spy( new NavigationBarController(mContext, - mock(WindowManager.class), - () -> mock(AssistManager.class), - mock(AccessibilityManager.class), - mock(AccessibilityManagerWrapper.class), - mock(DeviceProvisionedController.class), - mock(MetricsLogger.class), mock(OverviewProxyService.class), mock(NavigationModeController.class), - mock(AccessibilityButtonModeObserver.class), - mock(StatusBarStateController.class), mock(SysUiState.class), - mock(BroadcastDispatcher.class), mCommandQueue, - Optional.of(mock(Pip.class)), - Optional.of(mock(LegacySplitScreen.class)), - Optional.of(mock(Recents.class)), - () -> Optional.of(mock(StatusBar.class)), - mock(ShadeController.class), - mock(NotificationRemoteInputManager.class), - mock(NotificationShadeDepthController.class), - mock(SystemActions.class), Dependency.get(Dependency.MAIN_HANDLER), - mock(UiEventLogger.class), - mock(NavigationBarOverlayController.class), mock(ConfigurationController.class), mock(NavigationBarA11yHelper.class), mock(TaskbarDelegate.class), - mock(UserTracker.class), + mNavigationBarFactory, mock(DumpManager.class), mock(AutoHideController.class))); initializeNavigationBars(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java index e37f4224060c..223ffbd7bba5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java @@ -19,6 +19,7 @@ package com.android.systemui.navigationbar; import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT; import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN; import static android.inputmethodservice.InputMethodService.BACK_DISPOSITION_DEFAULT; +import static android.inputmethodservice.InputMethodService.IME_INVISIBLE; import static android.inputmethodservice.InputMethodService.IME_VISIBLE; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS; @@ -28,7 +29,6 @@ import static com.android.systemui.navigationbar.NavigationBar.NavBarActionEvent import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; @@ -45,11 +45,11 @@ import android.content.Context; import android.content.IntentFilter; import android.hardware.display.DisplayManagerGlobal; import android.os.Handler; -import android.os.Looper; import android.os.SystemClock; import android.os.UserHandle; import android.provider.DeviceConfig; import android.provider.Settings; +import android.telecom.TelecomManager; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; @@ -60,12 +60,12 @@ import android.view.View; import android.view.WindowManager; import android.view.WindowMetrics; import android.view.accessibility.AccessibilityManager; +import android.view.inputmethod.InputMethodManager; import androidx.test.filters.SmallTest; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.UiEventLogger; -import com.android.systemui.Dependency; import com.android.systemui.SysuiTestCase; import com.android.systemui.SysuiTestableContext; import com.android.systemui.accessibility.AccessibilityButtonModeObserver; @@ -81,9 +81,10 @@ import com.android.systemui.settings.UserTracker; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.NotificationShadeDepthController; +import com.android.systemui.statusbar.phone.AutoHideController; +import com.android.systemui.statusbar.phone.LightBarController; import com.android.systemui.statusbar.phone.ShadeController; import com.android.systemui.statusbar.phone.StatusBar; -import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.utils.leaks.LeakCheckedTest; @@ -110,7 +111,13 @@ public class NavigationBarTest extends SysuiTestCase { private NavigationBar mExternalDisplayNavigationBar; private SysuiTestableContext mSysuiTestableContextExternal; + @Mock private OverviewProxyService mOverviewProxyService; + @Mock + private StatusBarStateController mStatusBarStateController; + @Mock + private NavigationModeController mNavigationModeController; + @Mock private CommandQueue mCommandQueue; private SysUiState mMockSysUiState; @Mock @@ -125,11 +132,25 @@ public class NavigationBarTest extends SysuiTestCase { EdgeBackGestureHandler mEdgeBackGestureHandler; @Mock NavigationBarA11yHelper mNavigationBarA11yHelper; + @Mock + private LightBarController mLightBarController; + @Mock + private LightBarController.Factory mLightBarcontrollerFactory; + @Mock + private AutoHideController mAutoHideController; + @Mock + private AutoHideController.Factory mAutoHideControllerFactory; + @Mock + private WindowManager mWindowManager; + @Mock + private TelecomManager mTelecomManager; + @Mock + private InputMethodManager mInputMethodManager; + @Mock + private AssistManager mAssistManager; @Rule public final LeakCheckedTest.SysuiLeakCheck mLeakCheck = new LeakCheckedTest.SysuiLeakCheck(); - private AccessibilityManagerWrapper mAccessibilityWrapper = - new AccessibilityManagerWrapper(mContext); @Before public void setup() throws Exception { @@ -137,15 +158,19 @@ public class NavigationBarTest extends SysuiTestCase { when(mEdgeBackGestureHandlerFactory.create(any(Context.class))) .thenReturn(mEdgeBackGestureHandler); - mCommandQueue = new CommandQueue(mContext); + when(mLightBarcontrollerFactory.create(any(Context.class))).thenReturn(mLightBarController); + when(mAutoHideControllerFactory.create(any(Context.class))).thenReturn(mAutoHideController); setupSysuiDependency(); - mDependency.injectMockDependency(AssistManager.class); + // This class inflates views that call Dependency.get, thus these injections are still + // necessary. + mDependency.injectTestDependency(AssistManager.class, mAssistManager); mDependency.injectMockDependency(KeyguardStateController.class); - mDependency.injectMockDependency(StatusBarStateController.class); + mDependency.injectTestDependency(StatusBarStateController.class, mStatusBarStateController); mDependency.injectMockDependency(NavigationBarController.class); - mOverviewProxyService = mDependency.injectMockDependency(OverviewProxyService.class); mDependency.injectTestDependency(EdgeBackGestureHandler.Factory.class, mEdgeBackGestureHandlerFactory); + mDependency.injectTestDependency(OverviewProxyService.class, mOverviewProxyService); + mDependency.injectTestDependency(NavigationModeController.class, mNavigationModeController); TestableLooper.get(this).runWithLooper(() -> { mNavigationBar = createNavBar(mContext); mExternalDisplayNavigationBar = createNavBar(mSysuiTestableContextExternal); @@ -164,25 +189,21 @@ public class NavigationBarTest extends SysuiTestCase { mSysuiTestableContextExternal = (SysuiTestableContext) getContext().createDisplayContext( display); - WindowManager windowManager = mock(WindowManager.class); - Display defaultDisplay = mContext.getSystemService(WindowManager.class).getDefaultDisplay(); - when(windowManager.getDefaultDisplay()).thenReturn( - defaultDisplay); - WindowMetrics maximumWindowMetrics = mContext.getSystemService(WindowManager.class) + Display defaultDisplay = mContext.getDisplay(); + when(mWindowManager.getDefaultDisplay()).thenReturn(defaultDisplay); + WindowMetrics metrics = mContext.getSystemService(WindowManager.class) .getMaximumWindowMetrics(); - when(windowManager.getMaximumWindowMetrics()).thenReturn(maximumWindowMetrics); + when(mWindowManager.getMaximumWindowMetrics()).thenReturn(metrics); WindowMetrics currentWindowMetrics = mContext.getSystemService(WindowManager.class) .getCurrentWindowMetrics(); - when(windowManager.getCurrentWindowMetrics()).thenReturn(currentWindowMetrics); - doNothing().when(windowManager).addView(any(), any()); - mContext.addMockSystemService(Context.WINDOW_SERVICE, windowManager); - mSysuiTestableContextExternal.addMockSystemService(Context.WINDOW_SERVICE, windowManager); - - mDependency.injectTestDependency(Dependency.BG_LOOPER, Looper.getMainLooper()); - mDependency.injectTestDependency(AccessibilityManagerWrapper.class, mAccessibilityWrapper); - + when(mWindowManager.getCurrentWindowMetrics()).thenReturn(currentWindowMetrics); + doNothing().when(mWindowManager).addView(any(), any()); + doNothing().when(mWindowManager).removeViewImmediate(any()); mMockSysUiState = mock(SysUiState.class); when(mMockSysUiState.setFlag(anyInt(), anyBoolean())).thenReturn(mMockSysUiState); + + mContext.addMockSystemService(WindowManager.class, mWindowManager); + mSysuiTestableContextExternal.addMockSystemService(WindowManager.class, mWindowManager); } @Test @@ -239,10 +260,8 @@ public class NavigationBarTest extends SysuiTestCase { defaultNavBar.createView(null); externalNavBar.createView(null); - // Set IME window status for default NavBar. - mCommandQueue.setImeWindowStatus(DEFAULT_DISPLAY, null, IME_VISIBLE, - BACK_DISPOSITION_DEFAULT, true, false); - processAllMessages(); + defaultNavBar.setImeWindowStatus(DEFAULT_DISPLAY, null, IME_VISIBLE, + BACK_DISPOSITION_DEFAULT, true); // Verify IME window state will be updated in default NavBar & external NavBar state reset. assertEquals(NAVIGATION_HINT_BACK_ALT | NAVIGATION_HINT_IME_SHOWN, @@ -250,11 +269,10 @@ public class NavigationBarTest extends SysuiTestCase { assertFalse((externalNavBar.getNavigationIconHints() & NAVIGATION_HINT_BACK_ALT) != 0); assertFalse((externalNavBar.getNavigationIconHints() & NAVIGATION_HINT_IME_SHOWN) != 0); - // Set IME window status for external NavBar. - mCommandQueue.setImeWindowStatus(EXTERNAL_DISPLAY_ID, null, - IME_VISIBLE, BACK_DISPOSITION_DEFAULT, true, false); - processAllMessages(); - + externalNavBar.setImeWindowStatus(EXTERNAL_DISPLAY_ID, null, IME_VISIBLE, + BACK_DISPOSITION_DEFAULT, true); + defaultNavBar.setImeWindowStatus( + DEFAULT_DISPLAY, null, IME_INVISIBLE, BACK_DISPOSITION_DEFAULT, false); // Verify IME window state will be updated in external NavBar & default NavBar state reset. assertEquals(NAVIGATION_HINT_BACK_ALT | NAVIGATION_HINT_IME_SHOWN, externalNavBar.getNavigationIconHints()); @@ -280,19 +298,15 @@ public class NavigationBarTest extends SysuiTestCase { DeviceProvisionedController deviceProvisionedController = mock(DeviceProvisionedController.class); when(deviceProvisionedController.isDeviceProvisioned()).thenReturn(true); - assertNotNull(mAccessibilityWrapper); - return spy(new NavigationBar(context, - mock(WindowManager.class), - () -> mock(AssistManager.class), + NavigationBar.Factory factory = new NavigationBar.Factory( + () -> mAssistManager, mock(AccessibilityManager.class), - context.getDisplayId() == DEFAULT_DISPLAY ? mAccessibilityWrapper - : mock(AccessibilityManagerWrapper.class), deviceProvisionedController, new MetricsLogger(), mOverviewProxyService, - mock(NavigationModeController.class), + mNavigationModeController, mock(AccessibilityButtonModeObserver.class), - mock(StatusBarStateController.class), + mStatusBarStateController, mMockSysUiState, mBroadcastDispatcher, mCommandQueue, @@ -308,7 +322,14 @@ public class NavigationBarTest extends SysuiTestCase { mock(NavigationBarOverlayController.class), mUiEventLogger, mNavigationBarA11yHelper, - mock(UserTracker.class))); + mock(UserTracker.class), + mLightBarController, + mLightBarcontrollerFactory, + mAutoHideController, + mAutoHideControllerFactory, + Optional.of(mTelecomManager), + mInputMethodManager); + return spy(factory.create(context)); } private void processAllMessages() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java index 12c0d5379a20..c4bab738cc03 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java @@ -39,7 +39,6 @@ import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.UiEventLogger; import com.android.keyguard.CarrierText; import com.android.systemui.Dependency; -import com.android.systemui.SystemUIFactory; import com.android.systemui.SysuiBaseFragmentTest; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dump.DumpManager; @@ -63,7 +62,6 @@ import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler; import com.android.systemui.statusbar.policy.UserSwitcherController; import com.android.systemui.tuner.TunerService; -import com.android.systemui.util.InjectionInflationController; import com.android.systemui.util.settings.SecureSettings; import org.junit.Before; @@ -177,10 +175,6 @@ public class QSFragmentTest extends SysuiBaseFragmentTest { return new QSFragment( new RemoteInputQuickSettingsDisabler(context, mock(ConfigurationController.class), commandQueue), - new InjectionInflationController( - SystemUIFactory.getInstance() - .getSysUIComponent() - .createViewInstanceCreatorFactory()), mock(QSTileHost.class), mock(StatusBarStateController.class), commandQueue, diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java index c42b64a09985..66889607482f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java @@ -19,6 +19,7 @@ import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.view.View; import android.widget.LinearLayout; +import android.widget.TextView; import androidx.recyclerview.widget.RecyclerView; import androidx.test.filters.SmallTest; @@ -26,6 +27,8 @@ import androidx.test.filters.SmallTest; import com.android.internal.logging.UiEventLogger; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; +import com.android.systemui.util.concurrency.FakeExecutor; +import com.android.systemui.util.time.FakeSystemClock; import com.android.wifitrackerlib.WifiEntry; import org.junit.After; @@ -64,6 +67,7 @@ public class InternetDialogTest extends SysuiTestCase { @Mock private InternetDialogController mInternetDialogController; + private FakeExecutor mBgExecutor = new FakeExecutor(new FakeSystemClock()); private InternetDialog mInternetDialog; private View mDialogView; private View mSubTitle; @@ -73,6 +77,7 @@ public class InternetDialogTest extends SysuiTestCase { private LinearLayout mConnectedWifi; private RecyclerView mWifiList; private LinearLayout mSeeAll; + private LinearLayout mWifiScanNotify; @Before public void setUp() { @@ -91,7 +96,8 @@ public class InternetDialogTest extends SysuiTestCase { when(mInternetDialogController.getWifiManager()).thenReturn(mWifiManager); mInternetDialog = new InternetDialog(mContext, mock(InternetDialogFactory.class), - mInternetDialogController, true, true, true, mock(UiEventLogger.class), mHandler); + mInternetDialogController, true, true, true, mock(UiEventLogger.class), mHandler, + mBgExecutor); mInternetDialog.mAdapter = mInternetAdapter; mInternetDialog.onAccessPointsChanged(mWifiEntries, mInternetWifiEntry); mInternetDialog.show(); @@ -104,6 +110,7 @@ public class InternetDialogTest extends SysuiTestCase { mConnectedWifi = mDialogView.requireViewById(R.id.wifi_connected_layout); mWifiList = mDialogView.requireViewById(R.id.wifi_list_layout); mSeeAll = mDialogView.requireViewById(R.id.see_all_layout); + mWifiScanNotify = mDialogView.requireViewById(R.id.wifi_scan_notify_layout); } @After @@ -126,7 +133,7 @@ public class InternetDialogTest extends SysuiTestCase { public void updateDialog_withApmOn_internetDialogSubTitleGone() { when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true); - mInternetDialog.updateDialog(); + mInternetDialog.updateDialog(true); assertThat(mSubTitle.getVisibility()).isEqualTo(View.GONE); } @@ -135,7 +142,7 @@ public class InternetDialogTest extends SysuiTestCase { public void updateDialog_withApmOff_internetDialogSubTitleVisible() { when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(false); - mInternetDialog.updateDialog(); + mInternetDialog.updateDialog(true); assertThat(mSubTitle.getVisibility()).isEqualTo(View.VISIBLE); } @@ -145,7 +152,7 @@ public class InternetDialogTest extends SysuiTestCase { when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(false); when(mInternetDialogController.hasEthernet()).thenReturn(true); - mInternetDialog.updateDialog(); + mInternetDialog.updateDialog(true); assertThat(mEthernet.getVisibility()).isEqualTo(View.VISIBLE); } @@ -155,7 +162,7 @@ public class InternetDialogTest extends SysuiTestCase { when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(false); when(mInternetDialogController.hasEthernet()).thenReturn(false); - mInternetDialog.updateDialog(); + mInternetDialog.updateDialog(true); assertThat(mEthernet.getVisibility()).isEqualTo(View.GONE); } @@ -165,7 +172,7 @@ public class InternetDialogTest extends SysuiTestCase { when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true); when(mInternetDialogController.hasEthernet()).thenReturn(true); - mInternetDialog.updateDialog(); + mInternetDialog.updateDialog(true); assertThat(mEthernet.getVisibility()).isEqualTo(View.VISIBLE); } @@ -175,7 +182,7 @@ public class InternetDialogTest extends SysuiTestCase { when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true); when(mInternetDialogController.hasEthernet()).thenReturn(false); - mInternetDialog.updateDialog(); + mInternetDialog.updateDialog(true); assertThat(mEthernet.getVisibility()).isEqualTo(View.GONE); } @@ -184,7 +191,7 @@ public class InternetDialogTest extends SysuiTestCase { public void updateDialog_withApmOn_mobileDataLayoutGone() { when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true); - mInternetDialog.updateDialog(); + mInternetDialog.updateDialog(true); assertThat(mMobileDataToggle.getVisibility()).isEqualTo(View.GONE); } @@ -194,7 +201,7 @@ public class InternetDialogTest extends SysuiTestCase { // The preconditions WiFi ON and Internet WiFi are already in setUp() doReturn(false).when(mInternetDialogController).activeNetworkIsCellular(); - mInternetDialog.updateDialog(); + mInternetDialog.updateDialog(false); assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.VISIBLE); } @@ -205,7 +212,7 @@ public class InternetDialogTest extends SysuiTestCase { mInternetDialog.onAccessPointsChanged(mWifiEntries, null /* connectedEntry*/); doReturn(false).when(mInternetDialogController).activeNetworkIsCellular(); - mInternetDialog.updateDialog(); + mInternetDialog.updateDialog(false); assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.GONE); } @@ -215,7 +222,7 @@ public class InternetDialogTest extends SysuiTestCase { // The precondition WiFi ON is already in setUp() mInternetDialog.onAccessPointsChanged(null /* wifiEntries */, mInternetWifiEntry); - mInternetDialog.updateDialog(); + mInternetDialog.updateDialog(false); assertThat(mWifiList.getVisibility()).isEqualTo(View.GONE); assertThat(mSeeAll.getVisibility()).isEqualTo(View.GONE); @@ -225,7 +232,7 @@ public class InternetDialogTest extends SysuiTestCase { public void updateDialog_wifiOnAndHasWifiList_showWifiListAndSeeAll() { // The preconditions WiFi ON and WiFi entries are already in setUp() - mInternetDialog.updateDialog(); + mInternetDialog.updateDialog(false); assertThat(mWifiList.getVisibility()).isEqualTo(View.VISIBLE); assertThat(mSeeAll.getVisibility()).isEqualTo(View.VISIBLE); @@ -236,7 +243,7 @@ public class InternetDialogTest extends SysuiTestCase { // The preconditions WiFi ON and Internet WiFi are already in setUp() when(mInternetDialogController.isDeviceLocked()).thenReturn(true); - mInternetDialog.updateDialog(); + mInternetDialog.updateDialog(false); assertThat(mWifiToggle.getVisibility()).isEqualTo(View.VISIBLE); assertThat(mWifiToggle.getBackground()).isNotNull(); @@ -247,7 +254,7 @@ public class InternetDialogTest extends SysuiTestCase { // The preconditions WiFi ON and Internet WiFi are already in setUp() when(mInternetDialogController.isDeviceLocked()).thenReturn(true); - mInternetDialog.updateDialog(); + mInternetDialog.updateDialog(false); assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.GONE); } @@ -257,13 +264,57 @@ public class InternetDialogTest extends SysuiTestCase { // The preconditions WiFi entries are already in setUp() when(mInternetDialogController.isDeviceLocked()).thenReturn(true); - mInternetDialog.updateDialog(); + mInternetDialog.updateDialog(false); assertThat(mWifiList.getVisibility()).isEqualTo(View.GONE); assertThat(mSeeAll.getVisibility()).isEqualTo(View.GONE); } @Test + public void updateDialog_wifiOn_hideWifiScanNotify() { + // The preconditions WiFi ON and Internet WiFi are already in setUp() + + mInternetDialog.updateDialog(false); + + assertThat(mWifiScanNotify.getVisibility()).isEqualTo(View.GONE); + } + + @Test + public void updateDialog_wifiOffAndWifiScanOff_hideWifiScanNotify() { + when(mWifiManager.isWifiEnabled()).thenReturn(false); + when(mWifiManager.isScanAlwaysAvailable()).thenReturn(false); + + mInternetDialog.updateDialog(false); + + assertThat(mWifiScanNotify.getVisibility()).isEqualTo(View.GONE); + } + + @Test + public void updateDialog_wifiOffAndWifiScanOnAndDeviceLocked_hideWifiScanNotify() { + when(mWifiManager.isWifiEnabled()).thenReturn(false); + when(mWifiManager.isScanAlwaysAvailable()).thenReturn(true); + when(mInternetDialogController.isDeviceLocked()).thenReturn(true); + + mInternetDialog.updateDialog(false); + + assertThat(mWifiScanNotify.getVisibility()).isEqualTo(View.GONE); + } + + @Test + public void updateDialog_wifiOffAndWifiScanOnAndDeviceUnlocked_showWifiScanNotify() { + when(mWifiManager.isWifiEnabled()).thenReturn(false); + when(mWifiManager.isScanAlwaysAvailable()).thenReturn(true); + when(mInternetDialogController.isDeviceLocked()).thenReturn(false); + + mInternetDialog.updateDialog(false); + + assertThat(mWifiScanNotify.getVisibility()).isEqualTo(View.VISIBLE); + TextView wifiScanNotifyText = mDialogView.requireViewById(R.id.wifi_scan_notify_text); + assertThat(wifiScanNotifyText.getText().length()).isNotEqualTo(0); + assertThat(wifiScanNotifyText.getMovementMethod()).isNotNull(); + } + + @Test public void onClickSeeMoreButton_clickSeeAll_verifyLaunchNetworkSetting() { mSeeAll.performClick(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java index 2416132d8b83..af624ed1ea1a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java @@ -15,6 +15,8 @@ package com.android.systemui.statusbar; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE; +import static android.inputmethodservice.InputMethodService.BACK_DISPOSITION_DEFAULT; +import static android.inputmethodservice.InputMethodService.IME_INVISIBLE; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.InsetsState.ITYPE_NAVIGATION_BAR; import static android.view.InsetsState.ITYPE_STATUS_BAR; @@ -188,8 +190,13 @@ public class CommandQueueTest extends SysuiTestCase { @Test public void testShowImeButtonForSecondaryDisplay() { + // First show in default display to update the "last updated ime display" + testShowImeButton(); + mCommandQueue.setImeWindowStatus(SECONDARY_DISPLAY, null, 1, 2, true, false); waitForIdleSync(); + verify(mCallbacks).setImeWindowStatus(eq(DEFAULT_DISPLAY), eq(null), eq(IME_INVISIBLE), + eq(BACK_DISPOSITION_DEFAULT), eq(false)); verify(mCallbacks).setImeWindowStatus( eq(SECONDARY_DISPLAY), eq(null), eq(1), eq(2), eq(true)); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt index e5ae65f2dd17..dbd5168386de 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt @@ -24,7 +24,7 @@ import android.view.View import android.view.ViewRootImpl import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase -import com.android.systemui.animation.Interpolators +import com.android.systemui.animation.ShadeInterpolation import com.android.systemui.dump.DumpManager import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.statusbar.phone.BiometricUnlockController @@ -208,7 +208,7 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() { notificationShadeDepthController.onPanelExpansionChanged(1f, tracking = false) notificationShadeDepthController.updateBlurCallback.doFrame(0) verify(wallpaperController).setNotificationShadeZoom( - eq(Interpolators.getNotificationScrimAlpha(0.25f, false /* notifications */))) + eq(ShadeInterpolation.getNotificationScrimAlpha(0.25f))) } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/RankingBuilder.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/RankingBuilder.java index ac699f7192c8..045e6f19c667 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/RankingBuilder.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/RankingBuilder.java @@ -52,7 +52,7 @@ public class RankingBuilder { private ArrayList<Notification.Action> mSmartActions = new ArrayList<>(); private ArrayList<CharSequence> mSmartReplies = new ArrayList<>(); private boolean mCanBubble = false; - private boolean mIsVisuallyInterruptive = false; + private boolean mIsTextChanged = false; private boolean mIsConversation = false; private ShortcutInfo mShortcutInfo = null; private int mRankingAdjustment = 0; @@ -81,7 +81,7 @@ public class RankingBuilder { mSmartActions = copyList(ranking.getSmartActions()); mSmartReplies = copyList(ranking.getSmartReplies()); mCanBubble = ranking.canBubble(); - mIsVisuallyInterruptive = ranking.visuallyInterruptive(); + mIsTextChanged = ranking.isTextChanged(); mIsConversation = ranking.isConversation(); mShortcutInfo = ranking.getConversationShortcutInfo(); mRankingAdjustment = ranking.getRankingAdjustment(); @@ -110,7 +110,7 @@ public class RankingBuilder { mSmartActions, mSmartReplies, mCanBubble, - mIsVisuallyInterruptive, + mIsTextChanged, mIsConversation, mShortcutInfo, mRankingAdjustment, @@ -189,8 +189,8 @@ public class RankingBuilder { return this; } - public RankingBuilder setVisuallyInterruptive(boolean interruptive) { - mIsVisuallyInterruptive = interruptive; + public RankingBuilder setTextChanged(boolean textChanged) { + mIsTextChanged = textChanged; return this; } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerBaseTest.java index 67cab7413f1f..b23d07a314b4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerBaseTest.java @@ -216,7 +216,7 @@ public class NetworkControllerBaseTest extends SysuiTestCase { mCallbackHandler = mock(CallbackHandler.class); mMockProvisionController = mock(DeviceProvisionedController.class); - when(mMockProvisionController.isUserSetup(anyInt())).thenReturn(true); + when(mMockProvisionController.isCurrentUserSetup()).thenReturn(true); doAnswer(invocation -> { mUserCallback = (DeviceProvisionedListener) invocation.getArguments()[0]; mUserCallback.onUserSetupChanged(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerDataTest.java index 00dedd961074..12f8282c7aa0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerDataTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerDataTest.java @@ -21,7 +21,6 @@ import static android.telephony.NetworkRegistrationInfo.DOMAIN_PS; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.anyInt; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -211,7 +210,7 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { updateDataConnectionState(TelephonyManager.DATA_DISCONNECTED, 0); setConnectivityViaCallbackInNetworkController( NetworkCapabilities.TRANSPORT_CELLULAR, false, false, null); - when(mMockProvisionController.isUserSetup(anyInt())).thenReturn(false); + when(mMockProvisionController.isCurrentUserSetup()).thenReturn(false); mUserCallback.onUserSetupChanged(); TestableLooper.get(this).processAllMessages(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java index 0772c03d10d0..73560be1d265 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java @@ -32,6 +32,7 @@ import androidx.test.filters.SmallTest; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; +import com.android.systemui.flags.FeatureFlags; import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; @@ -61,6 +62,8 @@ public class NotificationRoundnessManagerTest extends SysuiTestCase { private ExpandableNotificationRow mSecond; @Mock private KeyguardBypassController mBypassController; + @Mock + private FeatureFlags mFeatureFlags; private float mSmallRadiusRatio; @Before @@ -71,7 +74,8 @@ public class NotificationRoundnessManagerTest extends SysuiTestCase { / resources.getDimension(R.dimen.notification_corner_radius); mRoundnessManager = new NotificationRoundnessManager( mBypassController, - new NotificationSectionsFeatureManager(new DeviceConfigProxy(), mContext)); + new NotificationSectionsFeatureManager(new DeviceConfigProxy(), mContext), + mFeatureFlags); allowTestableLooperAsMainThread(); NotificationTestHelper testHelper = new NotificationTestHelper( mContext, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java index 9f42fa4d2ae7..185d9cd8733e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java @@ -58,6 +58,8 @@ import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; +import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager; +import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.FooterView; import com.android.systemui.statusbar.phone.KeyguardBypassController; @@ -110,9 +112,20 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { Settings.Secure.putIntForUser(mContext.getContentResolver(), NOTIFICATION_HISTORY_ENABLED, 1, UserHandle.USER_CURRENT); + + // Interact with real instance of AmbientState. + mAmbientState = new AmbientState(mContext, mNotificationSectionsManager, mBypassController); + // Inject dependencies before initializing the layout mDependency.injectTestDependency(SysuiStatusBarStateController.class, mBarState); mDependency.injectMockDependency(ShadeController.class); + mDependency.injectTestDependency( + NotificationSectionsManager.class, mNotificationSectionsManager); + mDependency.injectTestDependency(GroupMembershipManager.class, mGroupMembershipManger); + mDependency.injectTestDependency(GroupExpansionManager.class, mGroupExpansionManager); + mDependency.injectTestDependency(AmbientState.class, mAmbientState); + mDependency.injectTestDependency( + UnlockedScreenOffAnimationController.class, mUnlockedScreenOffAnimationController); NotificationShelfController notificationShelfController = mock(NotificationShelfController.class); @@ -123,22 +136,12 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { mNotificationSection }); - // Interact with real instance of AmbientState. - mAmbientState = new AmbientState(mContext, mNotificationSectionsManager, mBypassController); - // The actual class under test. You may need to work with this class directly when // testing anonymous class members of mStackScroller, like mMenuEventListener, // which refer to members of NotificationStackScrollLayout. The spy // holds a copy of the CUT's instances of these KeyguardBypassController, so they still // refer to the CUT's member variables, not the spy's member variables. - mStackScrollerInternal = new NotificationStackScrollLayout( - getContext(), - null, - mNotificationSectionsManager, - mGroupMembershipManger, - mGroupExpansionManager, - mAmbientState, - mUnlockedScreenOffAnimationController); + mStackScrollerInternal = new NotificationStackScrollLayout(getContext(), null); mStackScrollerInternal.initView(getContext(), mNotificationSwipeHelper); mStackScroller = spy(mStackScrollerInternal); mStackScroller.setShelfController(notificationShelfController); 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 new file mode 100644 index 000000000000..5b60c9e07342 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt @@ -0,0 +1,58 @@ +package com.android.systemui.statusbar.notification.stack + +import android.widget.FrameLayout +import androidx.test.filters.SmallTest +import com.android.systemui.R +import com.android.systemui.SysuiTestCase +import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow +import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.BypassController +import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.SectionProvider +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.mockito.Mockito.mock +import org.mockito.Mockito.`when` as whenever + +@SmallTest +class StackScrollAlgorithmTest : SysuiTestCase() { + + private val hostView = FrameLayout(context) + private val stackScrollAlgorithm = StackScrollAlgorithm(context, hostView) + private val expandableViewState = ExpandableViewState() + private val notificationRow = mock(ExpandableNotificationRow::class.java) + private val ambientState = AmbientState( + context, + SectionProvider { _, _ -> false }, + BypassController { false }) + + @Before + fun setUp() { + whenever(notificationRow.viewState).thenReturn(expandableViewState) + hostView.addView(notificationRow) + } + + @Test + fun testUpTranslationSetToDefaultValue() { + whenever(notificationRow.isPinned).thenReturn(true) + whenever(notificationRow.isHeadsUp).thenReturn(true) + + stackScrollAlgorithm.resetViewStates(ambientState, 0) + + assertThat(expandableViewState.yTranslation).isEqualTo(stackScrollAlgorithm.mHeadsUpInset) + } + + @Test + fun testHeadsUpTranslationChangesBasedOnStackMargin() { + whenever(notificationRow.isPinned).thenReturn(true) + whenever(notificationRow.isHeadsUp).thenReturn(true) + val minHeadsUpTranslation = context.resources + .getDimensionPixelSize(R.dimen.notification_side_paddings) + + // split shade case with top margin introduced by shade's status bar + ambientState.stackTopMargin = 100 + stackScrollAlgorithm.resetViewStates(ambientState, 0) + + // top margin presence should decrease heads up translation up to minHeadsUpTranslation + assertThat(expandableViewState.yTranslation).isEqualTo(minHeadsUpTranslation) + } +}
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java index 8b5ba3848500..38d7ce76f1b9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java @@ -164,7 +164,7 @@ public class DozeServiceHostTest extends SysuiTestCase { @Test public void testPulseWhileDozing_notifyAuthInterrupt() { HashSet<Integer> reasonsWantingAuth = new HashSet<>( - Collections.singletonList(DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN)); + Collections.singletonList(DozeLog.PULSE_REASON_SENSOR_WAKE_REACH)); HashSet<Integer> reasonsSkippingAuth = new HashSet<>( Arrays.asList(DozeLog.PULSE_REASON_INTENT, DozeLog.PULSE_REASON_NOTIFICATION, @@ -173,7 +173,7 @@ public class DozeServiceHostTest extends SysuiTestCase { DozeLog.REASON_SENSOR_DOUBLE_TAP, DozeLog.PULSE_REASON_SENSOR_LONG_PRESS, DozeLog.PULSE_REASON_DOCKING, - DozeLog.REASON_SENSOR_WAKE_UP, + DozeLog.REASON_SENSOR_WAKE_UP_PRESENCE, DozeLog.REASON_SENSOR_QUICK_PICKUP, DozeLog.REASON_SENSOR_TAP)); HashSet<Integer> reasonsThatDontPulse = new HashSet<>( diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java index bca1227b7d35..bafbccdb87d2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java @@ -198,7 +198,6 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase { mHeadsUpAppearanceController.destroy(); verify(mHeadsUpManager).removeListener(any()); verify(mDarkIconDispatcher).removeDarkReceiver((DarkIconDispatcher.DarkReceiver) any()); - verify(mPanelView).setVerticalTranslationListener(isNull()); verify(mPanelView).removeTrackingHeadsUpListener(any()); verify(mPanelView).setHeadsUpAppearanceController(isNull()); verify(mStackScrollerController).removeOnExpandedHeightChangedListener(any()); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java index b18ea4bca681..ead32910f943 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java @@ -338,8 +338,6 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { when(mView.findViewById(R.id.keyguard_clock_container)).thenReturn(mKeyguardClockSwitch); when(mView.findViewById(R.id.notification_stack_scroller)) .thenReturn(mNotificationStackScrollLayout); - when(mNotificationStackScrollLayout.getController()) - .thenReturn(mNotificationStackScrollLayoutController); when(mNotificationStackScrollLayoutController.getHeight()).thenReturn(1000); when(mNotificationStackScrollLayoutController.getHeadsUpCallback()) .thenReturn(mHeadsUpCallback); @@ -450,6 +448,7 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { mControlsComponent); mNotificationPanelViewController.initDependencies( mStatusBar, + () -> {}, mNotificationShelfController); mNotificationPanelViewController.setHeadsUpManager(mHeadsUpManager); mNotificationPanelViewController.setBar(mPanelBar); @@ -518,6 +517,51 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { } @Test + public void onTouchForwardedFromStatusBar_panelsNotEnabled_returnsFalseAndNoViewEvent() { + when(mCommandQueue.panelsEnabled()).thenReturn(false); + + boolean returnVal = mTouchHandler.onTouchForwardedFromStatusBar( + MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0)); + + assertThat(returnVal).isFalse(); + verify(mView, never()).dispatchTouchEvent(any()); + } + + @Test + public void onTouchForwardedFromStatusBar_viewNotEnabled_returnsTrueAndNoViewEvent() { + when(mCommandQueue.panelsEnabled()).thenReturn(true); + when(mView.isEnabled()).thenReturn(false); + + boolean returnVal = mTouchHandler.onTouchForwardedFromStatusBar( + MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0)); + + assertThat(returnVal).isTrue(); + verify(mView, never()).dispatchTouchEvent(any()); + } + + @Test + public void onTouchForwardedFromStatusBar_viewNotEnabledButIsMoveEvent_viewReceivesEvent() { + when(mCommandQueue.panelsEnabled()).thenReturn(true); + when(mView.isEnabled()).thenReturn(false); + MotionEvent event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_MOVE, 0f, 0f, 0); + + mTouchHandler.onTouchForwardedFromStatusBar(event); + + verify(mView).dispatchTouchEvent(event); + } + + @Test + public void onTouchForwardedFromStatusBar_panelAndViewEnabled_viewReceivesEvent() { + when(mCommandQueue.panelsEnabled()).thenReturn(true); + when(mView.isEnabled()).thenReturn(true); + MotionEvent event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0); + + mTouchHandler.onTouchForwardedFromStatusBar(event); + + verify(mView).dispatchTouchEvent(event); + } + + @Test public void testA11y_initializeNode() { AccessibilityNodeInfo nodeInfo = new AccessibilityNodeInfo(); mAccessibiltyDelegate.onInitializeAccessibilityNodeInfo(mView, nodeInfo); @@ -658,18 +702,6 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { } @Test - public void testOnDragDownEvent_horizontalTranslationIsZeroForSplitShade() { - when(mNotificationStackScrollLayoutController.getWidth()).thenReturn(350f); - when(mView.getWidth()).thenReturn(800); - enableSplitShade(/* enabled= */ true); - - onTouchEvent(MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, - 200f /* x position */, 0f, 0)); - - verify(mQsFrame).setTranslationX(0); - } - - @Test public void testCanCollapsePanelOnTouch_trueForKeyGuard() { mStatusBarStateController.setState(KEYGUARD); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java index c62d73c98354..6e9bb2d30ed3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java @@ -34,7 +34,6 @@ import androidx.test.filters.SmallTest; import com.android.keyguard.LockIconViewController; import com.android.systemui.R; -import com.android.systemui.SystemUIFactory; import com.android.systemui.SysuiTestCase; import com.android.systemui.classifier.FalsingCollectorFake; import com.android.systemui.dock.DockManager; @@ -55,7 +54,6 @@ import com.android.systemui.statusbar.notification.stack.NotificationStackScroll import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.tuner.TunerService; -import com.android.systemui.util.InjectionInflationController; import org.junit.Before; import org.junit.Test; @@ -117,10 +115,6 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase { when(mDockManager.isDocked()).thenReturn(false); mController = new NotificationShadeWindowViewController( - new InjectionInflationController( - SystemUIFactory.getInstance() - .getSysUIComponent() - .createViewInstanceCreatorFactory()), mCoordinator, mPulseExpansionHandler, mDynamicPrivacyController, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt index 52a5e064f984..310a8baadb78 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt @@ -17,18 +17,25 @@ package com.android.systemui.statusbar.phone import android.view.LayoutInflater +import android.view.MotionEvent import android.view.ViewGroup +import android.view.ViewTreeObserver +import android.view.ViewTreeObserver.OnPreDrawListener import android.widget.FrameLayout import androidx.test.filters.SmallTest import androidx.test.platform.app.InstrumentationRegistry import com.android.systemui.R import com.android.systemui.SysuiTestCase -import com.android.systemui.statusbar.CommandQueue +import com.android.systemui.unfold.config.UnfoldTransitionConfig +import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider import com.android.systemui.util.mockito.any import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Test +import org.mockito.ArgumentCaptor import org.mockito.Mock +import org.mockito.Mockito.spy +import org.mockito.Mockito.mock import org.mockito.Mockito.`when` import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations @@ -36,11 +43,9 @@ import org.mockito.MockitoAnnotations @SmallTest class PhoneStatusBarViewControllerTest : SysuiTestCase() { - private val stateChangeListener = TestStateChangedListener() + private val touchEventHandler = TestTouchEventHandler() @Mock - private lateinit var commandQueue: CommandQueue - @Mock private lateinit var panelViewController: PanelViewController @Mock private lateinit var panelView: ViewGroup @@ -49,10 +54,14 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() { @Mock private lateinit var moveFromCenterAnimation: StatusBarMoveFromCenterAnimationController + @Mock + private lateinit var progressProvider: ScopedUnfoldTransitionProgressProvider private lateinit var view: PhoneStatusBarView private lateinit var controller: PhoneStatusBarViewController + private val unfoldConfig = UnfoldConfig() + @Before fun setUp() { MockitoAnnotations.initMocks(this) @@ -63,58 +72,62 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() { val parent = FrameLayout(mContext) // add parent to keep layout params view = LayoutInflater.from(mContext) .inflate(R.layout.status_bar, parent, false) as PhoneStatusBarView - view.setPanel(panelViewController) view.setScrimController(scrimController) + view.setBar(mock(StatusBar::class.java)) } - controller = PhoneStatusBarViewController( - view, - commandQueue, - null, - stateChangeListener - ) + controller = createController(view) } @Test - fun constructor_setsPanelEnabledProviderOnView() { - var providerUsed = false - `when`(commandQueue.panelsEnabled()).then { - providerUsed = true - true - } + fun constructor_setsTouchHandlerOnView() { + val event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0) - // If the constructor correctly set a [PanelEnabledProvider], then it should be used - // when [PhoneStatusBarView.panelEnabled] is called. - view.panelEnabled() + view.onTouchEvent(event) - assertThat(providerUsed).isTrue() + assertThat(touchEventHandler.lastEvent).isEqualTo(event) } @Test - fun constructor_moveFromCenterAnimationIsNotNull_moveFromCenterAnimationInitialized() { - controller = PhoneStatusBarViewController( - view, commandQueue, moveFromCenterAnimation, stateChangeListener - ) + fun onViewAttachedAndDrawn_moveFromCenterAnimationEnabled_moveFromCenterAnimationInitialized() { + val view = createViewMock() + val argumentCaptor = ArgumentCaptor.forClass(OnPreDrawListener::class.java) + unfoldConfig.isEnabled = true + controller = createController(view) + controller.init() - verify(moveFromCenterAnimation).init(any(), any()) - } + verify(view.viewTreeObserver).addOnPreDrawListener(argumentCaptor.capture()) + argumentCaptor.value.onPreDraw() - @Test - fun constructor_setsExpansionStateChangedListenerOnView() { - assertThat(stateChangeListener.stateChangeCalled).isFalse() + verify(moveFromCenterAnimation).onViewsReady(any(), any()) + } - // If the constructor correctly set the listener, then it should be used when - // [PhoneStatusBarView.panelExpansionChanged] is called. - view.panelExpansionChanged(0f, false) + private fun createViewMock(): PhoneStatusBarView { + val view = spy(view) + val viewTreeObserver = mock(ViewTreeObserver::class.java) + `when`(view.viewTreeObserver).thenReturn(viewTreeObserver) + `when`(view.isAttachedToWindow).thenReturn(true) + return view + } - assertThat(stateChangeListener.stateChangeCalled).isTrue() + private fun createController(view: PhoneStatusBarView): PhoneStatusBarViewController { + return PhoneStatusBarViewController.Factory( + { progressProvider }, + { moveFromCenterAnimation }, + unfoldConfig + ).create(view, touchEventHandler) } - private class TestStateChangedListener : PhoneStatusBarView.PanelExpansionStateChangedListener { - var stateChangeCalled: Boolean = false + private class UnfoldConfig : UnfoldTransitionConfig { + override var isEnabled: Boolean = false + override var isHingeAngleEnabled: Boolean = false + } - override fun onPanelExpansionStateChanged() { - stateChangeCalled = true + private class TestTouchEventHandler : PhoneStatusBarView.TouchEventHandler { + var lastEvent: MotionEvent? = null + override fun handleTouchEvent(event: MotionEvent?): Boolean { + lastEvent = event + return false } } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewTest.kt index ec7e07f905c6..fe3490399e81 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewTest.kt @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.phone +import android.view.MotionEvent import android.view.ViewGroup import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase @@ -48,63 +49,25 @@ class PhoneStatusBarViewTest : SysuiTestCase() { `when`(panelViewController.view).thenReturn(panelView) view = PhoneStatusBarView(mContext, null) - view.setPanel(panelViewController) view.setScrimController(scrimController) view.setBar(statusBar) } @Test - fun panelEnabled_providerReturnsTrue_returnsTrue() { - view.setPanelEnabledProvider { true } + fun panelExpansionChanged_expansionChangeListenerNotified() { + val listener = TestExpansionChangedListener() + view.setExpansionChangedListeners(listOf(listener)) + val fraction = 0.4f + val isExpanded = true - assertThat(view.panelEnabled()).isTrue() - } - - @Test - fun panelEnabled_providerReturnsFalse_returnsFalse() { - view.setPanelEnabledProvider { false } - - assertThat(view.panelEnabled()).isFalse() - } - - @Test - fun panelEnabled_noProvider_noCrash() { - view.panelEnabled() - // No assert needed, just testing no crash - } - - @Test - fun panelExpansionChanged_fracZero_stateChangeListenerNotified() { - val listener = TestExpansionStateChangedListener() - view.setPanelExpansionStateChangedListener(listener) + view.panelExpansionChanged(fraction, isExpanded) - view.panelExpansionChanged(0f, false) - - assertThat(listener.stateChangeCalled).isTrue() + assertThat(listener.fraction).isEqualTo(fraction) + assertThat(listener.isExpanded).isEqualTo(isExpanded) } @Test - fun panelExpansionChanged_fracOne_stateChangeListenerNotified() { - val listener = TestExpansionStateChangedListener() - view.setPanelExpansionStateChangedListener(listener) - - view.panelExpansionChanged(1f, false) - - assertThat(listener.stateChangeCalled).isTrue() - } - - @Test - fun panelExpansionChanged_fracHalf_stateChangeListenerNotNotified() { - val listener = TestExpansionStateChangedListener() - view.setPanelExpansionStateChangedListener(listener) - - view.panelExpansionChanged(0.5f, false) - - assertThat(listener.stateChangeCalled).isFalse() - } - - @Test - fun panelExpansionChanged_noStateChangeListener_noCrash() { + fun panelExpansionChanged_noListeners_noCrash() { view.panelExpansionChanged(1f, false) // No assert needed, just testing no crash } @@ -144,17 +107,52 @@ class PhoneStatusBarViewTest : SysuiTestCase() { } @Test - fun panelStateChanged_noListener_noCrash() { - view.panelExpansionChanged(1f, true) + fun onTouchEvent_listenerNotified() { + val handler = TestTouchEventHandler() + view.setTouchEventHandler(handler) + + val event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0) + view.onTouchEvent(event) + + assertThat(handler.lastEvent).isEqualTo(event) + } + + @Test + fun onTouchEvent_listenerReturnsTrue_viewReturnsTrue() { + val handler = TestTouchEventHandler() + view.setTouchEventHandler(handler) + val event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0) + + handler.returnValue = true + + assertThat(view.onTouchEvent(event)).isTrue() + } + + @Test + fun onTouchEvent_listenerReturnsFalse_viewReturnsFalse() { + val handler = TestTouchEventHandler() + view.setTouchEventHandler(handler) + val event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0) + + handler.returnValue = false + + assertThat(view.onTouchEvent(event)).isFalse() + } + + @Test + fun onTouchEvent_noListener_noCrash() { + view.onTouchEvent(MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0)) // No assert needed, just testing no crash } - private class TestExpansionStateChangedListener - : PhoneStatusBarView.PanelExpansionStateChangedListener { - var stateChangeCalled: Boolean = false + private class TestExpansionChangedListener + : StatusBar.ExpansionChangedListener { + var fraction: Float = 0f + var isExpanded: Boolean = false - override fun onPanelExpansionStateChanged() { - stateChangeCalled = true + override fun onExpansionChanged(expansion: Float, expanded: Boolean) { + this.fraction = expansion + this.isExpanded = expanded } } @@ -164,4 +162,13 @@ class PhoneStatusBarViewTest : SysuiTestCase() { this.state = state } } + + private class TestTouchEventHandler : PhoneStatusBarView.TouchEventHandler { + var lastEvent: MotionEvent? = null + var returnValue: Boolean = false + override fun handleTouchEvent(event: MotionEvent?): Boolean { + lastEvent = event + return returnValue + } + } } 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 705112afa93f..6849dab1a19a 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 @@ -1063,7 +1063,7 @@ public class ScrimControllerTest extends SysuiTestCase { HashSet<ScrimState> regularStates = new HashSet<>(Arrays.asList( ScrimState.UNINITIALIZED, ScrimState.KEYGUARD, ScrimState.BOUNCER, ScrimState.BOUNCER_SCRIMMED, ScrimState.BRIGHTNESS_MIRROR, ScrimState.UNLOCKED, - ScrimState.SHADE_LOCKED, ScrimState.AUTH_SCRIMMED)); + ScrimState.SHADE_LOCKED, ScrimState.AUTH_SCRIMMED, ScrimState.AUTH_SCRIMMED_SHADE)); for (ScrimState state : ScrimState.values()) { if (!lowPowerModeStates.contains(state) && !regularStates.contains(state)) { @@ -1087,6 +1087,44 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + public void testAuthScrim_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.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); + } + + @Test + public void testAuthScrimKeyguard() { + // GIVEN device is on the keyguard + mScrimController.transitionTo(ScrimState.KEYGUARD); + finishAnimationsImmediately(); + + // WHEN the user triggers the auth bouncer + mScrimController.transitionTo(ScrimState.AUTH_SCRIMMED); + finishAnimationsImmediately(); + + // THEN the front scrim is updated and the KEYGUARD scrims are the same as the + // KEYGUARD scrim state + assertScrimAlpha(Map.of( + mScrimInFront, SEMI_TRANSPARENT, + mScrimBehind, SEMI_TRANSPARENT, + mNotificationsScrim, TRANSPARENT)); + } + + @Test public void testScrimsVisible_whenShadeVisible() { mScrimController.transitionTo(ScrimState.UNLOCKED); mScrimController.setRawPanelExpansionFraction(0.3f); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java index 741d95f283e3..943d3c79984d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java @@ -144,6 +144,7 @@ import com.android.systemui.tuner.TunerService; import com.android.systemui.unfold.UnfoldLightRevealOverlayAnimation; import com.android.systemui.unfold.UnfoldTransitionWallpaperController; import com.android.systemui.unfold.config.UnfoldTransitionConfig; +import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider; import com.android.systemui.util.WallpaperController; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.concurrency.MessageRouterImpl; @@ -259,7 +260,7 @@ public class StatusBarTest extends SysuiTestCase { @Mock private BrightnessSlider.Factory mBrightnessSliderFactory; @Mock private UnfoldTransitionConfig mUnfoldTransitionConfig; @Mock private Lazy<UnfoldLightRevealOverlayAnimation> mUnfoldLightRevealOverlayAnimationLazy; - @Mock private Lazy<StatusBarMoveFromCenterAnimationController> mMoveFromCenterAnimationLazy; + @Mock private Lazy<NaturalRotationUnfoldProgressProvider> mNaturalRotationProgressProvider; @Mock private Lazy<UnfoldTransitionWallpaperController> mUnfoldWallpaperController; @Mock private WallpaperController mWallpaperController; @Mock private OngoingCallController mOngoingCallController; @@ -276,6 +277,7 @@ public class StatusBarTest extends SysuiTestCase { @Mock private StartingSurface mStartingSurface; @Mock private OperatorNameViewController mOperatorNameViewController; @Mock private OperatorNameViewController.Factory mOperatorNameViewControllerFactory; + @Mock private PhoneStatusBarViewController.Factory mPhoneStatusBarViewControllerFactory; @Mock private ActivityLaunchAnimator mActivityLaunchAnimator; @Mock private DialogLaunchAnimator mDialogLaunchAnimator; private ShadeController mShadeController; @@ -314,7 +316,6 @@ public class StatusBarTest extends SysuiTestCase { mContext.setTheme(R.style.Theme_SystemUI_LightWallpaper); - when(mStackScroller.getController()).thenReturn(mStackScrollerController); when(mStackScrollerController.getView()).thenReturn(mStackScroller); when(mStackScrollerController.getNotificationListContainer()).thenReturn( mNotificationListContainer); @@ -430,6 +431,7 @@ public class StatusBarTest extends SysuiTestCase { mExtensionController, mUserInfoControllerImpl, mOperatorNameViewControllerFactory, + mPhoneStatusBarViewControllerFactory, mPhoneStatusBarPolicy, mKeyguardIndicationController, mDemoModeController, @@ -440,7 +442,7 @@ public class StatusBarTest extends SysuiTestCase { mUnfoldTransitionConfig, mUnfoldLightRevealOverlayAnimationLazy, mUnfoldWallpaperController, - mMoveFromCenterAnimationLazy, + mNaturalRotationProgressProvider, mWallpaperController, mOngoingCallController, mAnimationScheduler, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImplTest.kt new file mode 100644 index 000000000000..5129f8584165 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImplTest.kt @@ -0,0 +1,241 @@ +/* + * 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.statusbar.policy + +import android.os.Handler +import android.provider.Settings +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.dump.DumpManager +import com.android.systemui.settings.UserTracker +import com.android.systemui.util.concurrency.FakeExecutor +import com.android.systemui.util.mockito.any +import com.android.systemui.util.mockito.capture +import com.android.systemui.util.settings.FakeSettings +import com.android.systemui.util.time.FakeSystemClock +import com.google.common.truth.Truth.assertThat +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.Mockito.`when` +import org.mockito.Mockito.never +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations + +@SmallTest +@RunWith(AndroidTestingRunner::class) +@TestableLooper.RunWithLooper +class DeviceProvisionedControllerImplTest : SysuiTestCase() { + + companion object { + private const val START_USER = 0 + } + + private lateinit var controller: DeviceProvisionedControllerImpl + + @Mock + private lateinit var userTracker: UserTracker + @Mock + private lateinit var dumpManager: DumpManager + @Mock + private lateinit var listener: DeviceProvisionedController.DeviceProvisionedListener + @Captor + private lateinit var userTrackerCallbackCaptor: ArgumentCaptor<UserTracker.Callback> + + private lateinit var mainExecutor: FakeExecutor + private lateinit var testableLooper: TestableLooper + private lateinit var settings: FakeSettings + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + testableLooper = TestableLooper.get(this) + mainExecutor = FakeExecutor(FakeSystemClock()) + settings = FakeSettings() + `when`(userTracker.userId).thenReturn(START_USER) + + controller = DeviceProvisionedControllerImpl( + settings, + settings, + userTracker, + dumpManager, + Handler(testableLooper.looper), + mainExecutor + ) + } + + @Test + fun testNotProvisionedByDefault() { + init() + assertThat(controller.isDeviceProvisioned).isFalse() + } + + @Test + fun testNotUserSetupByDefault() { + init() + assertThat(controller.isUserSetup(START_USER)).isFalse() + } + + @Test + fun testProvisionedWhenCreated() { + settings.putInt(Settings.Global.DEVICE_PROVISIONED, 1) + init() + + assertThat(controller.isDeviceProvisioned).isTrue() + } + + @Test + fun testUserSetupWhenCreated() { + settings.putIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 1, START_USER) + init() + + assertThat(controller.isUserSetup(START_USER)) + } + + @Test + fun testDeviceProvisionedChange() { + init() + + settings.putInt(Settings.Global.DEVICE_PROVISIONED, 1) + testableLooper.processAllMessages() // background observer + + assertThat(controller.isDeviceProvisioned).isTrue() + } + + @Test + fun testUserSetupChange() { + init() + + settings.putIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 1, START_USER) + testableLooper.processAllMessages() // background observer + + assertThat(controller.isUserSetup(START_USER)).isTrue() + } + + @Test + fun testUserSetupChange_otherUser() { + init() + val otherUser = 10 + + settings.putIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 1, otherUser) + testableLooper.processAllMessages() // background observer + + assertThat(controller.isUserSetup(START_USER)).isFalse() + assertThat(controller.isUserSetup(otherUser)).isTrue() + } + + @Test + fun testCurrentUserSetup() { + val otherUser = 10 + settings.putIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 1, otherUser) + init() + + assertThat(controller.isCurrentUserSetup).isFalse() + switchUser(otherUser) + testableLooper.processAllMessages() + + assertThat(controller.isCurrentUserSetup).isTrue() + } + + @Test + fun testListenerNotCalledOnAdd() { + init() + controller.addCallback(listener) + + mainExecutor.runAllReady() + + verify(listener, never()).onDeviceProvisionedChanged() + verify(listener, never()).onUserSetupChanged() + verify(listener, never()).onUserSwitched() + } + + @Test + fun testListenerCalledOnUserSwitched() { + init() + controller.addCallback(listener) + + switchUser(10) + + testableLooper.processAllMessages() + mainExecutor.runAllReady() + + verify(listener).onUserSwitched() + verify(listener, never()).onUserSetupChanged() + verify(listener, never()).onDeviceProvisionedChanged() + } + + @Test + fun testListenerCalledOnUserSetupChanged() { + init() + controller.addCallback(listener) + + settings.putIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 1, START_USER) + testableLooper.processAllMessages() + mainExecutor.runAllReady() + + verify(listener, never()).onUserSwitched() + verify(listener).onUserSetupChanged() + verify(listener, never()).onDeviceProvisionedChanged() + } + + @Test + fun testListenerCalledOnDeviceProvisionedChanged() { + init() + controller.addCallback(listener) + + settings.putInt(Settings.Global.DEVICE_PROVISIONED, 1) + testableLooper.processAllMessages() + mainExecutor.runAllReady() + + verify(listener, never()).onUserSwitched() + verify(listener, never()).onUserSetupChanged() + verify(listener).onDeviceProvisionedChanged() + } + + @Test + fun testRemoveListener() { + init() + controller.addCallback(listener) + controller.removeCallback(listener) + + switchUser(10) + settings.putIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 1, START_USER) + settings.putInt(Settings.Global.DEVICE_PROVISIONED, 1) + + testableLooper.processAllMessages() + mainExecutor.runAllReady() + + verify(listener, never()).onDeviceProvisionedChanged() + verify(listener, never()).onUserSetupChanged() + verify(listener, never()).onUserSwitched() + } + + private fun init() { + controller.init() + verify(userTracker).addCallback(capture(userTrackerCallbackCaptor), any()) + } + + private fun switchUser(toUser: Int) { + `when`(userTracker.userId).thenReturn(toUser) + userTrackerCallbackCaptor.value.onUserChanged(toUser, mContext) + } +}
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt index dd43ea56609b..69ab9c51db81 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt @@ -34,6 +34,7 @@ import android.testing.TestableLooper import androidx.test.filters.SmallTest import com.android.internal.jank.InteractionJankMonitor import com.android.internal.logging.testing.UiEventLoggerFake +import com.android.internal.util.LatencyTracker import com.android.internal.util.UserIcons import com.android.systemui.GuestResumeSessionReceiver import com.android.systemui.R @@ -83,6 +84,7 @@ class UserSwitcherControllerTest : SysuiTestCase() { @Mock private lateinit var falsingManager: FalsingManager @Mock private lateinit var dumpManager: DumpManager @Mock private lateinit var interactionJankMonitor: InteractionJankMonitor + @Mock private lateinit var latencyTracker: LatencyTracker private lateinit var testableLooper: TestableLooper private lateinit var uiBgExecutor: FakeExecutor private lateinit var uiEventLogger: UiEventLoggerFake @@ -132,6 +134,7 @@ class UserSwitcherControllerTest : SysuiTestCase() { secureSettings, uiBgExecutor, interactionJankMonitor, + latencyTracker, dumpManager) userSwitcherController.mPauseRefreshUsers = true @@ -156,6 +159,7 @@ class UserSwitcherControllerTest : SysuiTestCase() { userSwitcherController.onUserListItemClicked(emptyGuestUserRecord) testableLooper.processAllMessages() verify(interactionJankMonitor).begin(any()) + verify(latencyTracker).onActionStart(LatencyTracker.ACTION_USER_SWITCH) verify(activityManager).switchUser(guestInfo.id) assertEquals(1, uiEventLogger.numLogs()) assertEquals(QSUserSwitcherEvent.QS_USER_GUEST_ADD.id, uiEventLogger.eventId(0)) diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/TestUnfoldTransitionProvider.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/TestUnfoldTransitionProvider.kt new file mode 100644 index 000000000000..c31640279305 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/TestUnfoldTransitionProvider.kt @@ -0,0 +1,32 @@ +package com.android.systemui.unfold + +import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener + +class TestUnfoldTransitionProvider : UnfoldTransitionProgressProvider, TransitionProgressListener { + + private val listeners = arrayListOf<TransitionProgressListener>() + + override fun destroy() { + listeners.clear() + } + + override fun addCallback(listener: TransitionProgressListener) { + listeners.add(listener) + } + + override fun removeCallback(listener: TransitionProgressListener) { + listeners.remove(listener) + } + + override fun onTransitionStarted() { + listeners.forEach { it.onTransitionStarted() } + } + + override fun onTransitionFinished() { + listeners.forEach { it.onTransitionFinished() } + } + + override fun onTransitionProgress(progress: Float) { + listeners.forEach { it.onTransitionProgress(progress) } + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldTransitionWallpaperControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldTransitionWallpaperControllerTest.kt new file mode 100644 index 000000000000..6ec0251d41a5 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldTransitionWallpaperControllerTest.kt @@ -0,0 +1,51 @@ +package com.android.systemui.unfold + +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.util.WallpaperController +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.AdditionalMatchers.eq +import org.mockito.Mock +import org.mockito.Mockito.verify +import org.mockito.junit.MockitoJUnit + +@RunWith(AndroidTestingRunner::class) +@SmallTest +class UnfoldTransitionWallpaperControllerTest : SysuiTestCase() { + + @Mock + private lateinit var wallpaperController: WallpaperController + + private val progressProvider = TestUnfoldTransitionProvider() + + @JvmField + @Rule + val mockitoRule = MockitoJUnit.rule() + + private lateinit var unfoldWallpaperController: UnfoldTransitionWallpaperController + + @Before + fun setup() { + unfoldWallpaperController = UnfoldTransitionWallpaperController(progressProvider, + wallpaperController) + unfoldWallpaperController.init() + } + + @Test + fun onTransitionProgress_zoomsIn() { + progressProvider.onTransitionProgress(0.8f) + + verify(wallpaperController).setUnfoldTransitionZoom(eq(0.2f, 0.001f)) + } + + @Test + fun onTransitionFinished_resetsZoom() { + progressProvider.onTransitionFinished() + + verify(wallpaperController).setUnfoldTransitionZoom(eq(0f, 0.001f)) + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt new file mode 100644 index 000000000000..a1d9a7b50d81 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt @@ -0,0 +1,178 @@ +/* + * 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.unfold.updates + +import android.hardware.devicestate.DeviceStateManager +import android.hardware.devicestate.DeviceStateManager.FoldStateListener +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.unfold.updates.hinge.HingeAngleProvider +import com.android.systemui.unfold.updates.screen.ScreenStatusProvider +import com.android.systemui.unfold.updates.screen.ScreenStatusProvider.ScreenListener +import com.android.systemui.util.mockito.any +import com.google.common.truth.Truth.assertThat +import org.junit.Assume.assumeTrue +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentCaptor +import org.mockito.Mock +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations + +@RunWith(AndroidTestingRunner::class) +@SmallTest +class DeviceFoldStateProviderTest : SysuiTestCase() { + + @Mock + private lateinit var hingeAngleProvider: HingeAngleProvider + + @Mock + private lateinit var screenStatusProvider: ScreenStatusProvider + + @Mock + private lateinit var deviceStateManager: DeviceStateManager + + private lateinit var foldStateProvider: FoldStateProvider + + private val foldUpdates: MutableList<Int> = arrayListOf() + private val hingeAngleUpdates: MutableList<Float> = arrayListOf() + + private val foldStateListenerCaptor = ArgumentCaptor.forClass(FoldStateListener::class.java) + private var foldedDeviceState: Int = 0 + private var unfoldedDeviceState: Int = 0 + + private val screenOnListenerCaptor = ArgumentCaptor.forClass(ScreenListener::class.java) + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + val foldedDeviceStates: IntArray = context.resources.getIntArray( + com.android.internal.R.array.config_foldedDeviceStates) + assumeTrue("Test should be launched on a foldable device", + foldedDeviceStates.isNotEmpty()) + + foldedDeviceState = foldedDeviceStates.maxOrNull()!! + unfoldedDeviceState = foldedDeviceState + 1 + + foldStateProvider = DeviceFoldStateProvider( + context, + hingeAngleProvider, + screenStatusProvider, + deviceStateManager, + context.mainExecutor + ) + + foldStateProvider.addCallback(object : FoldStateProvider.FoldUpdatesListener { + override fun onHingeAngleUpdate(angle: Float) { + hingeAngleUpdates.add(angle) + } + + override fun onFoldUpdate(update: Int) { + foldUpdates.add(update) + } + }) + foldStateProvider.start() + + verify(deviceStateManager).registerCallback(any(), foldStateListenerCaptor.capture()) + verify(screenStatusProvider).addCallback(screenOnListenerCaptor.capture()) + } + + @Test + fun testOnFolded_emitsFinishClosedEvent() { + setFoldState(folded = true) + + assertThat(foldUpdates).containsExactly(FOLD_UPDATE_FINISH_CLOSED) + } + + @Test + fun testOnUnfolded_emitsStartOpeningEvent() { + setFoldState(folded = false) + + assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_OPENING) + } + + @Test + fun testOnFolded_stopsHingeAngleProvider() { + setFoldState(folded = true) + + verify(hingeAngleProvider).stop() + } + + @Test + fun testOnUnfolded_startsHingeAngleProvider() { + setFoldState(folded = false) + + verify(hingeAngleProvider).start() + } + + @Test + fun testFirstScreenOnEventWhenFolded_doesNotEmitEvents() { + setFoldState(folded = true) + foldUpdates.clear() + + fireScreenOnEvent() + + // Power button turn on + assertThat(foldUpdates).isEmpty() + } + + @Test + fun testFirstScreenOnEventWhenUnfolded_doesNotEmitEvents() { + setFoldState(folded = false) + foldUpdates.clear() + + fireScreenOnEvent() + + assertThat(foldUpdates).isEmpty() + } + + @Test + fun testFirstScreenOnEventAfterFoldAndUnfold_emitsUnfoldedScreenAvailableEvent() { + setFoldState(folded = false) + setFoldState(folded = true) + fireScreenOnEvent() + setFoldState(folded = false) + foldUpdates.clear() + + fireScreenOnEvent() + + assertThat(foldUpdates).containsExactly(FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE) + } + + @Test + fun testSecondScreenOnEventWhenUnfolded_doesNotEmitEvents() { + setFoldState(folded = false) + fireScreenOnEvent() + foldUpdates.clear() + + fireScreenOnEvent() + + // No events as this is power button turn on + assertThat(foldUpdates).isEmpty() + } + + private fun setFoldState(folded: Boolean) { + val state = if (folded) foldedDeviceState else unfoldedDeviceState + foldStateListenerCaptor.value.onStateChanged(state) + } + + private fun fireScreenOnEvent() { + screenOnListenerCaptor.value.onScreenTurnedOn() + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/util/NaturalRotationUnfoldProgressProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/util/NaturalRotationUnfoldProgressProviderTest.kt new file mode 100644 index 000000000000..a3f17aa5ba55 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/util/NaturalRotationUnfoldProgressProviderTest.kt @@ -0,0 +1,139 @@ +/* + * 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.unfold.util + +import android.testing.AndroidTestingRunner +import android.view.IRotationWatcher +import android.view.IWindowManager +import android.view.Surface +import androidx.test.filters.SmallTest +import com.android.systemui.unfold.UnfoldTransitionProgressProvider +import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener +import com.android.systemui.util.mockito.any +import com.android.systemui.SysuiTestCase +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentCaptor +import org.mockito.Mock +import org.mockito.Mockito.verify +import org.mockito.Mockito.clearInvocations +import org.mockito.Mockito.never +import org.mockito.MockitoAnnotations + +@RunWith(AndroidTestingRunner::class) +@SmallTest +class NaturalRotationUnfoldProgressProviderTest : SysuiTestCase() { + + @Mock + lateinit var windowManager: IWindowManager + + @Mock + lateinit var sourceProvider: UnfoldTransitionProgressProvider + + @Mock + lateinit var transitionListener: TransitionProgressListener + + lateinit var progressProvider: NaturalRotationUnfoldProgressProvider + + private val sourceProviderListenerCaptor = + ArgumentCaptor.forClass(TransitionProgressListener::class.java) + private val rotationWatcherCaptor = + ArgumentCaptor.forClass(IRotationWatcher.Stub::class.java) + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + + progressProvider = NaturalRotationUnfoldProgressProvider( + context, + windowManager, + sourceProvider + ) + + progressProvider.init() + + verify(sourceProvider).addCallback(sourceProviderListenerCaptor.capture()) + verify(windowManager).watchRotation(rotationWatcherCaptor.capture(), any()) + + progressProvider.addCallback(transitionListener) + } + + @Test + fun testNaturalRotation0_sendTransitionStartedEvent_eventReceived() { + onRotationChanged(Surface.ROTATION_0) + + source.onTransitionStarted() + + verify(transitionListener).onTransitionStarted() + } + + @Test + fun testNaturalRotation0_sendTransitionProgressEvent_eventReceived() { + onRotationChanged(Surface.ROTATION_0) + + source.onTransitionProgress(0.5f) + + verify(transitionListener).onTransitionProgress(0.5f) + } + + @Test + fun testNotNaturalRotation90_sendTransitionStartedEvent_eventNotReceived() { + onRotationChanged(Surface.ROTATION_90) + + source.onTransitionStarted() + + verify(transitionListener, never()).onTransitionStarted() + } + + @Test + fun testNaturalRotation90_sendTransitionProgressEvent_eventNotReceived() { + onRotationChanged(Surface.ROTATION_90) + + source.onTransitionProgress(0.5f) + + verify(transitionListener, never()).onTransitionProgress(0.5f) + } + + @Test + fun testRotationBecameUnnaturalDuringTransition_sendsTransitionFinishedEvent() { + onRotationChanged(Surface.ROTATION_0) + source.onTransitionStarted() + clearInvocations(transitionListener) + + onRotationChanged(Surface.ROTATION_90) + + verify(transitionListener).onTransitionFinished() + } + + @Test + fun testRotationBecameNaturalDuringTransition_sendsTransitionStartedEvent() { + onRotationChanged(Surface.ROTATION_90) + source.onTransitionStarted() + clearInvocations(transitionListener) + + onRotationChanged(Surface.ROTATION_0) + + verify(transitionListener).onTransitionStarted() + } + + private fun onRotationChanged(rotation: Int) { + rotationWatcherCaptor.value.onRotationChanged(rotation) + } + + private val source: TransitionProgressListener + get() = sourceProviderListenerCaptor.value +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/FakeSensorManager.java b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/FakeSensorManager.java index 6e73827fedfb..197873f15d0d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/FakeSensorManager.java +++ b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/FakeSensorManager.java @@ -55,6 +55,7 @@ public class FakeSensorManager extends SensorManager { private final FakeProximitySensor mFakeProximitySensor; private final FakeGenericSensor mFakeLightSensor; + private final FakeGenericSensor mFakeLightSensor2; private final FakeGenericSensor mFakeTapSensor; private final FakeGenericSensor[] mSensors; @@ -70,7 +71,8 @@ public class FakeSensorManager extends SensorManager { mSensors = new FakeGenericSensor[]{ mFakeProximitySensor = new FakeProximitySensor(proxSensor), mFakeLightSensor = new FakeGenericSensor(createSensor(Sensor.TYPE_LIGHT, null)), - mFakeTapSensor = new FakeGenericSensor(createSensor(99, TAP_SENSOR_TYPE)) + mFakeTapSensor = new FakeGenericSensor(createSensor(99, TAP_SENSOR_TYPE)), + mFakeLightSensor2 = new FakeGenericSensor(createSensor(Sensor.TYPE_LIGHT, null)) }; } @@ -82,6 +84,10 @@ public class FakeSensorManager extends SensorManager { return mFakeLightSensor; } + public FakeGenericSensor getFakeLightSensor2() { + return mFakeLightSensor2; + } + public FakeGenericSensor getFakeTapSensor() { return mFakeTapSensor; } diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettings.java b/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettings.java index 7bb26748a9d9..e66491e4cbd1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettings.java +++ b/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettings.java @@ -123,11 +123,11 @@ public class FakeSettings implements SecureSettings, GlobalSettings, SystemSetti Uri uri = getUriFor(name); for (ContentObserver observer : mContentObservers.getOrDefault(key, new ArrayList<>())) { - observer.dispatchChange(false, List.of(uri), userHandle); + observer.dispatchChange(false, List.of(uri), 0, userHandle); } for (ContentObserver observer : mContentObserversAllUsers.getOrDefault(uri.toString(), new ArrayList<>())) { - observer.dispatchChange(false, List.of(uri), userHandle); + observer.dispatchChange(false, List.of(uri), 0, userHandle); } return true; } diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettingsTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettingsTest.java index 34cae58d30e1..f65caee24e34 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettingsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettingsTest.java @@ -21,6 +21,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; @@ -86,7 +87,8 @@ public class FakeSettingsTest extends SysuiTestCase { mFakeSettings.putString("cat", "hat"); - verify(mContentObserver).dispatchChange(anyBoolean(), any(Collection.class), anyInt()); + verify(mContentObserver).dispatchChange(anyBoolean(), any(Collection.class), anyInt(), + anyInt()); } @Test @@ -96,7 +98,8 @@ public class FakeSettingsTest extends SysuiTestCase { mFakeSettings.putString("cat", "hat"); - verify(mContentObserver).dispatchChange(anyBoolean(), any(Collection.class), anyInt()); + verify(mContentObserver).dispatchChange(anyBoolean(), any(Collection.class), anyInt(), + anyInt()); } @Test @@ -119,6 +122,18 @@ public class FakeSettingsTest extends SysuiTestCase { mFakeSettings.putString("cat", "hat"); verify(mContentObserver, never()).dispatchChange( - anyBoolean(), any(Collection.class), anyInt()); + anyBoolean(), any(Collection.class), anyInt(), anyInt()); + } + + @Test + public void testContentObserverDispatchCorrectUser() { + int user = 10; + mFakeSettings.registerContentObserverForUser( + mFakeSettings.getUriFor("cat"), false, mContentObserver, UserHandle.USER_ALL + ); + + mFakeSettings.putStringForUser("cat", "hat", user); + verify(mContentObserver).dispatchChange(anyBoolean(), any(Collection.class), anyInt(), + eq(user)); } } 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 9f755f7be2c7..1159e0912926 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java @@ -179,6 +179,7 @@ public class BubblesTest extends SysuiTestCase { private SysUiState mSysUiState; private boolean mSysUiStateBubblesExpanded; + private boolean mSysUiStateBubblesManageMenuExpanded; @Captor private ArgumentCaptor<NotificationEntryListener> mEntryListenerCaptor; @@ -295,9 +296,13 @@ public class BubblesTest extends SysuiTestCase { when(mZenModeController.getConfig()).thenReturn(mZenModeConfig); mSysUiState = new SysUiState(); - mSysUiState.addCallback(sysUiFlags -> - mSysUiStateBubblesExpanded = - (sysUiFlags & QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED) != 0); + mSysUiState.addCallback(sysUiFlags -> { + mSysUiStateBubblesManageMenuExpanded = + (sysUiFlags + & QuickStepContract.SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED) != 0; + mSysUiStateBubblesExpanded = + (sysUiFlags & QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED) != 0; + }); // TODO: Fix mPositioner = new TestableBubblePositioner(mContext, mWindowManager); @@ -372,8 +377,7 @@ public class BubblesTest extends SysuiTestCase { public void testAddBubble() { mBubbleController.updateBubble(mBubbleEntry); assertTrue(mBubbleController.hasBubbles()); - - assertFalse(mSysUiStateBubblesExpanded); + assertSysuiStates(false /* stackExpanded */, false /* mangeMenuExpanded */); } @Test @@ -381,7 +385,7 @@ public class BubblesTest extends SysuiTestCase { assertFalse(mBubbleController.hasBubbles()); mBubbleController.updateBubble(mBubbleEntry); assertTrue(mBubbleController.hasBubbles()); - assertFalse(mSysUiStateBubblesExpanded); + assertSysuiStates(false /* stackExpanded */, false /* mangeMenuExpanded */); } @Test @@ -396,7 +400,7 @@ public class BubblesTest extends SysuiTestCase { assertNull(mBubbleData.getBubbleInStackWithKey(mRow.getKey())); verify(mNotificationEntryManager, times(2)).updateNotifications(anyString()); - assertFalse(mSysUiStateBubblesExpanded); + assertSysuiStates(false /* stackExpanded */, false /* mangeMenuExpanded */); } @Test @@ -459,7 +463,7 @@ public class BubblesTest extends SysuiTestCase { verify(mNotificationEntryManager, never()).performRemoveNotification( eq(mRow.getSbn()), any(), anyInt()); assertFalse(mBubbleController.hasBubbles()); - assertFalse(mSysUiStateBubblesExpanded); + assertSysuiStates(false /* stackExpanded */, false /* mangeMenuExpanded */); assertTrue(mRow.isBubble()); } @@ -478,7 +482,7 @@ public class BubblesTest extends SysuiTestCase { assertNull(mBubbleData.getBubbleInStackWithKey(mRow.getKey())); assertNull(mBubbleData.getBubbleInStackWithKey(mRow2.getKey())); - assertFalse(mSysUiStateBubblesExpanded); + assertSysuiStates(false /* stackExpanded */, false /* mangeMenuExpanded */); } @Test @@ -498,8 +502,7 @@ public class BubblesTest extends SysuiTestCase { mBubbleData.setExpanded(true); assertStackExpanded(); verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getKey()); - - assertTrue(mSysUiStateBubblesExpanded); + assertSysuiStates(true /* stackExpanded */, false /* mangeMenuExpanded */); // Make sure the notif is suppressed assertBubbleNotificationSuppressedFromShade(mBubbleEntry); @@ -508,8 +511,7 @@ public class BubblesTest extends SysuiTestCase { mBubbleController.collapseStack(); verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getKey()); assertStackCollapsed(); - - assertFalse(mSysUiStateBubblesExpanded); + assertSysuiStates(false /* stackExpanded */, false /* mangeMenuExpanded */); } @Test @@ -532,8 +534,7 @@ public class BubblesTest extends SysuiTestCase { assertStackExpanded(); verify(mBubbleExpandListener, atLeastOnce()).onBubbleExpandChanged( true, mRow2.getKey()); - - assertTrue(mSysUiStateBubblesExpanded); + assertSysuiStates(true /* stackExpanded */, false /* mangeMenuExpanded */); // Last added is the one that is expanded assertEquals(mRow2.getKey(), mBubbleData.getSelectedBubble().getKey()); @@ -557,8 +558,7 @@ public class BubblesTest extends SysuiTestCase { // Collapse mBubbleController.collapseStack(); assertStackCollapsed(); - - assertFalse(mSysUiStateBubblesExpanded); + assertSysuiStates(false /* stackExpanded */, false /* mangeMenuExpanded */); } @Test @@ -578,8 +578,7 @@ public class BubblesTest extends SysuiTestCase { mBubbleData.setExpanded(true); assertStackExpanded(); verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getKey()); - - assertTrue(mSysUiStateBubblesExpanded); + assertSysuiStates(true /* stackExpanded */, false /* mangeMenuExpanded */); // Notif is suppressed after expansion assertBubbleNotificationSuppressedFromShade(mBubbleEntry); @@ -604,8 +603,7 @@ public class BubblesTest extends SysuiTestCase { mBubbleData.setExpanded(true); assertStackExpanded(); verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getKey()); - - assertTrue(mSysUiStateBubblesExpanded); + assertSysuiStates(true /* stackExpanded */, false /* mangeMenuExpanded */); // Notif is suppressed after expansion assertBubbleNotificationSuppressedFromShade(mBubbleEntry); @@ -634,7 +632,7 @@ public class BubblesTest extends SysuiTestCase { BubbleStackView stackView = mBubbleController.getStackView(); mBubbleData.setExpanded(true); - assertTrue(mSysUiStateBubblesExpanded); + assertSysuiStates(true /* stackExpanded */, false /* mangeMenuExpanded */); assertStackExpanded(); verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getKey()); @@ -666,7 +664,7 @@ public class BubblesTest extends SysuiTestCase { assertEquals(mBubbleData.getSelectedBubble().getKey(), BubbleOverflow.KEY); verify(mBubbleExpandListener).onBubbleExpandChanged(true, BubbleOverflow.KEY); assertTrue(mBubbleController.hasBubbles()); - assertTrue(mSysUiStateBubblesExpanded); + assertSysuiStates(true /* stackExpanded */, false /* mangeMenuExpanded */); } @Test @@ -679,7 +677,7 @@ public class BubblesTest extends SysuiTestCase { BubbleStackView stackView = mBubbleController.getStackView(); mBubbleData.setExpanded(true); - assertTrue(mSysUiStateBubblesExpanded); + assertSysuiStates(true /* stackExpanded */, false /* mangeMenuExpanded */); assertStackExpanded(); verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getKey()); @@ -694,7 +692,7 @@ public class BubblesTest extends SysuiTestCase { // We should be collapsed verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getKey()); assertFalse(mBubbleController.hasBubbles()); - assertFalse(mSysUiStateBubblesExpanded); + assertSysuiStates(false /* stackExpanded */, false /* mangeMenuExpanded */); } @Test @@ -711,8 +709,7 @@ public class BubblesTest extends SysuiTestCase { verify(mBubbleExpandListener, never()).onBubbleExpandChanged(false /* expanded */, mRow.getKey()); assertStackCollapsed(); - - assertFalse(mSysUiStateBubblesExpanded); + assertSysuiStates(false /* stackExpanded */, false /* mangeMenuExpanded */); } @Test @@ -728,8 +725,7 @@ public class BubblesTest extends SysuiTestCase { verify(mBubbleExpandListener).onBubbleExpandChanged(true /* expanded */, mRow.getKey()); assertStackExpanded(); - - assertTrue(mSysUiStateBubblesExpanded); + assertSysuiStates(true /* stackExpanded */, false /* mangeMenuExpanded */); } @Test @@ -746,8 +742,7 @@ public class BubblesTest extends SysuiTestCase { // Dot + flyout is hidden because notif is suppressed assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot()); assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showFlyout()); - - assertFalse(mSysUiStateBubblesExpanded); + assertSysuiStates(false /* stackExpanded */, false /* mangeMenuExpanded */); } @Test @@ -769,8 +764,7 @@ public class BubblesTest extends SysuiTestCase { // Dot + flyout is hidden because notif is suppressed assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot()); assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showFlyout()); - - assertFalse(mSysUiStateBubblesExpanded); + assertSysuiStates(false /* stackExpanded */, false /* mangeMenuExpanded */); } @Test @@ -784,7 +778,7 @@ public class BubblesTest extends SysuiTestCase { mBubbleController.expandStackAndSelectBubble(mBubbleEntry); - assertTrue(mSysUiStateBubblesExpanded); + assertSysuiStates(true /* stackExpanded */, false /* mangeMenuExpanded */); } @Test @@ -1206,6 +1200,63 @@ public class BubblesTest extends SysuiTestCase { assertNotNull(info); } + @Test + public void testShowManageMenuChangesSysuiState() { + mBubbleController.updateBubble(mBubbleEntry); + assertTrue(mBubbleController.hasBubbles()); + + // Expand the stack + BubbleStackView stackView = mBubbleController.getStackView(); + mBubbleData.setExpanded(true); + assertStackExpanded(); + assertSysuiStates(true /* stackExpanded */, false /* mangeMenuExpanded */); + + // Show the menu + stackView.showManageMenu(true); + assertSysuiStates(true /* stackExpanded */, true /* mangeMenuExpanded */); + } + + @Test + public void testHideManageMenuChangesSysuiState() { + mBubbleController.updateBubble(mBubbleEntry); + assertTrue(mBubbleController.hasBubbles()); + + // Expand the stack + BubbleStackView stackView = mBubbleController.getStackView(); + mBubbleData.setExpanded(true); + assertStackExpanded(); + assertSysuiStates(true /* stackExpanded */, false /* mangeMenuExpanded */); + + // Show the menu + stackView.showManageMenu(true); + assertSysuiStates(true /* stackExpanded */, true /* mangeMenuExpanded */); + + // Hide the menu + stackView.showManageMenu(false); + assertSysuiStates(true /* stackExpanded */, false /* mangeMenuExpanded */); + } + + @Test + public void testCollapseBubbleManageMenuChangesSysuiState() { + mBubbleController.updateBubble(mBubbleEntry); + assertTrue(mBubbleController.hasBubbles()); + + // Expand the stack + BubbleStackView stackView = mBubbleController.getStackView(); + mBubbleData.setExpanded(true); + assertStackExpanded(); + assertSysuiStates(true /* stackExpanded */, false /* mangeMenuExpanded */); + + // Show the menu + stackView.showManageMenu(true); + assertSysuiStates(true /* stackExpanded */, true /* mangeMenuExpanded */); + + // Collapse the stack + mBubbleData.setExpanded(false); + + assertSysuiStates(false /* stackExpanded */, false /* mangeMenuExpanded */); + } + /** Creates a bubble using the userId and package. */ private Bubble createBubble(int userId, String pkg) { final UserHandle userHandle = new UserHandle(userId); @@ -1303,4 +1354,12 @@ public class BubblesTest extends SysuiTestCase { assertFalse(mBubbleController.getImplCachedState().isBubbleNotificationSuppressedFromShade( entry.getKey(), entry.getGroupKey())); } + + /** + * Asserts that the system ui states associated to bubbles are in the correct state. + */ + private void assertSysuiStates(boolean stackExpanded, boolean manageMenuExpanded) { + assertThat(mSysUiStateBubblesExpanded).isEqualTo(stackExpanded); + assertThat(mSysUiStateBubblesManageMenuExpanded).isEqualTo(manageMenuExpanded); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java index a3bbb26c6b23..05c4822f288e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java @@ -68,6 +68,7 @@ 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; +import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.RankingBuilder; import com.android.systemui.statusbar.SysuiStatusBarStateController; @@ -160,7 +161,9 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase { @Mock private AuthController mAuthController; - private SysUiState mSysUiState = new SysUiState(); + private SysUiState mSysUiState; + private boolean mSysUiStateBubblesExpanded; + private boolean mSysUiStateBubblesManageMenuExpanded; @Captor private ArgumentCaptor<NotifCollectionListener> mNotifListenerCaptor; @@ -257,6 +260,15 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase { mZenModeConfig.suppressedVisualEffects = 0; when(mZenModeController.getConfig()).thenReturn(mZenModeConfig); + mSysUiState = new SysUiState(); + mSysUiState.addCallback(sysUiFlags -> { + mSysUiStateBubblesManageMenuExpanded = + (sysUiFlags + & QuickStepContract.SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED) != 0; + mSysUiStateBubblesExpanded = + (sysUiFlags & QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED) != 0; + }); + mPositioner = new TestableBubblePositioner(mContext, mWindowManager); mPositioner.setMaxBubbles(5); mBubbleData = new BubbleData(mContext, mBubbleLogger, mPositioner, syncExecutor); @@ -325,6 +337,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase { public void testAddBubble() { mBubbleController.updateBubble(mBubbleEntry); assertTrue(mBubbleController.hasBubbles()); + assertSysuiStates(false /* stackExpanded */, false /* mangeMenuExpanded */); } @Test @@ -332,6 +345,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase { assertFalse(mBubbleController.hasBubbles()); mBubbleController.updateBubble(mBubbleEntry); assertTrue(mBubbleController.hasBubbles()); + assertSysuiStates(false /* stackExpanded */, false /* mangeMenuExpanded */); } @Test @@ -345,6 +359,8 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase { mRow.getKey(), Bubbles.DISMISS_USER_GESTURE); assertNull(mBubbleData.getBubbleInStackWithKey(mRow.getKey())); verify(mNotifCallback, times(2)).invalidateNotifications(anyString()); + + assertSysuiStates(false /* stackExpanded */, false /* mangeMenuExpanded */); } @Test @@ -407,6 +423,8 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase { verify(mNotifCallback, times(3)).invalidateNotifications(anyString()); assertNull(mBubbleData.getBubbleInStackWithKey(mRow.getKey())); assertNull(mBubbleData.getBubbleInStackWithKey(mRow2.getKey())); + + assertSysuiStates(false /* stackExpanded */, false /* mangeMenuExpanded */); } @Test @@ -425,6 +443,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase { mBubbleData.setExpanded(true); assertStackExpanded(); verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getKey()); + assertSysuiStates(true /* stackExpanded */, false /* mangeMenuExpanded */); // Make sure the notif is suppressed assertBubbleNotificationSuppressedFromShade(mBubbleEntry); @@ -433,6 +452,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase { mBubbleController.collapseStack(); verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getKey()); assertStackCollapsed(); + assertSysuiStates(false /* stackExpanded */, false /* mangeMenuExpanded */); } @Test @@ -455,6 +475,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase { assertStackExpanded(); verify(mBubbleExpandListener, atLeastOnce()).onBubbleExpandChanged( true, mRow2.getKey()); + assertSysuiStates(true /* stackExpanded */, false /* mangeMenuExpanded */); // Last added is the one that is expanded assertEquals(mRow2.getKey(), mBubbleData.getSelectedBubble().getKey()); @@ -479,6 +500,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase { // Collapse mBubbleController.collapseStack(); assertStackCollapsed(); + assertSysuiStates(false /* stackExpanded */, false /* mangeMenuExpanded */); } @Test @@ -498,6 +520,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase { mBubbleData.setExpanded(true); assertStackExpanded(); verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getKey()); + assertSysuiStates(true /* stackExpanded */, false /* mangeMenuExpanded */); // Notif is suppressed after expansion assertBubbleNotificationSuppressedFromShade(mBubbleEntry); @@ -522,6 +545,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase { mBubbleData.setExpanded(true); assertStackExpanded(); verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getKey()); + assertSysuiStates(true /* stackExpanded */, false /* mangeMenuExpanded */); // Notif is suppressed after expansion assertBubbleNotificationSuppressedFromShade(mBubbleEntry); @@ -550,6 +574,8 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase { BubbleStackView stackView = mBubbleController.getStackView(); mBubbleData.setExpanded(true); + assertSysuiStates(true /* stackExpanded */, false /* mangeMenuExpanded */); + assertStackExpanded(); verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getKey()); @@ -580,6 +606,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase { assertEquals(mBubbleData.getSelectedBubble().getKey(), BubbleOverflow.KEY); verify(mBubbleExpandListener).onBubbleExpandChanged(true, BubbleOverflow.KEY); assertTrue(mBubbleController.hasBubbles()); + assertSysuiStates(true /* stackExpanded */, false /* mangeMenuExpanded */); } @Test @@ -592,6 +619,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase { BubbleStackView stackView = mBubbleController.getStackView(); mBubbleData.setExpanded(true); + assertSysuiStates(true /* stackExpanded */, false /* mangeMenuExpanded */); assertStackExpanded(); verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getKey()); @@ -606,6 +634,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase { // We should be collapsed verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getKey()); assertFalse(mBubbleController.hasBubbles()); + assertSysuiStates(false /* stackExpanded */, false /* mangeMenuExpanded */); } @@ -623,6 +652,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase { verify(mBubbleExpandListener, never()).onBubbleExpandChanged(false /* expanded */, mRow.getKey()); assertStackCollapsed(); + assertSysuiStates(false /* stackExpanded */, false /* mangeMenuExpanded */); } @Test @@ -638,6 +668,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase { verify(mBubbleExpandListener).onBubbleExpandChanged(true /* expanded */, mRow.getKey()); assertStackExpanded(); + assertSysuiStates(true /* stackExpanded */, false /* mangeMenuExpanded */); } @Test @@ -654,6 +685,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase { // Dot + flyout is hidden because notif is suppressed assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot()); assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showFlyout()); + assertSysuiStates(false /* stackExpanded */, false /* mangeMenuExpanded */); } @Test @@ -675,6 +707,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase { // Dot + flyout is hidden because notif is suppressed assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot()); assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showFlyout()); + assertSysuiStates(false /* stackExpanded */, false /* mangeMenuExpanded */); } @Test @@ -980,6 +1013,63 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase { verify(mDataRepository, times(1)).loadBubbles(anyInt(), any()); } + @Test + public void testShowManageMenuChangesSysuiState() { + mBubbleController.updateBubble(mBubbleEntry); + assertTrue(mBubbleController.hasBubbles()); + + // Expand the stack + BubbleStackView stackView = mBubbleController.getStackView(); + mBubbleData.setExpanded(true); + assertStackExpanded(); + assertSysuiStates(true /* stackExpanded */, false /* mangeMenuExpanded */); + + // Show the menu + stackView.showManageMenu(true); + assertSysuiStates(true /* stackExpanded */, true /* mangeMenuExpanded */); + } + + @Test + public void testHideManageMenuChangesSysuiState() { + mBubbleController.updateBubble(mBubbleEntry); + assertTrue(mBubbleController.hasBubbles()); + + // Expand the stack + BubbleStackView stackView = mBubbleController.getStackView(); + mBubbleData.setExpanded(true); + assertStackExpanded(); + assertSysuiStates(true /* stackExpanded */, false /* mangeMenuExpanded */); + + // Show the menu + stackView.showManageMenu(true); + assertSysuiStates(true /* stackExpanded */, true /* mangeMenuExpanded */); + + // Hide the menu + stackView.showManageMenu(false); + assertSysuiStates(true /* stackExpanded */, false /* mangeMenuExpanded */); + } + + @Test + public void testCollapseBubbleManageMenuChangesSysuiState() { + mBubbleController.updateBubble(mBubbleEntry); + assertTrue(mBubbleController.hasBubbles()); + + // Expand the stack + BubbleStackView stackView = mBubbleController.getStackView(); + mBubbleData.setExpanded(true); + assertStackExpanded(); + assertSysuiStates(true /* stackExpanded */, false /* mangeMenuExpanded */); + + // Show the menu + stackView.showManageMenu(true); + assertSysuiStates(true /* stackExpanded */, true /* mangeMenuExpanded */); + + // Collapse the stack + mBubbleData.setExpanded(false); + + assertSysuiStates(false /* stackExpanded */, false /* mangeMenuExpanded */); + } + /** * Sets the bubble metadata flags for this entry. These flags are normally set by * NotificationManagerService when the notification is sent, however, these tests do not @@ -1034,4 +1124,12 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase { assertFalse(mBubbleController.getImplCachedState().isBubbleNotificationSuppressedFromShade( entry.getKey(), entry.getGroupKey())); } + + /** + * Asserts that the system ui states associated to bubbles are in the correct state. + */ + private void assertSysuiStates(boolean stackExpanded, boolean manageMenuExpanded) { + assertThat(mSysUiStateBubblesExpanded).isEqualTo(stackExpanded); + assertThat(mSysUiStateBubblesManageMenuExpanded).isEqualTo(manageMenuExpanded); + } } diff --git a/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values-land/config.xml b/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values-land/config.xml deleted file mode 100644 index bd52901cef95..000000000000 --- a/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values-land/config.xml +++ /dev/null @@ -1,22 +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 - --> - -<resources> - <!-- Can't link to other dimensions here, but this should be status_bar_height_landscape --> - <dimen name="quick_qs_offset_height">28dp</dimen> - <!-- Total height of QQS in landscape; quick_qs_offset_height + 128 --> - <dimen name="quick_qs_total_height">156dp</dimen> -</resources>
\ No newline at end of file diff --git a/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values/config.xml b/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values/config.xml index 9254b4d65b50..c340432b9b8c 100644 --- a/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values/config.xml +++ b/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values/config.xml @@ -44,14 +44,6 @@ --> <bool name="config_fillMainBuiltInDisplayCutout">true</bool> - <!-- Height of the status bar --> - <dimen name="status_bar_height_portrait">48dp</dimen> - <dimen name="status_bar_height_landscape">28dp</dimen> - <!-- Height of area above QQS where battery/time go (equal to status bar height if > 48dp) --> - <dimen name="quick_qs_offset_height">48dp</dimen> - <!-- Total height of QQS (quick_qs_offset_height + 128) --> - <dimen name="quick_qs_total_height">176dp</dimen> - </resources> diff --git a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values-land/config.xml b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values-land/config.xml deleted file mode 100644 index bd52901cef95..000000000000 --- a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values-land/config.xml +++ /dev/null @@ -1,22 +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 - --> - -<resources> - <!-- Can't link to other dimensions here, but this should be status_bar_height_landscape --> - <dimen name="quick_qs_offset_height">28dp</dimen> - <!-- Total height of QQS in landscape; quick_qs_offset_height + 128 --> - <dimen name="quick_qs_total_height">156dp</dimen> -</resources>
\ No newline at end of file diff --git a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/config.xml b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/config.xml index 80c997a46264..928d9dfa3ce1 100644 --- a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/config.xml +++ b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/config.xml @@ -56,14 +56,6 @@ --> <bool name="config_fillMainBuiltInDisplayCutout">true</bool> - <!-- Height of the status bar --> - <dimen name="status_bar_height_portrait">48dp</dimen> - <dimen name="status_bar_height_landscape">28dp</dimen> - <!-- Height of area above QQS where battery/time go (equal to status bar height if > 48dp) --> - <dimen name="quick_qs_offset_height">48dp</dimen> - <!-- Total height of QQS (quick_qs_offset_height + 128) --> - <dimen name="quick_qs_total_height">176dp</dimen> - </resources> diff --git a/packages/overlays/DisplayCutoutEmulationHoleOverlay/res/values-land/config.xml b/packages/overlays/DisplayCutoutEmulationHoleOverlay/res/values-land/config.xml deleted file mode 100644 index 2e971ded2256..000000000000 --- a/packages/overlays/DisplayCutoutEmulationHoleOverlay/res/values-land/config.xml +++ /dev/null @@ -1,22 +0,0 @@ -<!-- - ~ Copyright (C) 2020 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License - --> - -<resources> - <!-- Can't link to other dimensions here, but this should be status_bar_height_landscape --> - <dimen name="quick_qs_offset_height">28dp</dimen> - <!-- Total height of QQS in landscape; quick_qs_offset_height + 128 --> - <dimen name="quick_qs_total_height">156dp</dimen> -</resources> diff --git a/packages/overlays/DisplayCutoutEmulationHoleOverlay/res/values/config.xml b/packages/overlays/DisplayCutoutEmulationHoleOverlay/res/values/config.xml index 9f558d0e2bd5..62f0535a1746 100644 --- a/packages/overlays/DisplayCutoutEmulationHoleOverlay/res/values/config.xml +++ b/packages/overlays/DisplayCutoutEmulationHoleOverlay/res/values/config.xml @@ -48,14 +48,6 @@ --> <bool name="config_fillMainBuiltInDisplayCutout">true</bool> - <!-- Height of the status bar --> - <dimen name="status_bar_height_portrait">136px</dimen> - <dimen name="status_bar_height_landscape">28dp</dimen> - <!-- Height of area above QQS where battery/time go (equal to status bar) --> - <dimen name="quick_qs_offset_height">136px</dimen> - <!-- Total height of QQS (quick_qs_offset_height + 128) --> - <dimen name="quick_qs_total_height">488px</dimen> - </resources> diff --git a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values-land/config.xml b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values-land/config.xml deleted file mode 100644 index bd52901cef95..000000000000 --- a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values-land/config.xml +++ /dev/null @@ -1,22 +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 - --> - -<resources> - <!-- Can't link to other dimensions here, but this should be status_bar_height_landscape --> - <dimen name="quick_qs_offset_height">28dp</dimen> - <!-- Total height of QQS in landscape; quick_qs_offset_height + 128 --> - <dimen name="quick_qs_total_height">156dp</dimen> -</resources>
\ No newline at end of file diff --git a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values/config.xml b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values/config.xml index 6fb3c7f51e26..a9f8b4bc6329 100644 --- a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values/config.xml +++ b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values/config.xml @@ -47,14 +47,6 @@ --> <bool name="config_fillMainBuiltInDisplayCutout">true</bool> - <!-- Height of the status bar --> - <dimen name="status_bar_height_portrait">48dp</dimen> - <dimen name="status_bar_height_landscape">28dp</dimen> - <!-- Height of area above QQS where battery/time go (equal to status bar height if > 48dp) --> - <dimen name="quick_qs_offset_height">48dp</dimen> - <!-- Total height of QQS (quick_qs_offset_height + 128) --> - <dimen name="quick_qs_total_height">176dp</dimen> - </resources> diff --git a/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values-land/config.xml b/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values-land/config.xml deleted file mode 100644 index bd52901cef95..000000000000 --- a/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values-land/config.xml +++ /dev/null @@ -1,22 +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 - --> - -<resources> - <!-- Can't link to other dimensions here, but this should be status_bar_height_landscape --> - <dimen name="quick_qs_offset_height">28dp</dimen> - <!-- Total height of QQS in landscape; quick_qs_offset_height + 128 --> - <dimen name="quick_qs_total_height">156dp</dimen> -</resources>
\ No newline at end of file diff --git a/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values/config.xml b/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values/config.xml index 7c29ffb92f4e..be7d0e48fa3f 100644 --- a/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values/config.xml +++ b/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values/config.xml @@ -47,14 +47,6 @@ --> <bool name="config_fillMainBuiltInDisplayCutout">true</bool> - <!-- Height of the status bar --> - <dimen name="status_bar_height_portrait">48dp</dimen> - <dimen name="status_bar_height_landscape">28dp</dimen> - <!-- Height of area above QQS where battery/time go (equal to status bar height if > 48dp) --> - <dimen name="quick_qs_offset_height">48dp</dimen> - <!-- Total height of QQS (quick_qs_offset_height + 128) --> - <dimen name="quick_qs_total_height">176dp</dimen> - </resources> diff --git a/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-land/config.xml b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-land/config.xml deleted file mode 100644 index df2f3d19626e..000000000000 --- a/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-land/config.xml +++ /dev/null @@ -1,22 +0,0 @@ -<!-- - ~ Copyright (C) 2020 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<resources> - <!-- Can't link to other dimensions here, but this should be status_bar_height_landscape --> - <dimen name="quick_qs_offset_height">48dp</dimen> - <!-- Total height of QQS in landscape; quick_qs_offset_height + 128 --> - <dimen name="quick_qs_total_height">176dp</dimen> -</resources>
\ No newline at end of file diff --git a/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values/config.xml b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values/config.xml index 8d0227eed875..cc51ebee270c 100644 --- a/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values/config.xml +++ b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values/config.xml @@ -19,16 +19,6 @@ <string translatable="false" name="config_mainBuiltInDisplayCutout"></string> <string translatable="false" name="config_mainBuiltInDisplayCutoutRectApproximation"></string> - <!-- Height of the status bar in portrait. The height should be - Max((status bar content height + waterfall top size), top cutout size) --> - <dimen name="status_bar_height_portrait">28dp</dimen> - <!-- Max((28 + 20), 0) = 48 --> - <dimen name="status_bar_height_landscape">48dp</dimen> - <!-- Height of area above QQS where battery/time go (equal to status bar height if > 48dp) --> - <dimen name="quick_qs_offset_height">48dp</dimen> - <!-- Total height of QQS (quick_qs_offset_height + 128) --> - <dimen name="quick_qs_total_height">176dp</dimen> - <dimen name="waterfall_display_left_edge_size">20dp</dimen> <dimen name="waterfall_display_top_edge_size">0dp</dimen> <dimen name="waterfall_display_right_edge_size">20dp</dimen> diff --git a/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values-land/config.xml b/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values-land/config.xml deleted file mode 100644 index bd52901cef95..000000000000 --- a/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values-land/config.xml +++ /dev/null @@ -1,22 +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 - --> - -<resources> - <!-- Can't link to other dimensions here, but this should be status_bar_height_landscape --> - <dimen name="quick_qs_offset_height">28dp</dimen> - <!-- Total height of QQS in landscape; quick_qs_offset_height + 128 --> - <dimen name="quick_qs_total_height">156dp</dimen> -</resources>
\ No newline at end of file diff --git a/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values/config.xml b/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values/config.xml index 5fb8b9e241b8..78cc7e04c7a0 100644 --- a/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values/config.xml +++ b/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values/config.xml @@ -47,14 +47,6 @@ --> <bool name="config_fillMainBuiltInDisplayCutout">true</bool> - <!-- Height of the status bar --> - <dimen name="status_bar_height_portrait">48dp</dimen> - <dimen name="status_bar_height_landscape">28dp</dimen> - <!-- Height of area above QQS where battery/time go (equal to status bar height if > 48dp) --> - <dimen name="quick_qs_offset_height">48dp</dimen> - <!-- Total height of QQS (quick_qs_offset_height + 128) --> - <dimen name="quick_qs_total_height">176dp</dimen> - </resources> diff --git a/packages/overlays/NoCutoutOverlay/res/values/config.xml b/packages/overlays/NoCutoutOverlay/res/values/config.xml index 91576998cc54..84b91b85350d 100644 --- a/packages/overlays/NoCutoutOverlay/res/values/config.xml +++ b/packages/overlays/NoCutoutOverlay/res/values/config.xml @@ -25,12 +25,4 @@ by shrinking the display such that it does not overlap the cutout area. --> <bool name="config_maskMainBuiltInDisplayCutout">true</bool> - <!-- Height of the status bar --> - <dimen name="status_bar_height_portrait">28dp</dimen> - <dimen name="status_bar_height_landscape">28dp</dimen> - - <!-- Height of area above QQS where battery/time go (equal to status bar height if > 48dp) --> - <dimen name="quick_qs_offset_height">48dp</dimen> - <!-- Total height of QQS (quick_qs_offset_height + 128) --> - <dimen name="quick_qs_total_height">176dp</dimen> </resources> diff --git a/packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java b/packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java index 46bda06d0e04..27d4ea71dfc0 100644 --- a/packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java +++ b/packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java @@ -21,6 +21,7 @@ import android.os.Binder; import android.os.IBinder; import android.os.Process; import android.os.RemoteException; +import android.os.UserManager; import android.util.Log; import android.webkit.PacProcessor; @@ -33,16 +34,44 @@ import java.net.URL; public class PacService extends Service { private static final String TAG = "PacService"; - private Object mLock = new Object(); + private final Object mLock = new Object(); + // Webkit PacProcessor cannot be instantiated before the user is unlocked, so this field is + // initialized lazily. @GuardedBy("mLock") - private final PacProcessor mPacProcessor = PacProcessor.getInstance(); + private PacProcessor mPacProcessor; + + // Stores PAC script when setPacFile is called before mPacProcessor is available. In case the + // script was already fed to the PacProcessor, it should be null. + @GuardedBy("mLock") + private String mPendingScript; private ProxyServiceStub mStub = new ProxyServiceStub(); @Override public void onCreate() { super.onCreate(); + + synchronized (mLock) { + checkPacProcessorLocked(); + } + } + + /** + * Initializes PacProcessor if it hasn't been initialized yet and if the system user is + * unlocked, e.g. after the user has entered their PIN after a reboot. + * Returns whether PacProcessor is available. + */ + private boolean checkPacProcessorLocked() { + if (mPacProcessor != null) { + return true; + } + UserManager um = getSystemService(UserManager.class); + if (um.isUserUnlocked()) { + mPacProcessor = PacProcessor.getInstance(); + return true; + } + return false; } @Override @@ -74,7 +103,20 @@ public class PacService extends Service { } synchronized (mLock) { - return mPacProcessor.findProxyForUrl(url); + if (checkPacProcessorLocked()) { + // Apply pending script in case it was set before processor was ready. + if (mPendingScript != null) { + if (!mPacProcessor.setProxyScript(mPendingScript)) { + Log.e(TAG, "Unable to parse proxy script."); + } + mPendingScript = null; + } + return mPacProcessor.findProxyForUrl(url); + } else { + Log.e(TAG, "PacProcessor isn't ready during early boot," + + " request will be direct"); + return null; + } } } catch (MalformedURLException e) { throw new IllegalArgumentException("Invalid URL was passed"); @@ -88,8 +130,13 @@ public class PacService extends Service { throw new SecurityException(); } synchronized (mLock) { - if (!mPacProcessor.setProxyScript(script)) { - Log.e(TAG, "Unable to parse proxy script."); + if (checkPacProcessorLocked()) { + if (!mPacProcessor.setProxyScript(script)) { + Log.e(TAG, "Unable to parse proxy script."); + } + } else { + Log.d(TAG, "PAC processor isn't ready, saving script for later."); + mPendingScript = script; } } } diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java index e9aa3be8b403..cf4c8a356662 100644 --- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java +++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java @@ -114,6 +114,9 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync { private int mScreenState; @GuardedBy("this") + private int[] mPerDisplayScreenStates = null; + + @GuardedBy("this") private boolean mUseLatestStates = true; @GuardedBy("this") @@ -291,8 +294,8 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync { } @Override - public Future<?> scheduleSyncDueToScreenStateChange( - int flags, boolean onBattery, boolean onBatteryScreenOff, int screenState) { + public Future<?> scheduleSyncDueToScreenStateChange(int flags, boolean onBattery, + boolean onBatteryScreenOff, int screenState, int[] perDisplayScreenStates) { synchronized (BatteryExternalStatsWorker.this) { if (mCurrentFuture == null || (mUpdateFlags & UPDATE_CPU) == 0) { mOnBattery = onBattery; @@ -301,6 +304,7 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync { } // always update screen state mScreenState = screenState; + mPerDisplayScreenStates = perDisplayScreenStates; return scheduleSyncLocked("screen-state", flags); } } @@ -432,6 +436,7 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync { final boolean onBattery; final boolean onBatteryScreenOff; final int screenState; + final int[] displayScreenStates; final boolean useLatestStates; synchronized (BatteryExternalStatsWorker.this) { updateFlags = mUpdateFlags; @@ -440,6 +445,7 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync { onBattery = mOnBattery; onBatteryScreenOff = mOnBatteryScreenOff; screenState = mScreenState; + displayScreenStates = mPerDisplayScreenStates; useLatestStates = mUseLatestStates; mUpdateFlags = 0; mCurrentReason = null; @@ -461,7 +467,8 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync { } try { updateExternalStatsLocked(reason, updateFlags, onBattery, - onBatteryScreenOff, screenState, useLatestStates); + onBatteryScreenOff, screenState, displayScreenStates, + useLatestStates); } finally { if (DEBUG) { Slog.d(TAG, "end updateExternalStatsSync"); @@ -506,7 +513,8 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync { @GuardedBy("mWorkerLock") private void updateExternalStatsLocked(final String reason, int updateFlags, boolean onBattery, - boolean onBatteryScreenOff, int screenState, boolean useLatestStates) { + boolean onBatteryScreenOff, int screenState, int[] displayScreenStates, + boolean useLatestStates) { // We will request data from external processes asynchronously, and wait on a timeout. SynchronousResultReceiver wifiReceiver = null; SynchronousResultReceiver bluetoothReceiver = null; @@ -661,11 +669,10 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync { if (measuredEnergyDeltas != null) { final long[] displayChargeUC = measuredEnergyDeltas.displayChargeUC; if (displayChargeUC != null && displayChargeUC.length > 0) { - // TODO (b/194107383): pass all display ordinals to mStats. - final long primaryDisplayChargeUC = displayChargeUC[0]; - // If updating, pass in what BatteryExternalStatsWorker thinks screenState is. - mStats.updateDisplayMeasuredEnergyStatsLocked(primaryDisplayChargeUC, - screenState, elapsedRealtime); + // If updating, pass in what BatteryExternalStatsWorker thinks + // displayScreenStates is. + mStats.updateDisplayMeasuredEnergyStatsLocked(displayChargeUC, + displayScreenStates, elapsedRealtime); } final long gnssChargeUC = measuredEnergyDeltas.gnssChargeUC; diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java index ae14ca7b66bd..8d10d562520a 100644 --- a/services/core/java/com/android/server/am/BatteryStatsService.java +++ b/services/core/java/com/android/server/am/BatteryStatsService.java @@ -1215,7 +1215,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub mHandler.post(() -> { if (DBG) Slog.d(TAG, "begin noteScreenState"); synchronized (mStats) { - mStats.noteScreenStateLocked(state, elapsedRealtime, uptime, currentTime); + mStats.noteScreenStateLocked(0, state, elapsedRealtime, uptime, currentTime); } if (DBG) Slog.d(TAG, "end noteScreenState"); }); @@ -1230,7 +1230,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub final long uptime = SystemClock.uptimeMillis(); mHandler.post(() -> { synchronized (mStats) { - mStats.noteScreenBrightnessLocked(brightness, elapsedRealtime, uptime); + mStats.noteScreenBrightnessLocked(0, brightness, elapsedRealtime, uptime); } }); } diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java index 503b3a93b31f..94bf62f8b9b7 100644 --- a/services/core/java/com/android/server/am/BroadcastQueue.java +++ b/services/core/java/com/android/server/am/BroadcastQueue.java @@ -1568,17 +1568,23 @@ public final class BroadcastQueue { perm = PackageManager.PERMISSION_DENIED; } - if (perm == PackageManager.PERMISSION_GRANTED) { - skip = true; - break; - } - int appOp = AppOpsManager.permissionToOpCode(excludedPermission); if (appOp != AppOpsManager.OP_NONE) { - if (mService.getAppOpsManager().checkOpNoThrow(appOp, + // When there is an app op associated with the permission, + // skip when both the permission and the app op are + // granted. + if ((perm == PackageManager.PERMISSION_GRANTED) && ( + mService.getAppOpsManager().checkOpNoThrow(appOp, info.activityInfo.applicationInfo.uid, info.activityInfo.packageName) - == AppOpsManager.MODE_ALLOWED) { + == AppOpsManager.MODE_ALLOWED)) { + skip = true; + break; + } + } else { + // When there is no app op associated with the permission, + // skip when permission is granted. + if (perm == PackageManager.PERMISSION_GRANTED) { skip = true; break; } diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java index 85d6d7fb2f6a..031f6eeeca5f 100644 --- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java @@ -360,6 +360,43 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T> } } + /** + * Only call this method on interfaces where lockout does not come from onError, I.E. the + * old HIDL implementation. + */ + protected void onLockoutTimed(long durationMillis) { + final ClientMonitorCallbackConverter listener = getListener(); + final CoexCoordinator coordinator = CoexCoordinator.getInstance(); + coordinator.onAuthenticationError(this, BiometricConstants.BIOMETRIC_ERROR_LOCKOUT, + new CoexCoordinator.ErrorCallback() { + @Override + public void sendHapticFeedback() { + if (listener != null && mShouldVibrate) { + vibrateError(); + } + } + }); + } + + /** + * Only call this method on interfaces where lockout does not come from onError, I.E. the + * old HIDL implementation. + */ + protected void onLockoutPermanent() { + final ClientMonitorCallbackConverter listener = getListener(); + final CoexCoordinator coordinator = CoexCoordinator.getInstance(); + coordinator.onAuthenticationError(this, + BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT, + new CoexCoordinator.ErrorCallback() { + @Override + public void sendHapticFeedback() { + if (listener != null && mShouldVibrate) { + vibrateError(); + } + } + }); + } + private void sendCancelOnly(@Nullable ClientMonitorCallbackConverter listener) { if (listener == null) { Slog.e(TAG, "Unable to sendAuthenticationCanceled, listener null"); diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java index cbceba6cc959..97d791b7e1c9 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java @@ -225,6 +225,7 @@ class FaceAuthenticationClient extends AuthenticationClient<ISession> implements @Override public void onLockoutTimed(long durationMillis) { + super.onLockoutTimed(durationMillis); mLockoutCache.setLockoutModeForUser(getTargetUserId(), LockoutTracker.LOCKOUT_TIMED); // Lockout metrics are logged as an error code. final int error = BiometricFaceConstants.FACE_ERROR_LOCKOUT; @@ -239,6 +240,7 @@ class FaceAuthenticationClient extends AuthenticationClient<ISession> implements @Override public void onLockoutPermanent() { + super.onLockoutPermanent(); mLockoutCache.setLockoutModeForUser(getTargetUserId(), LockoutTracker.LOCKOUT_PERMANENT); // Lockout metrics are logged as an error code. final int error = BiometricFaceConstants.FACE_ERROR_LOCKOUT_PERMANENT; diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java index 42b676f0d816..9d2cff9901e2 100644 --- a/services/core/java/com/android/server/camera/CameraServiceProxy.java +++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java @@ -15,6 +15,7 @@ */ package com.android.server.camera; +import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; import static android.os.Build.VERSION_CODES.M; import android.annotation.IntDef; @@ -39,7 +40,9 @@ import android.hardware.CameraSessionStats; import android.hardware.CameraStreamStats; import android.hardware.ICameraService; import android.hardware.ICameraServiceProxy; +import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CameraMetadata; +import android.hardware.camera2.CaptureRequest; import android.hardware.devicestate.DeviceStateManager; import android.hardware.devicestate.DeviceStateManager.FoldStateListener; import android.hardware.display.DisplayManager; @@ -346,13 +349,13 @@ public class CameraServiceProxy extends SystemService private final TaskStateHandler mTaskStackListener = new TaskStateHandler(); - private final class TaskInfo { - private int frontTaskId; - private boolean isResizeable; - private boolean isFixedOrientationLandscape; - private boolean isFixedOrientationPortrait; - private int displayId; - private int userId; + public static final class TaskInfo { + public int frontTaskId; + public boolean isResizeable; + public boolean isFixedOrientationLandscape; + public boolean isFixedOrientationPortrait; + public int displayId; + public int userId; } private final class TaskStateHandler extends TaskStackListener { @@ -367,7 +370,8 @@ public class CameraServiceProxy extends SystemService synchronized (mMapLock) { TaskInfo info = new TaskInfo(); info.frontTaskId = taskInfo.taskId; - info.isResizeable = taskInfo.isResizeable; + info.isResizeable = + (taskInfo.topActivityInfo.resizeMode != RESIZE_MODE_UNRESIZEABLE); info.displayId = taskInfo.displayId; info.userId = taskInfo.userId; info.isFixedOrientationLandscape = ActivityInfo.isFixedOrientationLandscape( @@ -427,97 +431,108 @@ public class CameraServiceProxy extends SystemService } }; - private final ICameraServiceProxy.Stub mCameraServiceProxy = new ICameraServiceProxy.Stub() { - private boolean isMOrBelow(Context ctx, String packageName) { - try { - return ctx.getPackageManager().getPackageInfo( - packageName, 0).applicationInfo.targetSdkVersion <= M; - } catch (PackageManager.NameNotFoundException e) { - Slog.e(TAG,"Package name not found!"); - } - return false; + private static boolean isMOrBelow(Context ctx, String packageName) { + try { + return ctx.getPackageManager().getPackageInfo( + packageName, 0).applicationInfo.targetSdkVersion <= M; + } catch (PackageManager.NameNotFoundException e) { + Slog.e(TAG,"Package name not found!"); } + return false; + } - /** - * Gets whether crop-rotate-scale is needed. - */ - private boolean getNeedCropRotateScale(@NonNull Context ctx, @NonNull String packageName, - @Nullable TaskInfo taskInfo, int sensorOrientation, int lensFacing, - boolean ignoreResizableAndSdkCheck) { - if (taskInfo == null) { - return false; - } + /** + * Estimate the app crop-rotate-scale compensation value. + */ + public static int getCropRotateScale(@NonNull Context ctx, @NonNull String packageName, + @Nullable TaskInfo taskInfo, int displayRotation, int lensFacing, + boolean ignoreResizableAndSdkCheck) { + if (taskInfo == null) { + return CaptureRequest.SCALER_ROTATE_AND_CROP_NONE; + } - // External cameras do not need crop-rotate-scale. - if (lensFacing != CameraMetadata.LENS_FACING_FRONT - && lensFacing != CameraMetadata.LENS_FACING_BACK) { - Log.v(TAG, "lensFacing=" + lensFacing + ". Crop-rotate-scale is disabled."); - return false; - } + // External cameras do not need crop-rotate-scale. + if (lensFacing != CameraMetadata.LENS_FACING_FRONT + && lensFacing != CameraMetadata.LENS_FACING_BACK) { + Log.v(TAG, "lensFacing=" + lensFacing + ". Crop-rotate-scale is disabled."); + return CaptureRequest.SCALER_ROTATE_AND_CROP_NONE; + } - // In case the activity behavior is not explicitly overridden, enable the - // crop-rotate-scale workaround if the app targets M (or below) or is not - // resizeable. - if (!ignoreResizableAndSdkCheck && !isMOrBelow(ctx, packageName) && - taskInfo.isResizeable) { - Slog.v(TAG, - "The activity is N or above and claims to support resizeable-activity. " - + "Crop-rotate-scale is disabled."); - return false; - } + // In case the activity behavior is not explicitly overridden, enable the + // crop-rotate-scale workaround if the app targets M (or below) or is not + // resizeable. + if (!ignoreResizableAndSdkCheck && !isMOrBelow(ctx, packageName) && + taskInfo.isResizeable) { + Slog.v(TAG, + "The activity is N or above and claims to support resizeable-activity. " + + "Crop-rotate-scale is disabled."); + return CaptureRequest.SCALER_ROTATE_AND_CROP_NONE; + } - DisplayManager displayManager = ctx.getSystemService(DisplayManager.class); - int rotationDegree = 0; - if (displayManager != null) { - Display display = displayManager.getDisplay(taskInfo.displayId); - if (display == null) { - Slog.e(TAG, "Invalid display id: " + taskInfo.displayId); - return false; - } + if (!taskInfo.isFixedOrientationPortrait && !taskInfo.isFixedOrientationLandscape) { + Log.v(TAG, "Non-fixed orientation activity. Crop-rotate-scale is disabled."); + return CaptureRequest.SCALER_ROTATE_AND_CROP_NONE; + } - int rotation = display.getRotation(); - switch (rotation) { - case Surface.ROTATION_0: - rotationDegree = 0; - break; - case Surface.ROTATION_90: - rotationDegree = 90; - break; - case Surface.ROTATION_180: - rotationDegree = 180; - break; - case Surface.ROTATION_270: - rotationDegree = 270; - break; - } - } else { - Slog.e(TAG, "Failed to query display manager!"); - return false; - } + int rotationDegree; + switch (displayRotation) { + case Surface.ROTATION_0: + rotationDegree = 0; + break; + case Surface.ROTATION_90: + rotationDegree = 90; + break; + case Surface.ROTATION_180: + rotationDegree = 180; + break; + case Surface.ROTATION_270: + rotationDegree = 270; + break; + default: + Log.e(TAG, "Unsupported display rotation: " + displayRotation); + return CaptureRequest.SCALER_ROTATE_AND_CROP_NONE; + } - // Here we only need to know whether the camera is landscape or portrait. Therefore we - // don't need to consider whether it is a front or back camera. The formula works for - // both. - boolean landscapeCamera = ((rotationDegree + sensorOrientation) % 180 == 0); - Slog.v(TAG, - "Display.getRotation()=" + rotationDegree - + " CameraCharacteristics.SENSOR_ORIENTATION=" + sensorOrientation - + " isFixedOrientationPortrait=" + taskInfo.isFixedOrientationPortrait - + " isFixedOrientationLandscape=" + - taskInfo.isFixedOrientationLandscape); - // We need to do crop-rotate-scale when camera is landscape and activity is portrait or - // vice versa. - return (taskInfo.isFixedOrientationPortrait && landscapeCamera) - || (taskInfo.isFixedOrientationLandscape && !landscapeCamera); + Slog.v(TAG, + "Display.getRotation()=" + rotationDegree + + " isFixedOrientationPortrait=" + taskInfo.isFixedOrientationPortrait + + " isFixedOrientationLandscape=" + + taskInfo.isFixedOrientationLandscape); + // We are trying to estimate the necessary rotation compensation for clients that + // don't handle various display orientations. + // The logic that is missing on client side is similar to the reference code + // in {@link android.hardware.Camera#setDisplayOrientation} where "info.orientation" + // is already applied in "CameraUtils::getRotationTransform". + // Care should be taken to reverse the rotation direction depending on the camera + // lens facing. + if (rotationDegree == 0) { + return CaptureRequest.SCALER_ROTATE_AND_CROP_NONE; + } + if (lensFacing == CameraCharacteristics.LENS_FACING_FRONT) { + // Switch direction for front facing cameras + rotationDegree = 360 - rotationDegree; } + switch (rotationDegree) { + case 90: + return CaptureRequest.SCALER_ROTATE_AND_CROP_90; + case 270: + return CaptureRequest.SCALER_ROTATE_AND_CROP_270; + case 180: + return CaptureRequest.SCALER_ROTATE_AND_CROP_180; + case 0: + default: + return CaptureRequest.SCALER_ROTATE_AND_CROP_NONE; + } + } + + private final ICameraServiceProxy.Stub mCameraServiceProxy = new ICameraServiceProxy.Stub() { @Override - public boolean isRotateAndCropOverrideNeeded(String packageName, int sensorOrientation, - int lensFacing) { + public int getRotateAndCropOverride(String packageName, int lensFacing) { if (Binder.getCallingUid() != Process.CAMERASERVER_UID) { Slog.e(TAG, "Calling UID: " + Binder.getCallingUid() + " doesn't match expected " + " camera service UID!"); - return false; + return CaptureRequest.SCALER_ROTATE_AND_CROP_NONE; } // TODO: Modify the sensor orientation in camera characteristics along with any 3A @@ -531,10 +546,10 @@ public class CameraServiceProxy extends SystemService if (CompatChanges.isChangeEnabled(OVERRIDE_CAMERA_ROTATE_AND_CROP, packageName, UserHandle.getUserHandleForUid(taskInfo.userId))) { Slog.v(TAG, "OVERRIDE_CAMERA_ROTATE_AND_CROP enabled!"); - return true; + return CaptureRequest.SCALER_ROTATE_AND_CROP_NONE; } else { Slog.v(TAG, "OVERRIDE_CAMERA_ROTATE_AND_CROP disabled!"); - return false; + return CaptureRequest.SCALER_ROTATE_AND_CROP_NONE; } } boolean ignoreResizableAndSdkCheck = false; @@ -544,7 +559,23 @@ public class CameraServiceProxy extends SystemService Slog.v(TAG, "OVERRIDE_CAMERA_RESIZABLE_AND_SDK_CHECK enabled!"); ignoreResizableAndSdkCheck = true; } - return getNeedCropRotateScale(mContext, packageName, taskInfo, sensorOrientation, + + DisplayManager displayManager = mContext.getSystemService(DisplayManager.class); + int displayRotation; + if (displayManager != null) { + Display display = displayManager.getDisplay(taskInfo.displayId); + if (display == null) { + Slog.e(TAG, "Invalid display id: " + taskInfo.displayId); + return CaptureRequest.SCALER_ROTATE_AND_CROP_NONE; + } + + displayRotation = display.getRotation(); + } else { + Slog.e(TAG, "Failed to query display manager!"); + return CaptureRequest.SCALER_ROTATE_AND_CROP_NONE; + } + + return getCropRotateScale(mContext, packageName, taskInfo, displayRotation, lensFacing, ignoreResizableAndSdkCheck); } diff --git a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java index 091e6c4adf4d..a56a8ea993f0 100644 --- a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java +++ b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java @@ -227,7 +227,7 @@ public class MultipathPolicyTracker { subscriberId = tele.getSubscriberId(); mNetworkTemplate = new NetworkTemplate( NetworkTemplate.MATCH_MOBILE, subscriberId, new String[] { subscriberId }, - null, NetworkStats.METERED_ALL, NetworkStats.ROAMING_ALL, + null, NetworkStats.METERED_YES, NetworkStats.ROAMING_ALL, NetworkStats.DEFAULT_NETWORK_NO, NETWORK_TYPE_ALL, OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT); mUsageCallback = new UsageCallback() { diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index 63d32c8da2b2..768587a6a2b8 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -1052,11 +1052,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } assert(state != Display.STATE_UNKNOWN); - // Initialize things the first time the power state is changed. - if (mustInitialize) { - initialize(state); - } - // Apply the proximity sensor. if (mProximitySensor != null) { if (mPowerRequest.useProximitySensor && state != Display.STATE_OFF) { @@ -1107,6 +1102,11 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call state = Display.STATE_OFF; } + // Initialize things the first time the power state is changed. + if (mustInitialize) { + initialize(state); + } + // Animate the screen state change unless already animating. // The transition may be deferred, so after this point we will use the // actual state instead of the desired one. diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 0e82c2a42f3f..9d6678053533 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -2356,6 +2356,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub if (displayIdToShowIme == INVALID_DISPLAY) { mImeHiddenByDisplayPolicy = true; + hideCurrentInputLocked(mCurFocusedWindow, 0, null, + SoftInputShowHideReason.HIDE_DISPLAY_IME_POLICY_HIDE); return InputBindResult.NO_IME; } mImeHiddenByDisplayPolicy = false; diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java index 9f02c3caa388..9be618cb7add 100644 --- a/services/core/java/com/android/server/media/MediaRouterService.java +++ b/services/core/java/com/android/server/media/MediaRouterService.java @@ -338,6 +338,25 @@ public final class MediaRouterService extends IMediaRouterService.Stub // Binder call @Override + public void setBluetoothA2dpOn(IMediaRouterClient client, boolean on) { + if (client == null) { + throw new IllegalArgumentException("client must not be null"); + } + + final long token = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + mAudioService.setBluetoothA2dpOn(on); + } + } catch (RemoteException ex) { + Slog.w(TAG, "RemoteException while calling setBluetoothA2dpOn. on=" + on); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + // Binder call + @Override public void setDiscoveryRequest(IMediaRouterClient client, int routeTypes, boolean activeScan) { if (client == null) { diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index 84be7f5809e6..20687c6764db 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -4073,7 +4073,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { if (hasRestrictedModeAccess(uid)) { uidBlockedState.allowedReasons |= ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS; } else { - uidBlockedState.allowedReasons &= ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS; + uidBlockedState.allowedReasons &= ~ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS; } uidBlockedState.updateEffectiveBlockedReasons(); if (oldEffectiveBlockedReasons != uidBlockedState.effectiveBlockedReasons) { diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 7ba0f04a435f..2f550c6e9338 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -7076,7 +7076,6 @@ public class NotificationManagerService extends SystemService { r.isUpdate = true; final boolean isInterruptive = isVisuallyInterruptive(old, r); r.setTextChanged(isInterruptive); - r.setInterruptive(isInterruptive); } mNotificationsByKey.put(n.getKey(), r); @@ -9424,7 +9423,7 @@ public class NotificationManagerService extends SystemService { record.getSystemGeneratedSmartActions(), record.getSmartReplies(), record.canBubble(), - record.isInterruptive(), + record.isTextChanged(), record.isConversation(), record.getShortcutInfo(), record.getRankingScore() == 0 diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java index b4ca5118e10f..b6b54fc19011 100644 --- a/services/core/java/com/android/server/notification/NotificationRecord.java +++ b/services/core/java/com/android/server/notification/NotificationRecord.java @@ -1143,6 +1143,10 @@ public final class NotificationRecord { return mIsInterruptive; } + public boolean isTextChanged() { + return mTextChanged; + } + /** Returns the time the notification audibly alerted the user. */ public long getLastAudiblyAlertedMs() { return mLastAudiblyAlertedMs; diff --git a/services/core/java/com/android/server/os/NativeTombstoneManager.java b/services/core/java/com/android/server/os/NativeTombstoneManager.java index ed1f5f567d95..3fc416931a06 100644 --- a/services/core/java/com/android/server/os/NativeTombstoneManager.java +++ b/services/core/java/com/android/server/os/NativeTombstoneManager.java @@ -356,7 +356,7 @@ public final class NativeTombstoneManager { return false; } - if (Math.abs(exitInfo.getTimestamp() - mTimestampMs) > 1000) { + if (Math.abs(exitInfo.getTimestamp() - mTimestampMs) > 5000) { return false; } diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java index 301914615562..7096f6f419b7 100644 --- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java +++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java @@ -913,6 +913,11 @@ final class DefaultPermissionGrantPolicy { } grantPermissionsToSystemPackage(pm, dialerPackage, userId, CONTACTS_PERMISSIONS, SMS_PERMISSIONS, MICROPHONE_PERMISSIONS, CAMERA_PERMISSIONS); + boolean isAndroidAutomotive = + mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0); + if (isAndroidAutomotive) { + grantPermissionsToSystemPackage(pm, dialerPackage, userId, NEARBY_DEVICES_PERMISSIONS); + } } private void grantDefaultPermissionsToDefaultSystemSmsApp(PackageManagerWrapper pm, diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 5b6bf1510bf2..cda7407dc98c 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -404,7 +404,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { private AccessibilityShortcutController mAccessibilityShortcutController; boolean mSafeMode; - private WindowState mKeyguardCandidate = null; // Whether to allow dock apps with METADATA_DOCK_HOME to temporarily take over the Home key. // This is for car dock and this is updated from resource. @@ -1813,18 +1812,22 @@ public class PhoneWindowManager implements WindowManagerPolicy { mWindowManagerInternal.registerAppTransitionListener(new AppTransitionListener() { @Override - public int onAppTransitionStartingLocked(boolean keyguardGoingAway, long duration, - long statusBarAnimationStartTime, long statusBarAnimationDuration) { + public int onAppTransitionStartingLocked(boolean keyguardGoingAway, + boolean keyguardOccluding, long duration, long statusBarAnimationStartTime, + long statusBarAnimationDuration) { // When remote animation is enabled for KEYGUARD_GOING_AWAY transition, SysUI // receives IRemoteAnimationRunner#onAnimationStart to start animation, so we don't // need to call IKeyguardService#keyguardGoingAway here. return handleStartTransitionForKeyguardLw(keyguardGoingAway - && !WindowManagerService.sEnableRemoteKeyguardGoingAwayAnimation, duration); + && !WindowManagerService.sEnableRemoteKeyguardGoingAwayAnimation, + keyguardOccluding, duration); } @Override public void onAppTransitionCancelledLocked(boolean keyguardGoingAway) { - handleStartTransitionForKeyguardLw(keyguardGoingAway, 0 /* duration */); + handleStartTransitionForKeyguardLw( + keyguardGoingAway, false /* keyguardOccludingStarted */, + 0 /* duration */); } }); @@ -3047,26 +3050,28 @@ public class PhoneWindowManager implements WindowManagerPolicy { mPendingKeyguardOccluded = occluded; mKeyguardOccludedChanged = true; } else { - setKeyguardOccludedLw(occluded, false /* force */); + setKeyguardOccludedLw(occluded, false /* force */, + false /* transitionStarted */); } } @Override - public int applyKeyguardOcclusionChange() { + public int applyKeyguardOcclusionChange(boolean transitionStarted) { if (mKeyguardOccludedChanged) { if (DEBUG_KEYGUARD) Slog.d(TAG, "transition/occluded changed occluded=" + mPendingKeyguardOccluded); - mKeyguardOccludedChanged = false; - if (setKeyguardOccludedLw(mPendingKeyguardOccluded, false /* force */)) { + if (setKeyguardOccludedLw(mPendingKeyguardOccluded, false /* force */, + transitionStarted)) { return FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_WALLPAPER; } } return 0; } - private int handleStartTransitionForKeyguardLw(boolean keyguardGoingAway, long duration) { - final int res = applyKeyguardOcclusionChange(); - if (res != 0) return res; + private int handleStartTransitionForKeyguardLw(boolean keyguardGoingAway, + boolean keyguardOccluding, long duration) { + final int redoLayout = applyKeyguardOcclusionChange(keyguardOccluding); + if (redoLayout != 0) return redoLayout; if (keyguardGoingAway) { if (DEBUG_KEYGUARD) Slog.d(TAG, "Starting keyguard exit animation"); startKeyguardExitAnimation(SystemClock.uptimeMillis(), duration); @@ -3264,30 +3269,31 @@ public class PhoneWindowManager implements WindowManagerPolicy { mNavBarVirtualKeyHapticFeedbackEnabled = enabled; } - /** {@inheritDoc} */ - @Override - public void setKeyguardCandidateLw(WindowState win) { - mKeyguardCandidate = win; - setKeyguardOccludedLw(isKeyguardOccluded(), true /* force */); - } - /** * Updates the occluded state of the Keyguard. * * @param isOccluded Whether the Keyguard is occluded by another window. * @param force notify the occluded status to KeyguardService and update flags even though * occlude status doesn't change. + * @param transitionStarted {@code true} if keyguard (un)occluded transition started. * @return Whether the flags have changed and we have to redo the layout. */ - private boolean setKeyguardOccludedLw(boolean isOccluded, boolean force) { + private boolean setKeyguardOccludedLw(boolean isOccluded, boolean force, + boolean transitionStarted) { if (DEBUG_KEYGUARD) Slog.d(TAG, "setKeyguardOccluded occluded=" + isOccluded); + mKeyguardOccludedChanged = false; if (isKeyguardOccluded() == isOccluded && !force) { return false; } final boolean showing = mKeyguardDelegate.isShowing(); final boolean animate = showing && !isOccluded; - mKeyguardDelegate.setOccluded(isOccluded, animate); + // When remote animation is enabled for keyguard (un)occlude transition, KeyguardService + // uses remote animation start as a signal to update its occlusion status ,so we don't need + // to notify here. + final boolean notify = !WindowManagerService.sEnableRemoteKeyguardOccludeAnimation + || !transitionStarted; + mKeyguardDelegate.setOccluded(isOccluded, animate, notify); return showing; } diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java index 78b03b2b88e7..87465a4b2ffe 100644 --- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java +++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java @@ -173,8 +173,11 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { */ void onKeyguardOccludedChangedLw(boolean occluded); - /** Applies a keyguard occlusion change if one happened. */ - int applyKeyguardOcclusionChange(); + /** + * Applies a keyguard occlusion change if one happened. + * @param transitionStarted Whether keyguard (un)occlude transition is starting or not. + */ + int applyKeyguardOcclusionChange(boolean transitionStarted); /** * Interface to the Window Manager state associated with a particular @@ -719,13 +722,6 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { int icon, int logo, int windowFlags, Configuration overrideConfig, int displayId); /** - * Set or clear a window which can behave as the keyguard. - * - * @param win The window which can behave as the keyguard. - */ - void setKeyguardCandidateLw(@Nullable WindowState win); - - /** * Create and return an animation to re-display a window that was force hidden by Keyguard. */ public Animation createHiddenByKeyguardExit(boolean onWallpaper, diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java index cdd36f7e25dd..0080ec6cc989 100644 --- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java +++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java @@ -29,7 +29,6 @@ import com.android.internal.policy.IKeyguardExitCallback; import com.android.internal.policy.IKeyguardService; import com.android.server.UiThread; import com.android.server.policy.WindowManagerPolicy.OnKeyguardExitResult; -import com.android.server.wm.WindowManagerService; import java.io.PrintWriter; @@ -252,13 +251,8 @@ public class KeyguardServiceDelegate { } } - /** - * @deprecated Notify occlude status change via remote animation. - */ - @Deprecated - public void setOccluded(boolean isOccluded, boolean animate) { - if (!WindowManagerService.sEnableRemoteKeyguardOccludeAnimation - && mKeyguardService != null) { + public void setOccluded(boolean isOccluded, boolean animate, boolean notify) { + if (mKeyguardService != null && notify) { if (DEBUG) Log.v(TAG, "setOccluded(" + isOccluded + ") animate=" + animate); mKeyguardService.setOccluded(isOccluded, animate); } diff --git a/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java b/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java index 6366280e1762..7ffff935128f 100644 --- a/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java +++ b/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java @@ -429,15 +429,7 @@ class ConversionUtil { private static @NonNull HidlMemory parcelFileDescriptorToHidlMemory(@Nullable ParcelFileDescriptor data, int dataSize) { if (dataSize > 0) { - // Extract a dup of the underlying FileDescriptor out of data. - FileDescriptor fd = new FileDescriptor(); - try { - ParcelFileDescriptor dup = data.dup(); - fd.setInt$(dup.detachFd()); - return HidlMemoryUtil.fileDescriptorToHidlMemory(fd, dataSize); - } catch (IOException e) { - throw new RuntimeException(e); - } + return HidlMemoryUtil.fileDescriptorToHidlMemory(data.getFileDescriptor(), dataSize); } else { return HidlMemoryUtil.fileDescriptorToHidlMemory(null, 0); } diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java index 106cff17dbef..2be29d4a5ab4 100644 --- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java +++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java @@ -29,6 +29,7 @@ import static android.net.NetworkIdentity.OEM_PAID; import static android.net.NetworkIdentity.OEM_PRIVATE; import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; import static android.net.NetworkStats.METERED_ALL; +import static android.net.NetworkStats.METERED_YES; import static android.net.NetworkStats.ROAMING_ALL; import static android.net.NetworkTemplate.MATCH_ETHERNET; import static android.net.NetworkTemplate.MATCH_MOBILE_WILDCARD; @@ -1348,7 +1349,7 @@ public class StatsPullAtomService extends SystemService { @Nullable private NetworkStats getUidNetworkStatsSnapshotForTransport(int transport) { final NetworkTemplate template = (transport == TRANSPORT_CELLULAR) ? NetworkTemplate.buildTemplateMobileWithRatType( - /*subscriptionId=*/null, NETWORK_TYPE_ALL) + /*subscriptionId=*/null, NETWORK_TYPE_ALL, METERED_YES) : NetworkTemplate.buildTemplateWifiWildcard(); return getUidNetworkStatsSnapshotForTemplate(template, /*includeTags=*/false); } @@ -1388,7 +1389,8 @@ public class StatsPullAtomService extends SystemService { final List<NetworkStatsExt> ret = new ArrayList<>(); for (final int ratType : getAllCollapsedRatTypes()) { final NetworkTemplate template = - buildTemplateMobileWithRatType(subInfo.subscriberId, ratType); + buildTemplateMobileWithRatType(subInfo.subscriberId, ratType, + METERED_YES); final NetworkStats stats = getUidNetworkStatsSnapshotForTemplate(template, /*includeTags=*/false); if (stats != null) { diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 8ef973dbcfae..b8e350b753d2 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -154,6 +154,7 @@ import static com.android.server.wm.ActivityRecordProto.IS_ANIMATING; import static com.android.server.wm.ActivityRecordProto.IS_WAITING_FOR_TRANSITION_START; import static com.android.server.wm.ActivityRecordProto.LAST_ALL_DRAWN; import static com.android.server.wm.ActivityRecordProto.LAST_SURFACE_SHOWING; +import static com.android.server.wm.ActivityRecordProto.MIN_ASPECT_RATIO; import static com.android.server.wm.ActivityRecordProto.NAME; import static com.android.server.wm.ActivityRecordProto.NUM_DRAWN_WINDOWS; import static com.android.server.wm.ActivityRecordProto.NUM_INTERESTING_WINDOWS; @@ -1145,10 +1146,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (info.getMaxAspectRatio() != 0) { pw.println(prefix + "maxAspectRatio=" + info.getMaxAspectRatio()); } - if (info.getMinAspectRatio() != 0) { - pw.println(prefix + "minAspectRatio=" + info.getMinAspectRatio()); + final float minAspectRatio = getMinAspectRatio(); + if (minAspectRatio != 0) { + pw.println(prefix + "minAspectRatio=" + minAspectRatio); } - if (info.getMinAspectRatio() != info.getManifestMinAspectRatio()) { + if (minAspectRatio != info.getManifestMinAspectRatio()) { // Log the fact that we've overridden the min aspect ratio from the manifest pw.println(prefix + "manifestMinAspectRatio=" + info.getManifestMinAspectRatio()); @@ -3642,6 +3644,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (mPendingRelaunchCount > 0) { mPendingRelaunchCount--; + if (mPendingRelaunchCount == 0 && !isClientVisible()) { + // Don't count if the client won't report drawn. + mRelaunchStartTime = 0; + } } else { // Update keyguard flags upon finishing relaunch. checkKeyguardFlagsChanged(); @@ -4694,6 +4700,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (app != null) { mTaskSupervisor.onProcessActivityStateChanged(app, false /* forceBatch */); } + logAppCompatState(); } /** @@ -4721,7 +4728,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A ActivityTaskManagerService.LAYOUT_REASON_VISIBILITY_CHANGED); mTaskSupervisor.getActivityMetricsLogger().notifyVisibilityChanged(this); mTaskSupervisor.mAppVisibilitiesChangedSinceLastPause = true; - logAppCompatState(); } @VisibleForTesting @@ -4961,7 +4967,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A */ private void postApplyAnimation(boolean visible, boolean fromTransition) { final boolean usingShellTransitions = mTransitionController.isShellTransitionsEnabled(); - final boolean delayed = isAnimating(TRANSITION | PARENTS | CHILDREN, + final boolean delayed = isAnimating(PARENTS | CHILDREN, ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_WINDOW_ANIMATION | ANIMATION_TYPE_RECENTS); if (!delayed && !usingShellTransitions) { @@ -7272,7 +7278,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return false; } } - return !isResizeable() && (info.isFixedOrientation() || info.hasFixedAspectRatio()) + return !isResizeable() && (info.isFixedOrientation() || hasFixedAspectRatio()) // The configuration of non-standard type should be enforced by system. // {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD} is set when this activity is // added to a task, but this function is called when resolving the launch params, at @@ -7511,7 +7517,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A /** * Adjusts horizontal position of resolved bounds if they doesn't fill the parent using gravity * requested in the config or via an ADB command. For more context see {@link - * WindowManagerService#getLetterboxHorizontalPositionMultiplier}. + * LetterboxUiController#getHorizontalPositionMultiplier(Configuration)}. */ private void updateResolvedBoundsHorizontalPosition(Configuration newParentConfiguration) { final Configuration resolvedConfig = getResolvedOverrideConfiguration(); @@ -7848,7 +7854,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // Below figure is an example that puts an activity which was launched in a larger container // into a smaller container. // The outermost rectangle is the real display bounds. - // "@" is the container app bounds (parent bounds or fixed orientation bouds) + // "@" is the container app bounds (parent bounds or fixed orientation bounds) // "#" is the {@code resolvedBounds} that applies to application. // "*" is the {@code mSizeCompatBounds} that used to show on screen if scaled. // ------------------------------ @@ -7891,12 +7897,15 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A mSizeCompatBounds = null; } - // Align to top of parent (bounds) - this is a UX choice and exclude the horizontal decor - // if needed. Horizontal position is adjusted in updateResolvedBoundsHorizontalPosition. + // Vertically center within parent (bounds) - this is a UX choice and exclude the horizontal + // decor if needed. Horizontal position is adjusted in + // updateResolvedBoundsHorizontalPosition. // Above coordinates are in "@" space, now place "*" and "#" to screen space. final boolean fillContainer = resolvedBounds.equals(containingBounds); final int screenPosX = fillContainer ? containerBounds.left : containerAppBounds.left; - final int screenPosY = containerBounds.top; + final int screenPosY = mSizeCompatBounds == null + ? (containerBounds.height() - resolvedBounds.height()) / 2 + : (containerBounds.height() - mSizeCompatBounds.height()) / 2; if (screenPosX != 0 || screenPosY != 0) { if (mSizeCompatBounds != null) { mSizeCompatBounds.offset(screenPosX, screenPosY); @@ -7940,13 +7949,14 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return false; } } - if (info.getMinAspectRatio() > 0) { + final float minAspectRatio = getMinAspectRatio(); + if (minAspectRatio > 0) { // The activity should have at least the min aspect ratio, so this checks if the // container still has available space to provide larger aspect ratio. final float containerAspectRatio = (0.5f + Math.max(containerAppWidth, containerAppHeight)) / Math.min(containerAppWidth, containerAppHeight); - if (containerAspectRatio <= info.getMinAspectRatio()) { + if (containerAspectRatio <= minAspectRatio) { // The long side has reached the parent. return false; } @@ -8157,8 +8167,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A Rect containingBounds, float desiredAspectRatio, boolean fixedOrientationLetterboxed) { final float maxAspectRatio = info.getMaxAspectRatio(); final Task rootTask = getRootTask(); - final float minAspectRatio = info.getMinAspectRatio(); - + final float minAspectRatio = getMinAspectRatio(); if (task == null || rootTask == null || (inMultiWindowMode() && !shouldCreateCompatDisplayInsets() && !fixedOrientationLetterboxed) @@ -8262,6 +8271,20 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } /** + * Returns the min aspect ratio of this activity. + */ + private float getMinAspectRatio() { + return info.getMinAspectRatio(getRequestedOrientation()); + } + + /** + * Returns true if the activity has maximum or minimum aspect ratio. + */ + private boolean hasFixedAspectRatio() { + return info.hasFixedAspectRatio(getRequestedOrientation()); + } + + /** * Returns the aspect ratio of the given {@code rect}. */ static float computeAspectRatio(Rect rect) { @@ -8990,6 +9013,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } proto.write(PIP_AUTO_ENTER_ENABLED, pictureInPictureArgs.isAutoEnterEnabled()); proto.write(IN_SIZE_COMPAT_MODE, inSizeCompatMode()); + proto.write(MIN_ASPECT_RATIO, getMinAspectRatio()); } @Override diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 47467abf459b..dc5126dbf916 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -1565,7 +1565,7 @@ class ActivityStarter { // transition based on a sub-action. // Only do the create here (and defer requestStart) since startActivityInner might abort. final TransitionController transitionController = r.mTransitionController; - final Transition newTransition = (!transitionController.isCollecting() + Transition newTransition = (!transitionController.isCollecting() && transitionController.getTransitionPlayer() != null) ? transitionController.createTransition(TRANSIT_OPEN) : null; RemoteTransition remoteTransition = r.takeRemoteTransition(); @@ -1620,6 +1620,10 @@ class ActivityStarter { // The activity is started new rather than just brought forward, so record // it as an existence change. transitionController.collectExistenceChange(r); + } else if (result == START_DELIVERED_TO_TOP && newTransition != null) { + // We just delivered to top, so there isn't an actual transition here + newTransition.abort(); + newTransition = null; } if (isTransient) { // `r` isn't guaranteed to be the actual relevant activity, so we must wait @@ -2737,9 +2741,11 @@ class ActivityStarter { // If it exist, we need to reparent target root task from TDA to launch root task. final TaskDisplayArea tda = mTargetRootTask.getDisplayArea(); final Task launchRootTask = tda.getLaunchRootTask(mTargetRootTask.getWindowingMode(), - mTargetRootTask.getActivityType(), null /** options */, null /** sourceTask */, - 0 /** launchFlags */); - if (launchRootTask != null && launchRootTask != mTargetRootTask) { + mTargetRootTask.getActivityType(), null /** options */, + mSourceRootTask, 0 /** launchFlags */); + // If target root task is created by organizer, let organizer handle reparent itself. + if (!mTargetRootTask.mCreatedByOrganizer && launchRootTask != null + && launchRootTask != mTargetRootTask) { mTargetRootTask.reparent(launchRootTask, POSITION_TOP); mTargetRootTask = launchRootTask; } diff --git a/services/core/java/com/android/server/wm/AnimationAdapter.java b/services/core/java/com/android/server/wm/AnimationAdapter.java index 529c4f608743..5899a4e89ca7 100644 --- a/services/core/java/com/android/server/wm/AnimationAdapter.java +++ b/services/core/java/com/android/server/wm/AnimationAdapter.java @@ -16,6 +16,7 @@ package com.android.server.wm; +import android.annotation.NonNull; import android.util.proto.ProtoOutputStream; import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; @@ -52,7 +53,7 @@ interface AnimationAdapter { * @param finishCallback The callback to be invoked when the animation has finished. */ void startAnimation(SurfaceControl animationLeash, Transaction t, @AnimationType int type, - OnAnimationFinishedCallback finishCallback); + @NonNull OnAnimationFinishedCallback finishCallback); /** * Called when the animation that was started with {@link #startAnimation} was cancelled by the diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java index e21a00b4aec6..bd08d01768e3 100644 --- a/services/core/java/com/android/server/wm/AppTransition.java +++ b/services/core/java/com/android/server/wm/AppTransition.java @@ -443,6 +443,7 @@ public class AppTransition implements Dump { int redoLayout = notifyAppTransitionStartingLocked( AppTransition.isKeyguardGoingAwayTransitOld(transit), + AppTransition.isKeyguardOccludeTransitOld(transit), topOpeningAnim != null ? topOpeningAnim.getDurationHint() : 0, topOpeningAnim != null ? topOpeningAnim.getStatusBarTransitionsStartTime() @@ -557,12 +558,14 @@ public class AppTransition implements Dump { } } - private int notifyAppTransitionStartingLocked(boolean keyguardGoingAway, long duration, - long statusBarAnimationStartTime, long statusBarAnimationDuration) { + private int notifyAppTransitionStartingLocked(boolean keyguardGoingAway, + boolean keyguardOcclude, long duration, long statusBarAnimationStartTime, + long statusBarAnimationDuration) { int redoLayout = 0; for (int i = 0; i < mListeners.size(); i++) { redoLayout |= mListeners.get(i).onAppTransitionStartingLocked(keyguardGoingAway, - duration, statusBarAnimationStartTime, statusBarAnimationDuration); + keyguardOcclude, duration, statusBarAnimationStartTime, + statusBarAnimationDuration); } return redoLayout; } diff --git a/services/core/java/com/android/server/wm/BLASTSyncEngine.java b/services/core/java/com/android/server/wm/BLASTSyncEngine.java index 4355b3855bb7..2a8ac39ead8d 100644 --- a/services/core/java/com/android/server/wm/BLASTSyncEngine.java +++ b/services/core/java/com/android/server/wm/BLASTSyncEngine.java @@ -20,9 +20,11 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SYNC_ENGINE; import android.annotation.NonNull; import android.util.ArraySet; +import android.util.Slog; import android.util.SparseArray; import android.view.SurfaceControl; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.protolog.common.ProtoLog; /** @@ -65,6 +67,7 @@ class BLASTSyncEngine { class SyncGroup { final int mSyncId; final TransactionReadyListener mListener; + final Runnable mOnTimeout; boolean mReady = false; final ArraySet<WindowContainer> mRootMembers = new ArraySet<>(); private SurfaceControl.Transaction mOrphanTransaction = null; @@ -72,6 +75,12 @@ class BLASTSyncEngine { private SyncGroup(TransactionReadyListener listener, int id) { mSyncId = id; mListener = listener; + mOnTimeout = () -> { + Slog.w(TAG, "Sync group " + mSyncId + " timeout"); + synchronized (mWm.mGlobalLock) { + onTimeout(); + } + }; } /** @@ -114,6 +123,7 @@ class BLASTSyncEngine { } mListener.onTransactionReady(mSyncId, merged); mActiveSyncs.remove(mSyncId); + mWm.mH.removeCallbacks(mOnTimeout); } private void setReady(boolean ready) { @@ -136,6 +146,17 @@ class BLASTSyncEngine { void onCancelSync(WindowContainer wc) { mRootMembers.remove(wc); } + + private void onTimeout() { + if (!mActiveSyncs.contains(mSyncId)) return; + for (int i = mRootMembers.size() - 1; i >= 0; --i) { + final WindowContainer<?> wc = mRootMembers.valueAt(i); + if (!wc.isSyncFinished()) { + Slog.i(TAG, "Unfinished container: " + wc); + } + } + finishNow(); + } } private final WindowManagerService mWm; @@ -147,13 +168,23 @@ class BLASTSyncEngine { } int startSyncSet(TransactionReadyListener listener) { + return startSyncSet(listener, WindowState.BLAST_TIMEOUT_DURATION); + } + + int startSyncSet(TransactionReadyListener listener, long timeoutMs) { final int id = mNextSyncId++; final SyncGroup s = new SyncGroup(listener, id); mActiveSyncs.put(id, s); ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d: Started for listener: %s", id, listener); + scheduleTimeout(s, timeoutMs); return id; } + @VisibleForTesting + void scheduleTimeout(SyncGroup s, long timeoutMs) { + mWm.mH.postDelayed(s.mOnTimeout, timeoutMs); + } + void addToSyncSet(int id, WindowContainer wc) { mActiveSyncs.get(id).addToSync(wc); } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index aaca58ef4ac0..0de3fa3ad968 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -93,6 +93,7 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SCREEN_ON; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WALLPAPER; import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_TRANSACTIONS; +import static com.android.internal.util.LatencyTracker.ACTION_ROTATE_SCREEN; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT; @@ -297,7 +298,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp * The direct child layer of the display to put all non-overlay windows. This is also used for * screen rotation animation so that there is a parent layer to put the animation leash. */ - private final SurfaceControl mWindowingLayer; + private SurfaceControl mWindowingLayer; /** * The window token of the layer of the hierarchy to mirror, or null if this DisplayContent @@ -329,7 +330,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp private final ImeContainer mImeWindowsContainer = new ImeContainer(mWmService); @VisibleForTesting - final DisplayAreaPolicy mDisplayAreaPolicy; + DisplayAreaPolicy mDisplayAreaPolicy; private WindowState mTmpWindow; private boolean mUpdateImeTarget; @@ -1104,52 +1105,91 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp mDividerControllerLocked = new DockedTaskDividerController(this); mPinnedTaskController = new PinnedTaskController(mWmService, this); + final Transaction pendingTransaction = getPendingTransaction(); + configureSurfaces(pendingTransaction); + pendingTransaction.apply(); + + // Sets the display content for the children. + onDisplayChanged(this); + updateDisplayAreaOrganizers(); + + mInputMonitor = new InputMonitor(mWmService, this); + mInsetsPolicy = new InsetsPolicy(mInsetsStateController, this); + + if (DEBUG_DISPLAY) Slog.v(TAG_WM, "Creating display=" + display); + + mWmService.mDisplayWindowSettings.applySettingsToDisplayLocked(this); + } + + @Override + void migrateToNewSurfaceControl(Transaction t) { + t.remove(mSurfaceControl); + + mLastSurfacePosition.set(0, 0); + + configureSurfaces(t); + + for (int i = 0; i < mChildren.size(); i++) { + SurfaceControl sc = mChildren.get(i).getSurfaceControl(); + if (sc != null) { + t.reparent(sc, mSurfaceControl); + } + } + + scheduleAnimation(); + } + + /** + * Configures the surfaces hierarchy for DisplayContent + * This method always recreates the main surface control but reparents the children + * if they are already created. + * @param transaction as part of which to perform the configuration + */ + private void configureSurfaces(Transaction transaction) { final SurfaceControl.Builder b = mWmService.makeSurfaceBuilder(mSession) .setOpaque(true) .setContainerLayer() .setCallsite("DisplayContent"); - mSurfaceControl = b.setName("Root").setContainerLayer().build(); + mSurfaceControl = b.setName(getName()).setContainerLayer().build(); - // Setup the policy and build the display area hierarchy. - mDisplayAreaPolicy = mWmService.getDisplayAreaPolicyProvider().instantiate( - mWmService, this /* content */, this /* root */, mImeWindowsContainer); + if (mDisplayAreaPolicy == null) { + // Setup the policy and build the display area hierarchy. + // Build the hierarchy only after creating the surface so it is reparented correctly + mDisplayAreaPolicy = mWmService.getDisplayAreaPolicyProvider().instantiate( + mWmService, this /* content */, this /* root */, + mImeWindowsContainer); + } final List<DisplayArea<? extends WindowContainer>> areas = mDisplayAreaPolicy.getDisplayAreas(FEATURE_WINDOWED_MAGNIFICATION); final DisplayArea<?> area = areas.size() == 1 ? areas.get(0) : null; + if (area != null && area.getParent() == this) { // The windowed magnification area should contain all non-overlay windows, so just use // it as the windowing layer. mWindowingLayer = area.mSurfaceControl; + transaction.reparent(mWindowingLayer, mSurfaceControl); } else { // Need an additional layer for screen level animation, so move the layer containing // the windows to the new root. mWindowingLayer = mSurfaceControl; mSurfaceControl = b.setName("RootWrapper").build(); - getPendingTransaction().reparent(mWindowingLayer, mSurfaceControl) + transaction.reparent(mWindowingLayer, mSurfaceControl) .show(mWindowingLayer); } - mOverlayLayer = b.setName("Display Overlays").setParent(mSurfaceControl).build(); + if (mOverlayLayer == null) { + mOverlayLayer = b.setName("Display Overlays").setParent(mSurfaceControl).build(); + } else { + transaction.reparent(mOverlayLayer, mSurfaceControl); + } - getPendingTransaction() + transaction .setLayer(mSurfaceControl, 0) .setLayerStack(mSurfaceControl, mDisplayId) .show(mSurfaceControl) .setLayer(mOverlayLayer, Integer.MAX_VALUE) .show(mOverlayLayer); - getPendingTransaction().apply(); - - // Sets the display content for the children. - onDisplayChanged(this); - updateDisplayAreaOrganizers(); - - mInputMonitor = new InputMonitor(mWmService, this); - mInsetsPolicy = new InsetsPolicy(mInsetsStateController, this); - - if (DEBUG_DISPLAY) Slog.v(TAG_WM, "Creating display=" + display); - - mWmService.mDisplayWindowSettings.applySettingsToDisplayLocked(this); } boolean isReady() { @@ -3191,6 +3231,11 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } final Transition t = controller.requestTransitionIfNeeded(TRANSIT_CHANGE, this); if (t != null) { + if (getRotation() != getWindowConfiguration().getRotation()) { + mWmService.mLatencyTracker.onActionStart(ACTION_ROTATE_SCREEN); + controller.mTransitionMetricsReporter.associate(t, + startTime -> mWmService.mLatencyTracker.onActionEnd(ACTION_ROTATE_SCREEN)); + } t.setKnownConfigChanges(this, changes); } } @@ -3404,7 +3449,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp @Override public String toString() { - return "Display " + mDisplayId + " info=" + mDisplayInfo + " rootTasks=" + mChildren; + return "Display{#" + mDisplayId + " state=" + Display.stateToString(mDisplayInfo.state) + + " size=" + mDisplayInfo.logicalWidth + "x" + mDisplayInfo.logicalHeight + + " " + Surface.rotationToString(mDisplayInfo.rotation) + "}"; } String getName() { diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index c09db1e6fa98..73a699bb164d 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -156,6 +156,7 @@ import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.policy.GestureNavigationSettingsObserver; import com.android.internal.policy.ScreenDecorationsUtils; +import com.android.internal.policy.SystemBarUtils; import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.ScreenshotHelper; import com.android.internal.util.function.TriConsumer; @@ -618,7 +619,8 @@ public class DisplayPolicy { } @Override - public int onAppTransitionStartingLocked(boolean keyguardGoingAway, long duration, + public int onAppTransitionStartingLocked(boolean keyguardGoingAway, + boolean keyguardOccluding, long duration, long statusBarAnimationStartTime, long statusBarAnimationDuration) { mHandler.post(() -> { StatusBarManagerInternal statusBar = getStatusBarManagerInternal(); @@ -1093,9 +1095,6 @@ public class DisplayPolicy { switch (attrs.type) { case TYPE_NOTIFICATION_SHADE: mNotificationShade = win; - if (mDisplayContent.isDefaultDisplay) { - mService.mPolicy.setKeyguardCandidateLw(win); - } break; case TYPE_STATUS_BAR: mStatusBar = win; @@ -1291,9 +1290,6 @@ public class DisplayPolicy { mDisplayContent.setInsetProvider(ITYPE_NAVIGATION_BAR, null, null); } else if (mNotificationShade == win) { mNotificationShade = null; - if (mDisplayContent.isDefaultDisplay) { - mService.mPolicy.setKeyguardCandidateLw(null); - } } else if (mClimateBarAlt == win) { mClimateBarAlt = null; mDisplayContent.setInsetProvider(ITYPE_CLIMATE_BAR, null, null); @@ -1320,6 +1316,11 @@ public class DisplayPolicy { return Math.max(statusBarHeight, displayFrames.mDisplayCutoutSafe.top); } + @VisibleForTesting + int getStatusBarHeightForRotation(@Surface.Rotation int rotation) { + return SystemBarUtils.getStatusBarHeightForRotation(mUiContext, rotation); + } + WindowState getStatusBar() { return mStatusBar != null ? mStatusBar : mStatusBarAlt; } @@ -1589,8 +1590,6 @@ public class DisplayPolicy { // For layout, the status bar is always at the top with our fixed height. int statusBarBottom = displayFrames.mUnrestricted.top + mStatusBarHeightForRotation[displayFrames.mRotation]; - // Make sure the status bar covers the entire cutout height - statusBarBottom = Math.max(statusBarBottom, displayFrames.mDisplayCutoutSafe.top); if (displayFrames.mDisplayCutoutSafe.top > displayFrames.mUnrestricted.top) { // Make sure that the zone we're avoiding for the cutout is at least as tall as the @@ -2123,10 +2122,11 @@ public class DisplayPolicy { if (hasStatusBar()) { mStatusBarHeightForRotation[portraitRotation] = mStatusBarHeightForRotation[upsideDownRotation] = - res.getDimensionPixelSize(R.dimen.status_bar_height_portrait); + getStatusBarHeightForRotation(portraitRotation); mStatusBarHeightForRotation[landscapeRotation] = - mStatusBarHeightForRotation[seascapeRotation] = - res.getDimensionPixelSize(R.dimen.status_bar_height_landscape); + getStatusBarHeightForRotation(landscapeRotation); + mStatusBarHeightForRotation[seascapeRotation] = + getStatusBarHeightForRotation(seascapeRotation); mDisplayCutoutTouchableRegionSize = res.getDimensionPixelSize( R.dimen.display_cutout_touchable_region_size); } else { diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java index 403df9185126..d202587bd306 100644 --- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java +++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java @@ -535,7 +535,7 @@ class InsetsSourceProvider { @Override public void startAnimation(SurfaceControl animationLeash, Transaction t, - @AnimationType int type, OnAnimationFinishedCallback finishCallback) { + @AnimationType int type, @NonNull OnAnimationFinishedCallback finishCallback) { // TODO(b/166736352): Check if we still need to control the IME visibility here. if (mSource.getType() == ITYPE_IME) { // TODO: use 0 alpha and remove t.hide() once b/138459974 is fixed. diff --git a/services/core/java/com/android/server/wm/LocalAnimationAdapter.java b/services/core/java/com/android/server/wm/LocalAnimationAdapter.java index 520bd8b2108e..a3eb980992c7 100644 --- a/services/core/java/com/android/server/wm/LocalAnimationAdapter.java +++ b/services/core/java/com/android/server/wm/LocalAnimationAdapter.java @@ -19,6 +19,7 @@ package com.android.server.wm; import static com.android.server.wm.AnimationAdapterProto.LOCAL; import static com.android.server.wm.LocalAnimationAdapterProto.ANIMATION_SPEC; +import android.annotation.NonNull; import android.os.SystemClock; import android.util.proto.ProtoOutputStream; import android.view.SurfaceControl; @@ -51,7 +52,7 @@ class LocalAnimationAdapter implements AnimationAdapter { @Override public void startAnimation(SurfaceControl animationLeash, Transaction t, - @AnimationType int type, OnAnimationFinishedCallback finishCallback) { + @AnimationType int type, @NonNull OnAnimationFinishedCallback finishCallback) { mAnimator.startAnimation(mSpec, animationLeash, t, () -> finishCallback.onAnimationFinished(type, this)); } diff --git a/services/core/java/com/android/server/wm/NavBarFadeAnimationController.java b/services/core/java/com/android/server/wm/NavBarFadeAnimationController.java index e50dc51c402d..7abf3b820c18 100644 --- a/services/core/java/com/android/server/wm/NavBarFadeAnimationController.java +++ b/services/core/java/com/android/server/wm/NavBarFadeAnimationController.java @@ -18,6 +18,7 @@ package com.android.server.wm; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION; +import android.annotation.NonNull; import android.view.SurfaceControl; import android.view.animation.AlphaAnimation; import android.view.animation.Animation; @@ -144,7 +145,7 @@ public class NavBarFadeAnimationController extends FadeAnimationController{ @Override public void startAnimation(SurfaceControl animationLeash, SurfaceControl.Transaction t, - int type, SurfaceAnimator.OnAnimationFinishedCallback finishCallback) { + int type, @NonNull SurfaceAnimator.OnAnimationFinishedCallback finishCallback) { super.startAnimation(animationLeash, t, type, finishCallback); if (mParent != null && mParent.isValid()) { t.reparent(animationLeash, mParent); diff --git a/services/core/java/com/android/server/wm/NonAppWindowAnimationAdapter.java b/services/core/java/com/android/server/wm/NonAppWindowAnimationAdapter.java index 88941eb4d369..9f28509c56bd 100644 --- a/services/core/java/com/android/server/wm/NonAppWindowAnimationAdapter.java +++ b/services/core/java/com/android/server/wm/NonAppWindowAnimationAdapter.java @@ -27,6 +27,7 @@ import static com.android.server.wm.AnimationAdapterProto.REMOTE; import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION; +import android.annotation.NonNull; import android.graphics.Rect; import android.os.SystemClock; import android.util.proto.ProtoOutputStream; @@ -145,7 +146,7 @@ class NonAppWindowAnimationAdapter implements AnimationAdapter { @Override public void startAnimation(SurfaceControl animationLeash, SurfaceControl.Transaction t, - int type, SurfaceAnimator.OnAnimationFinishedCallback finishCallback) { + int type, @NonNull SurfaceAnimator.OnAnimationFinishedCallback finishCallback) { ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "startAnimation"); mCapturedLeash = animationLeash; mCapturedLeashFinishCallback = finishCallback; diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java index ba1cf8ae06df..ee05523b3f2a 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimation.java +++ b/services/core/java/com/android/server/wm/RecentsAnimation.java @@ -170,6 +170,13 @@ class RecentsAnimation implements RecentsAnimationCallbacks, OnRootTaskOrderChan ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "startRecentsActivity(): intent=%s", mTargetIntent); Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "RecentsAnimation#startRecentsActivity"); + // Cancel any existing recents animation running synchronously (do not hold the + // WM lock) before starting the newly requested recents animation as they can not coexist + if (mWindowManager.getRecentsAnimationController() != null) { + mWindowManager.getRecentsAnimationController().forceCancelAnimation( + REORDER_MOVE_TO_ORIGINAL_POSITION, "startRecentsActivity"); + } + // If the activity is associated with the root recents task, then try and get that first Task targetRootTask = mDefaultTaskDisplayArea.getRootTask(WINDOWING_MODE_UNDEFINED, mTargetActivityType); @@ -243,12 +250,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks, OnRootTaskOrderChan targetActivity.intent.replaceExtras(mTargetIntent); // Fetch all the surface controls and pass them to the client to get the animation - // started. Cancel any existing recents animation running synchronously (do not hold the - // WM lock) - if (mWindowManager.getRecentsAnimationController() != null) { - mWindowManager.getRecentsAnimationController().forceCancelAnimation( - REORDER_MOVE_TO_ORIGINAL_POSITION, "startRecentsActivity"); - } + // started mWindowManager.initializeRecentsAnimation(mTargetActivityType, recentsAnimationRunner, this, mDefaultTaskDisplayArea.getDisplayId(), mTaskSupervisor.mRecentTasks.getRecentTaskIds(), targetActivity); diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java index 22c84590fcfc..67b3ec8c2b90 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimationController.java +++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java @@ -169,8 +169,9 @@ public class RecentsAnimationController implements DeathRecipient { */ final AppTransitionListener mAppTransitionListener = new AppTransitionListener() { @Override - public int onAppTransitionStartingLocked(boolean keyguardGoingAway, long duration, - long statusBarAnimationStartTime, long statusBarAnimationDuration) { + public int onAppTransitionStartingLocked(boolean keyguardGoingAway, + boolean keyguardOccluding, long duration, long statusBarAnimationStartTime, + long statusBarAnimationDuration) { continueDeferredCancel(); return 0; } @@ -1320,7 +1321,7 @@ public class RecentsAnimationController implements DeathRecipient { @Override public void startAnimation(SurfaceControl animationLeash, Transaction t, - @AnimationType int type, OnAnimationFinishedCallback finishCallback) { + @AnimationType int type, @NonNull OnAnimationFinishedCallback finishCallback) { // Restore position and root task crop until client has a chance to modify it. t.setPosition(animationLeash, mLocalBounds.left, mLocalBounds.top); mTmpRect.set(mLocalBounds); diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java index ca1aed52fe04..eeac230489f9 100644 --- a/services/core/java/com/android/server/wm/RemoteAnimationController.java +++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java @@ -22,6 +22,7 @@ import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; +import android.annotation.NonNull; import android.graphics.Point; import android.graphics.Rect; import android.os.Binder; @@ -477,7 +478,7 @@ class RemoteAnimationController implements DeathRecipient { @Override public void startAnimation(SurfaceControl animationLeash, Transaction t, - @AnimationType int type, OnAnimationFinishedCallback finishCallback) { + @AnimationType int type, @NonNull OnAnimationFinishedCallback finishCallback) { ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "startAnimation"); if (mStartBounds.isEmpty()) { diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 0f7c6497ff72..e3600e656307 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -73,6 +73,7 @@ import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS; import static com.android.server.wm.ActivityTaskSupervisor.dumpHistoryList; import static com.android.server.wm.ActivityTaskSupervisor.printThisActivity; import static com.android.server.wm.KeyguardController.KEYGUARD_SLEEP_TOKEN_TAG; +import static com.android.server.wm.RootWindowContainerProto.DEFAULT_MIN_SIZE_RESIZABLE_TASK; import static com.android.server.wm.RootWindowContainerProto.IS_HOME_RECENTS_COMPONENT; import static com.android.server.wm.RootWindowContainerProto.KEYGUARD_CONTROLLER; import static com.android.server.wm.RootWindowContainerProto.WINDOW_CONTAINER; @@ -1254,6 +1255,11 @@ class RootWindowContainer extends WindowContainer<DisplayContent> pw.println(mTopFocusedDisplayId); } + void dumpDefaultMinSizeOfResizableTask(PrintWriter pw) { + pw.print(" mDefaultMinSizeOfResizeableTaskDp="); + pw.println(mDefaultMinSizeOfResizeableTaskDp); + } + void dumpLayoutNeededDisplayIds(PrintWriter pw) { if (!isLayoutNeeded()) { return; @@ -1300,7 +1306,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> mTaskSupervisor.getKeyguardController().dumpDebug(proto, KEYGUARD_CONTROLLER); proto.write(IS_HOME_RECENTS_COMPONENT, mTaskSupervisor.mRecentTasks.isRecentsComponentHomeActivity(mCurrentUser)); - + proto.write(DEFAULT_MIN_SIZE_RESIZABLE_TASK, mDefaultMinSizeOfResizeableTaskDp); proto.end(token); } diff --git a/services/core/java/com/android/server/wm/SurfaceFreezer.java b/services/core/java/com/android/server/wm/SurfaceFreezer.java index 9a0cabebbdc6..c667db86e410 100644 --- a/services/core/java/com/android/server/wm/SurfaceFreezer.java +++ b/services/core/java/com/android/server/wm/SurfaceFreezer.java @@ -229,7 +229,7 @@ class SurfaceFreezer { cancelAnimation(t, false /* restarting */); return; } - mAnimation.startAnimation(mSurfaceControl, t, type, null /* finishCallback */); + mAnimation.startAnimation(mSurfaceControl, t, type, (typ, ani) -> { }); } /** diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 3cb80d6e643e..ba2da06efab4 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -1001,7 +1001,6 @@ class Task extends TaskFragment { mCallingPackage = r.launchedFromPackage; mCallingFeatureId = r.launchedFromFeatureId; setIntent(intent != null ? intent : r.intent, info != null ? info : r.info); - return; } setLockTaskAuth(r); } @@ -1926,6 +1925,7 @@ class Task extends TaskFragment { final ActivityRecord r = topRunningActivity(); if (r != null && mDisplayContent.isFixedRotationLaunchingApp(r)) { getSyncTransaction().setWindowCrop(mSurfaceControl, null) + .setCornerRadius(mSurfaceControl, 0f) .setMatrix(mSurfaceControl, Matrix.IDENTITY_MATRIX, new float[9]); } } diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java index 71844ce02b20..275ed0ee28a9 100644 --- a/services/core/java/com/android/server/wm/TaskDisplayArea.java +++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java @@ -1275,6 +1275,11 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> { } } } + // For better split UX, If task launch by the source task which root task is created by + // organizer, it should also launch in that root too. + if (sourceTask != null && sourceTask.getRootTask().mCreatedByOrganizer) { + return sourceTask.getRootTask(); + } return null; } diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java index e31a6620187a..b8ceb4a4f421 100644 --- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java +++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java @@ -717,7 +717,7 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { } // First we get the default size we want. - getDefaultFreeformSize(displayArea, layout, orientation, mTmpBounds); + getDefaultFreeformSize(root.info, displayArea, layout, orientation, mTmpBounds); if (hasInitialBounds || sizeMatches(inOutBounds, mTmpBounds)) { // We're here because either input parameters specified initial bounds, or the suggested // bounds have the same size of the default freeform size. We should use the suggested @@ -785,7 +785,8 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { return orientation; } - private void getDefaultFreeformSize(@NonNull TaskDisplayArea displayArea, + private void getDefaultFreeformSize(@NonNull ActivityInfo info, + @NonNull TaskDisplayArea displayArea, @NonNull ActivityInfo.WindowLayout layout, int orientation, @NonNull Rect bounds) { // Default size, which is letterboxing/pillarboxing in displayArea. That's to say the large // dimension of default size is the small dimension of displayArea size, and the small @@ -816,11 +817,38 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { final int layoutMinWidth = (layout == null) ? -1 : layout.minWidth; final int layoutMinHeight = (layout == null) ? -1 : layout.minHeight; - // Final result. + // Aspect ratio requirements. + final float minAspectRatio = info.getMinAspectRatio(orientation); + final float maxAspectRatio = info.getMaxAspectRatio(); + final int width = Math.min(defaultWidth, Math.max(phoneWidth, layoutMinWidth)); final int height = Math.min(defaultHeight, Math.max(phoneHeight, layoutMinHeight)); + final float aspectRatio = (float) Math.max(width, height) / (float) Math.min(width, height); + + // Adjust the width and height to the aspect ratio requirements. + int adjWidth = width; + int adjHeight = height; + if (minAspectRatio >= 1 && aspectRatio < minAspectRatio) { + // The aspect ratio is below the minimum, adjust it to the minimum. + if (orientation == SCREEN_ORIENTATION_LANDSCAPE) { + // Fix the width, scale the height. + adjHeight = (int) (adjWidth / minAspectRatio + 0.5f); + } else { + // Fix the height, scale the width. + adjWidth = (int) (adjHeight / minAspectRatio + 0.5f); + } + } else if (maxAspectRatio >= 1 && aspectRatio > maxAspectRatio) { + // The aspect ratio exceeds the maximum, adjust it to the maximum. + if (orientation == SCREEN_ORIENTATION_LANDSCAPE) { + // Fix the width, scale the height. + adjHeight = (int) (adjWidth / maxAspectRatio + 0.5f); + } else { + // Fix the height, scale the width. + adjWidth = (int) (adjHeight / maxAspectRatio + 0.5f); + } + } - bounds.set(0, 0, width, height); + bounds.set(0, 0, adjWidth, adjHeight); bounds.offset(stableBounds.left, stableBounds.top); } diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java index 731036b3d9a4..3d5f9881e044 100644 --- a/services/core/java/com/android/server/wm/TaskOrganizerController.java +++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java @@ -22,6 +22,7 @@ import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_STARTING_REVEAL; import static com.android.server.wm.WindowOrganizerController.configurationsAreEqualForOrganizer; +import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityManager.RunningTaskInfo; @@ -431,7 +432,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { @Override public void startAnimation(SurfaceControl animationLeash, SurfaceControl.Transaction t, - int type, SurfaceAnimator.OnAnimationFinishedCallback finishCallback) { + int type, @NonNull SurfaceAnimator.OnAnimationFinishedCallback finishCallback) { mAnimationLeash = animationLeash; } diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index e537c0afc147..5d82553ad284 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -165,13 +165,13 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe private boolean mNavBarAttachedToApp = false; private int mRecentsDisplayId = INVALID_DISPLAY; - Transition(@TransitionType int type, @TransitionFlags int flags, + Transition(@TransitionType int type, @TransitionFlags int flags, long timeoutMs, TransitionController controller, BLASTSyncEngine syncEngine) { mType = type; mFlags = flags; mController = controller; mSyncEngine = syncEngine; - mSyncId = mSyncEngine.startSyncSet(this); + mSyncId = mSyncEngine.startSyncSet(this, timeoutMs); } void addFlag(int flag) { @@ -469,6 +469,7 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe if (mState != STATE_COLLECTING) { throw new IllegalStateException("Too late to abort."); } + ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Aborting Transition: %d", mSyncId); mController.dispatchLegacyAppTransitionCancelled(); mState = STATE_ABORT; // Syncengine abort will call through to onTransactionReady() @@ -789,7 +790,8 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe } } if ((flags & TRANSIT_FLAG_KEYGUARD_LOCKED) != 0) { - mController.mAtm.mWindowManager.mPolicy.applyKeyguardOcclusionChange(); + mController.mAtm.mWindowManager.mPolicy.applyKeyguardOcclusionChange( + true /* keyguardOccludingStarted */); } } diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java index ff4cc3d1b784..91825ccf98e7 100644 --- a/services/core/java/com/android/server/wm/TransitionController.java +++ b/services/core/java/com/android/server/wm/TransitionController.java @@ -17,6 +17,7 @@ package com.android.server.wm; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; +import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_CLOSE; import static android.view.WindowManager.TRANSIT_FLAG_IS_RECENTS; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY; @@ -30,10 +31,12 @@ import android.os.IBinder; import android.os.IRemoteCallback; import android.os.RemoteException; import android.os.SystemClock; +import android.util.ArrayMap; import android.util.Slog; import android.util.proto.ProtoOutputStream; import android.view.WindowManager; import android.window.IRemoteTransition; +import android.window.ITransitionMetricsReporter; import android.window.ITransitionPlayer; import android.window.RemoteTransition; import android.window.TransitionInfo; @@ -45,6 +48,7 @@ import com.android.server.LocalServices; import com.android.server.statusbar.StatusBarManagerInternal; import java.util.ArrayList; +import java.util.function.LongConsumer; /** * Handles all the aspects of recording and synchronizing transitions. @@ -52,12 +56,19 @@ import java.util.ArrayList; class TransitionController { private static final String TAG = "TransitionController"; + /** The same as legacy APP_TRANSITION_TIMEOUT_MS. */ + private static final int DEFAULT_TIMEOUT_MS = 5000; + /** Less duration for CHANGE type because it does not involve app startup. */ + private static final int CHANGE_TIMEOUT_MS = 2000; + // State constants to line-up with legacy app-transition proto expectations. private static final int LEGACY_STATE_IDLE = 0; private static final int LEGACY_STATE_READY = 1; private static final int LEGACY_STATE_RUNNING = 2; private ITransitionPlayer mTransitionPlayer; + final TransitionMetricsReporter mTransitionMetricsReporter = new TransitionMetricsReporter(); + final ActivityTaskManagerService mAtm; final TaskSnapshotController mTaskSnapshotController; @@ -116,7 +127,10 @@ class TransitionController { if (mCollectingTransition != null) { throw new IllegalStateException("Simultaneous transitions not supported yet."); } - mCollectingTransition = new Transition(type, flags, this, mAtm.mWindowManager.mSyncEngine); + // Distinguish change type because the response time is usually expected to be not too long. + final long timeoutMs = type == TRANSIT_CHANGE ? CHANGE_TIMEOUT_MS : DEFAULT_TIMEOUT_MS; + mCollectingTransition = new Transition(type, flags, timeoutMs, this, + mAtm.mWindowManager.mSyncEngine); ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Creating Transition: %s", mCollectingTransition); dispatchLegacyAppTransitionPending(); @@ -324,6 +338,8 @@ class TransitionController { /** @see Transition#finishTransition */ void finishTransition(@NonNull IBinder token) { + // It is usually a no-op but make sure that the metric consumer is removed. + mTransitionMetricsReporter.reportAnimationStart(token, 0 /* startTime */); final Transition record = Transition.fromBinder(token); if (record == null || !mPlayingTransitions.contains(record)) { Slog.e(TAG, "Trying to finish a non-playing transition " + token); @@ -388,9 +404,10 @@ class TransitionController { void dispatchLegacyAppTransitionStarting(TransitionInfo info) { final boolean keyguardGoingAway = info.isKeyguardGoingAway(); for (int i = 0; i < mLegacyListeners.size(); ++i) { + // TODO(shell-transitions): handle (un)occlude transition. mLegacyListeners.get(i).onAppTransitionStartingLocked(keyguardGoingAway, - 0 /* durationHint */, SystemClock.uptimeMillis(), - AnimationAdapter.STATUS_BAR_TRANSITION_DURATION); + false /* keyguardOcclude */, 0 /* durationHint */, + SystemClock.uptimeMillis(), AnimationAdapter.STATUS_BAR_TRANSITION_DURATION); } } @@ -419,6 +436,28 @@ class TransitionController { proto.end(token); } + static class TransitionMetricsReporter extends ITransitionMetricsReporter.Stub { + private final ArrayMap<IBinder, LongConsumer> mMetricConsumers = new ArrayMap<>(); + + void associate(IBinder transitionToken, LongConsumer consumer) { + synchronized (mMetricConsumers) { + mMetricConsumers.put(transitionToken, consumer); + } + } + + @Override + public void reportAnimationStart(IBinder transitionToken, long startTime) { + final LongConsumer c; + synchronized (mMetricConsumers) { + if (mMetricConsumers.isEmpty()) return; + c = mMetricConsumers.remove(transitionToken); + } + if (c != null) { + c.accept(startTime); + } + } + } + class Lock { private int mTransitionWaiters = 0; void runWhenIdle(long timeout, Runnable r) { diff --git a/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java b/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java index 0b20f37eea0f..26527233aef0 100644 --- a/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java +++ b/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java @@ -20,6 +20,7 @@ import static com.android.server.wm.AnimationAdapterProto.REMOTE; import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION; +import android.annotation.NonNull; import android.graphics.Point; import android.os.SystemClock; import android.util.proto.ProtoOutputStream; @@ -133,7 +134,8 @@ class WallpaperAnimationAdapter implements AnimationAdapter { @Override public void startAnimation(SurfaceControl animationLeash, SurfaceControl.Transaction t, - @AnimationType int type, SurfaceAnimator.OnAnimationFinishedCallback finishCallback) { + @AnimationType int type, + @NonNull SurfaceAnimator.OnAnimationFinishedCallback finishCallback) { ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "startAnimation"); // Restore z-layering until client has a chance to modify it. diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java index a92e0883db37..d93b649b390a 100644 --- a/services/core/java/com/android/server/wm/WallpaperController.java +++ b/services/core/java/com/android/server/wm/WallpaperController.java @@ -801,6 +801,18 @@ class WallpaperController { wallpaperBuffer.getHardwareBuffer(), wallpaperBuffer.getColorSpace()); } + /** + * Mirrors the visible wallpaper if it's available. + * + * @return A SurfaceControl for the parent of the mirrored wallpaper. + */ + SurfaceControl mirrorWallpaperSurface() { + final WindowState wallpaperWindowState = getTopVisibleWallpaper(); + return wallpaperWindowState != null + ? SurfaceControl.mirrorSurface(wallpaperWindowState.getSurfaceControl()) + : null; + } + WindowState getTopVisibleWallpaper() { mTmpTopWallpaper = null; diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java index ba0266a575bf..4e51a17e03e0 100644 --- a/services/core/java/com/android/server/wm/WindowManagerInternal.java +++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java @@ -194,7 +194,7 @@ public abstract class WindowManagerInternal { /** * Called when a pending app transition gets cancelled. * - * @param keyguardGoingAway true if keyguard going away transition transition got cancelled. + * @param keyguardGoingAway true if keyguard going away transition got cancelled. */ public void onAppTransitionCancelledLocked(boolean keyguardGoingAway) {} @@ -207,6 +207,7 @@ public abstract class WindowManagerInternal { * Called when an app transition gets started * * @param keyguardGoingAway true if keyguard going away transition is started. + * @param keyguardOccluding true if keyguard (un)occlude transition is started. * @param duration the total duration of the transition * @param statusBarAnimationStartTime the desired start time for all visual animations in * the status bar caused by this app transition in uptime millis @@ -218,8 +219,9 @@ public abstract class WindowManagerInternal { * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_WALLPAPER}, * or {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_ANIM}. */ - public int onAppTransitionStartingLocked(boolean keyguardGoingAway, long duration, - long statusBarAnimationStartTime, long statusBarAnimationDuration) { + public int onAppTransitionStartingLocked(boolean keyguardGoingAway, + boolean keyguardOccluding, long duration, long statusBarAnimationStartTime, + long statusBarAnimationDuration) { return 0; } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 17297bd0ba45..9b53d3e00a1e 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -433,7 +433,7 @@ public class WindowManagerService extends IWindowManager.Stub "persist.wm.enable_remote_keyguard_animation"; private static final int sEnableRemoteKeyguardAnimation = - SystemProperties.getInt(ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY, 0); + SystemProperties.getInt(ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY, 1); /** * @see #ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY @@ -2584,7 +2584,7 @@ public class WindowManagerService extends IWindowManager.Stub win.mAnimatingExit = true; } else if (win.mDisplayContent.okToAnimate() && win.mDisplayContent.mWallpaperController.isWallpaperTarget(win) - && win.mAttrs.type == TYPE_NOTIFICATION_SHADE) { + && win.mAttrs.type != TYPE_NOTIFICATION_SHADE) { // If the wallpaper is currently behind this app window, we need to change both of them // inside of a transaction to avoid artifacts. // For NotificationShade, sysui is in charge of running window animation and it updates @@ -3792,6 +3792,14 @@ public class WindowManagerService extends IWindowManager.Stub } } + @Override + public SurfaceControl mirrorWallpaperSurface(int displayId) { + synchronized (mGlobalLock) { + final DisplayContent dc = mRoot.getDisplayContent(displayId); + return dc.mWallpaperController.mirrorWallpaperSurface(); + } + } + /** * Takes a snapshot of the screen. In landscape mode this grabs the whole screen. * In portrait mode, it grabs the upper region of the screen based on the vertical dimension @@ -5388,6 +5396,7 @@ public class WindowManagerService extends IWindowManager.Stub case WINDOW_STATE_BLAST_SYNC_TIMEOUT: { synchronized (mGlobalLock) { final WindowState ws = (WindowState) msg.obj; + Slog.i(TAG, "Blast sync timeout: " + ws); ws.immediatelyNotifyBlastSync(); } break; @@ -5828,7 +5837,9 @@ public class WindowManagerService extends IWindowManager.Stub return; } - if (!displayContent.isReady() || !mPolicy.isScreenOn() || !displayContent.okToAnimate()) { + if (!displayContent.isReady() || !displayContent.getDisplayPolicy().isScreenOnFully() + || displayContent.getDisplayInfo().state == Display.STATE_OFF + || !displayContent.okToAnimate()) { // No need to freeze the screen before the display is ready, if the screen is off, // or we can't currently animate. return; @@ -6422,6 +6433,7 @@ public class WindowManagerService extends IWindowManager.Stub pw.print(" mGlobalConfiguration="); pw.println(mRoot.getConfiguration()); pw.print(" mHasPermanentDpad="); pw.println(mHasPermanentDpad); mRoot.dumpTopFocusedDisplayId(pw); + mRoot.dumpDefaultMinSizeOfResizableTask(pw); mRoot.forAllDisplays(dc -> { final int displayId = dc.getDisplayId(); final InsetsControlTarget imeLayeringTarget = dc.getImeTarget(IME_TARGET_LAYERING); diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index 54ce5fc6bbec..6e706e9df003 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -66,6 +66,7 @@ import android.window.IDisplayAreaOrganizerController; import android.window.ITaskFragmentOrganizer; import android.window.ITaskFragmentOrganizerController; import android.window.ITaskOrganizerController; +import android.window.ITransitionMetricsReporter; import android.window.ITransitionPlayer; import android.window.IWindowContainerTransactionCallback; import android.window.IWindowOrganizerController; @@ -83,7 +84,7 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.function.Consumer; +import java.util.function.Function; /** * Server side implementation for the interface for organizing windows @@ -893,24 +894,31 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub // We want to collect the tasks first before re-parenting to avoid array shifting on us. final ArrayList<Task> tasksToReparent = new ArrayList<>(); - currentParent.forAllTasks((Consumer<Task>) (task) -> { + currentParent.forAllTasks((Function<Task, Boolean>) task -> { Slog.i(TAG, " Processing task=" + task); - if (task.mCreatedByOrganizer - || task.getParent() != finalCurrentParent) { + final boolean reparent; + if (task.mCreatedByOrganizer || task.getParent() != finalCurrentParent) { // We only care about non-organized task that are direct children of the thing we // are reparenting from. - return; + return false; } if (newParentInMultiWindow && !task.supportsMultiWindowInDisplayArea(newParentTda)) { Slog.e(TAG, "reparentChildrenTasksHierarchyOp non-resizeable task to multi window," + " task=" + task); - return; + return false; + } + if (!ArrayUtils.contains(hop.getActivityTypes(), task.getActivityType()) + || !ArrayUtils.contains(hop.getWindowingModes(), task.getWindowingMode())) { + return false; } - if (!ArrayUtils.contains(hop.getActivityTypes(), task.getActivityType())) return; - if (!ArrayUtils.contains(hop.getWindowingModes(), task.getWindowingMode())) return; - tasksToReparent.add(task); - }, !hop.getToTop()); + if (hop.getToTop()) { + tasksToReparent.add(0, task); + } else { + tasksToReparent.add(task); + } + return hop.getReparentTopOnly() && tasksToReparent.size() == 1; + }); final int count = tasksToReparent.size(); for (int i = 0; i < count; ++i) { @@ -1033,6 +1041,11 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub } } + @Override + public ITransitionMetricsReporter getTransitionMetricsReporter() { + return mTransitionController.mTransitionMetricsReporter; + } + /** Whether the configuration changes are important to report back to an organizer. */ static boolean configurationsAreEqualForOrganizer( Configuration newConfig, @Nullable Configuration oldConfig) { diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java index 719d52c89209..af386419d455 100644 --- a/services/core/java/com/android/server/wm/WindowProcessController.java +++ b/services/core/java/com/android/server/wm/WindowProcessController.java @@ -952,7 +952,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio final int displayId = r.getDisplayId(); final Context c = root.getDisplayUiContext(displayId); - if (r.mVisibleRequested && !displayContexts.contains(c)) { + if (c != null && r.mVisibleRequested && !displayContexts.contains(c)) { displayContexts.add(c); } } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index d29b2aecf793..8fafc7d64c29 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -6041,16 +6041,13 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // in WAITING state rather than READY. mSyncState = SYNC_STATE_WAITING_FOR_DRAW; requestRedrawForSync(); - - mWmService.mH.removeMessages(WINDOW_STATE_BLAST_SYNC_TIMEOUT, this); - mWmService.mH.sendNewMessageDelayed(WINDOW_STATE_BLAST_SYNC_TIMEOUT, this, - BLAST_TIMEOUT_DURATION); return true; } @Override boolean isSyncFinished() { - if (mSyncState == SYNC_STATE_WAITING_FOR_DRAW && mViewVisibility == View.GONE) { + if (mSyncState == SYNC_STATE_WAITING_FOR_DRAW && mViewVisibility == View.GONE + && !isVisibleRequested()) { // Don't wait for GONE windows. However, we don't alter the state in case the window // becomes un-gone while the syncset is still active. return true; diff --git a/services/tests/servicestests/src/com/android/server/am/BatteryExternalStatsWorkerTest.java b/services/tests/servicestests/src/com/android/server/am/BatteryExternalStatsWorkerTest.java index 8a8a6246b73b..6faa7e7c89e7 100644 --- a/services/tests/servicestests/src/com/android/server/am/BatteryExternalStatsWorkerTest.java +++ b/services/tests/servicestests/src/com/android/server/am/BatteryExternalStatsWorkerTest.java @@ -202,6 +202,7 @@ public class BatteryExternalStatsWorkerTest { public class TestBatteryStatsImpl extends BatteryStatsImpl { public TestBatteryStatsImpl(Context context) { mPowerProfile = new PowerProfile(context, true /* forTest */); + initTimersAndCounters(); } } diff --git a/services/tests/servicestests/src/com/android/server/camera/CameraServiceProxyTest.java b/services/tests/servicestests/src/com/android/server/camera/CameraServiceProxyTest.java new file mode 100644 index 000000000000..ea746d1f4fd3 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/camera/CameraServiceProxyTest.java @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.camera; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import static com.google.common.truth.Truth.assertThat; + +import androidx.test.InstrumentationRegistry; + +import android.content.Context; +import android.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.CameraMetadata; +import android.view.Display; +import android.view.Surface; + +import java.util.HashMap; + +@RunWith(JUnit4.class) +public class CameraServiceProxyTest { + + @Test + public void testGetCropRotateScale() { + + Context ctx = InstrumentationRegistry.getContext(); + + // Check resizeability and SDK + CameraServiceProxy.TaskInfo taskInfo = new CameraServiceProxy.TaskInfo(); + taskInfo.isResizeable = true; + taskInfo.displayId = Display.DEFAULT_DISPLAY; + taskInfo.isFixedOrientationLandscape = false; + taskInfo.isFixedOrientationPortrait = true; + // Resizeable apps should be ignored + assertThat(CameraServiceProxy.getCropRotateScale(ctx, ctx.getPackageName(), taskInfo, + Surface.ROTATION_90 , CameraCharacteristics.LENS_FACING_BACK, + /*ignoreResizableAndSdkCheck*/false)).isEqualTo( + CameraMetadata.SCALER_ROTATE_AND_CROP_NONE); + // Resizeable apps will be considered in case the ignore flag is set + assertThat(CameraServiceProxy.getCropRotateScale(ctx, ctx.getPackageName(), taskInfo, + Surface.ROTATION_90, CameraCharacteristics.LENS_FACING_BACK, + /*ignoreResizableAndSdkCheck*/true)).isEqualTo( + CameraMetadata.SCALER_ROTATE_AND_CROP_90); + taskInfo.isResizeable = false; + // Non-resizeable apps should be considered + assertThat(CameraServiceProxy.getCropRotateScale(ctx, ctx.getPackageName(), taskInfo, + Surface.ROTATION_90, CameraCharacteristics.LENS_FACING_BACK, + /*ignoreResizableAndSdkCheck*/false)).isEqualTo( + CameraMetadata.SCALER_ROTATE_AND_CROP_90); + // The ignore flag for non-resizeable should have no effect + assertThat(CameraServiceProxy.getCropRotateScale(ctx, ctx.getPackageName(), taskInfo, + Surface.ROTATION_90, CameraCharacteristics.LENS_FACING_BACK, + /*ignoreResizableAndSdkCheck*/true)).isEqualTo( + CameraMetadata.SCALER_ROTATE_AND_CROP_90); + // Non-fixed orientation should be ignored + taskInfo.isFixedOrientationLandscape = false; + taskInfo.isFixedOrientationPortrait = false; + assertThat(CameraServiceProxy.getCropRotateScale(ctx, ctx.getPackageName(), taskInfo, + Surface.ROTATION_90, CameraCharacteristics.LENS_FACING_BACK, + /*ignoreResizableAndSdkCheck*/true)).isEqualTo( + CameraMetadata.SCALER_ROTATE_AND_CROP_NONE); + // Check rotation and lens facing combinations + HashMap<Integer, Integer> backFacingMap = new HashMap<Integer, Integer>() {{ + put(Surface.ROTATION_0, CameraMetadata.SCALER_ROTATE_AND_CROP_NONE); + put(Surface.ROTATION_90, CameraMetadata.SCALER_ROTATE_AND_CROP_90); + put(Surface.ROTATION_270, CameraMetadata.SCALER_ROTATE_AND_CROP_270); + put(Surface.ROTATION_180, CameraMetadata.SCALER_ROTATE_AND_CROP_180); + }}; + taskInfo.isFixedOrientationPortrait = true; + backFacingMap.forEach((key, value) -> { + assertThat(CameraServiceProxy.getCropRotateScale(ctx, ctx.getPackageName(), taskInfo, + key, CameraCharacteristics.LENS_FACING_BACK, + /*ignoreResizableAndSdkCheck*/true)).isEqualTo(value); + }); + HashMap<Integer, Integer> frontFacingMap = new HashMap<Integer, Integer>() {{ + put(Surface.ROTATION_0, CameraMetadata.SCALER_ROTATE_AND_CROP_NONE); + put(Surface.ROTATION_90, CameraMetadata.SCALER_ROTATE_AND_CROP_270); + put(Surface.ROTATION_270, CameraMetadata.SCALER_ROTATE_AND_CROP_90); + put(Surface.ROTATION_180, CameraMetadata.SCALER_ROTATE_AND_CROP_180); + }}; + frontFacingMap.forEach((key, value) -> { + assertThat(CameraServiceProxy.getCropRotateScale(ctx, ctx.getPackageName(), taskInfo, + key, CameraCharacteristics.LENS_FACING_FRONT, + /*ignoreResizableAndSdkCheck*/true)).isEqualTo(value); + }); + } +} diff --git a/services/tests/servicestests/src/com/android/server/camera/OWNERS b/services/tests/servicestests/src/com/android/server/camera/OWNERS new file mode 100644 index 000000000000..f48a95c5b3a3 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/camera/OWNERS @@ -0,0 +1 @@ +include platform/frameworks/av:/camera/OWNERS diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt index 581ff5472e92..9099bb515361 100644 --- a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt +++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt @@ -341,10 +341,8 @@ open class AndroidPackageParsingTestBase { launchToken=${this.launchToken} lockTaskLaunchMode=${this.lockTaskLaunchMode} logo=${this.logo} - maxAspectRatio=${this.maxAspectRatio} maxRecents=${this.maxRecents} metaData=${this.metaData.dumpToString()} - minAspectRatio=${this.minAspectRatio} name=${this.name} nonLocalizedLabel=${ // Per b/184574333, v1 mistakenly trimmed the label. v2 fixed this, but for test diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java index 577e36c7d5db..a834e2b6cc5a 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java @@ -118,7 +118,7 @@ public class NotificationListenerServiceTest extends UiServiceTestCase { assertActionsEqual(getSmartActions(key, i), ranking.getSmartActions()); assertEquals(getSmartReplies(key, i), ranking.getSmartReplies()); assertEquals(canBubble(i), ranking.canBubble()); - assertEquals(visuallyInterruptive(i), ranking.visuallyInterruptive()); + assertEquals(isTextChanged(i), ranking.isTextChanged()); assertEquals(isConversation(i), ranking.isConversation()); assertEquals(getShortcutInfo(i).getId(), ranking.getConversationShortcutInfo().getId()); assertEquals(getRankingAdjustment(i), ranking.getRankingAdjustment()); @@ -189,7 +189,7 @@ public class NotificationListenerServiceTest extends UiServiceTestCase { (ArrayList) tweak.getSmartActions(), (ArrayList) tweak.getSmartReplies(), tweak.canBubble(), - tweak.visuallyInterruptive(), + tweak.isTextChanged(), tweak.isConversation(), tweak.getConversationShortcutInfo(), tweak.getRankingAdjustment(), @@ -270,7 +270,7 @@ public class NotificationListenerServiceTest extends UiServiceTestCase { getSmartActions(key, i), getSmartReplies(key, i), canBubble(i), - visuallyInterruptive(i), + isTextChanged(i), isConversation(i), getShortcutInfo(i), getRankingAdjustment(i), @@ -379,7 +379,7 @@ public class NotificationListenerServiceTest extends UiServiceTestCase { return index % 4 == 0; } - private boolean visuallyInterruptive(int index) { + private boolean isTextChanged(int index) { return index % 4 == 0; } 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 1ae219db7726..c493639fc6b1 100755 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -3872,6 +3872,27 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test + public void testVisuallyInterruptive_notSeen() throws Exception { + NotificationRecord original = generateNotificationRecord(mTestNotificationChannel); + mService.addNotification(original); + + StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, original.getSbn().getId(), + original.getSbn().getTag(), mUid, 0, + new Notification.Builder(mContext, mTestNotificationChannel.getId()) + .setContentTitle("new title").build(), + UserHandle.getUserHandleForUid(mUid), null, 0); + NotificationRecord update = new NotificationRecord(mContext, sbn, mTestNotificationChannel); + mService.addEnqueuedNotification(update); + + NotificationManagerService.PostNotificationRunnable runnable = + mService.new PostNotificationRunnable(update.getKey()); + runnable.run(); + waitForIdle(); + + assertFalse(update.isInterruptive()); + } + + @Test public void testApplyAdjustmentMultiUser() throws Exception { final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); mService.addNotification(r); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index 65733d7a4129..44cff33d6146 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -77,6 +77,7 @@ import static com.android.server.wm.ActivityRecord.State.RESUMED; import static com.android.server.wm.ActivityRecord.State.STARTED; import static com.android.server.wm.ActivityRecord.State.STOPPED; import static com.android.server.wm.ActivityRecord.State.STOPPING; +import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION; import static com.android.server.wm.TaskFragment.TASK_FRAGMENT_VISIBILITY_INVISIBLE; import static com.android.server.wm.TaskFragment.TASK_FRAGMENT_VISIBILITY_VISIBLE; import static com.android.server.wm.TaskFragment.TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT; @@ -1751,6 +1752,11 @@ public class ActivityRecordTests extends WindowTestsBase { anyInt() /* orientation */, anyInt() /* lastRotation */); // Set to visible so the activity can freeze the screen. activity.setVisibility(true); + // Update the display policy to make the screen fully turned on so the freeze is allowed + display.getDisplayPolicy().screenTurnedOn(null); + display.getDisplayPolicy().finishKeyguardDrawn(); + display.getDisplayPolicy().finishWindowsDrawn(); + display.getDisplayPolicy().finishScreenTurningOn(); display.rotateInDifferentOrientationIfNeeded(activity); display.setFixedRotationLaunchingAppUnchecked(activity); @@ -3026,6 +3032,10 @@ public class ActivityRecordTests extends WindowTestsBase { // Because the app is waiting for transition, it should not hide the surface. assertTrue(app.mActivityRecord.isSurfaceShowing()); + + // Ensure onAnimationFinished will callback when the closing animation is finished. + verify(app.mActivityRecord).onAnimationFinished(eq(ANIMATION_TYPE_APP_TRANSITION), + eq(null)); } private void assertHasStartingWindow(ActivityRecord atoken) { diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java index 3982a83d7778..1d2baab934e5 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java @@ -31,6 +31,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.server.wm.utils.CoordinateTransforms.transformPhysicalToLogicalCoordinates; import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.anyInt; import android.content.Context; import android.content.ContextWrapper; @@ -75,13 +76,12 @@ public class DisplayPolicyTestsBase extends WindowTestsBase { final TestContextWrapper context = new TestContextWrapper( mDisplayPolicy.getContext(), mDisplayPolicy.getCurrentUserResources()); final TestableResources resources = context.getResourceMocker(); - resources.addOverride(R.dimen.status_bar_height_portrait, STATUS_BAR_HEIGHT); - resources.addOverride(R.dimen.status_bar_height_landscape, STATUS_BAR_HEIGHT); resources.addOverride(R.dimen.navigation_bar_height, NAV_BAR_HEIGHT); resources.addOverride(R.dimen.navigation_bar_height_landscape, NAV_BAR_HEIGHT); resources.addOverride(R.dimen.navigation_bar_width, NAV_BAR_HEIGHT); resources.addOverride(R.dimen.navigation_bar_frame_height_landscape, NAV_BAR_HEIGHT); resources.addOverride(R.dimen.navigation_bar_frame_height, NAV_BAR_HEIGHT); + doReturn(STATUS_BAR_HEIGHT).when(mDisplayPolicy).getStatusBarHeightForRotation(anyInt()); doReturn(resources.getResources()).when(mDisplayPolicy).getCurrentUserResources(); doReturn(true).when(mDisplayPolicy).hasNavigationBar(); doReturn(true).when(mDisplayPolicy).hasStatusBar(); diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java index a680cba8b266..9d2a69197013 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java @@ -257,7 +257,7 @@ public class RecentsAnimationControllerTest extends WindowTestsBase { verify(mMockRunner).onAnimationCanceled(null /* taskSnapshot */); // Simulate the app transition finishing - mController.mAppTransitionListener.onAppTransitionStartingLocked(false, 0, 0, 0); + mController.mAppTransitionListener.onAppTransitionStartingLocked(false, false, 0, 0, 0); verify(mAnimationCallbacks).onAnimationFinished(REORDER_KEEP_IN_PLACE, false); } diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java index 6407c92ee2aa..bed0a94f3b8f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java @@ -83,6 +83,8 @@ import android.view.WindowManager; import androidx.test.filters.MediumTest; +import com.android.internal.policy.SystemBarUtils; + import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges; import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges; @@ -174,7 +176,9 @@ public class SizeCompatTests extends WindowTestsBase { // The activity should be able to accept negative x position [-150, 100 - 150, 600]. final int dx = bounds.left + bounds.width() / 2; - mTask.setBounds(bounds.left - dx, bounds.top, bounds.right - dx, bounds.bottom); + final int dy = bounds.top + bounds.height() / 2; + mTask.setBounds(bounds.left - dx, bounds.top - dy, bounds.right - dx, bounds.bottom - dy); + // expected:<Rect(-150, 100 - 150, 600)> but was:<Rect(-150, 0 - 150, 500)> assertEquals(mTask.getBounds(), mActivity.getBounds()); final int density = mActivity.getConfiguration().densityDpi; @@ -1119,6 +1123,98 @@ public class SizeCompatTests extends WindowTestsBase { } @Test + @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO, + ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM}) + public void testOverrideMinAspectRatioScreenOrientationNotSetThenChangedToPortrait() { + // In this test, the activity's orientation isn't fixed to portrait, therefore the override + // isn't applied. + + setUpDisplaySizeWithApp(1000, 1200); + + // Create a size compat activity on the same task. + final ActivityRecord activity = new ActivityBuilder(mAtm) + .setTask(mTask) + .setComponent(ComponentName.createRelative(mContext, + SizeCompatTests.class.getName())) + .setUid(android.os.Process.myUid()) + .build(); + + // The per-package override should have no effect + assertEquals(1200, activity.getBounds().height()); + assertEquals(1000, activity.getBounds().width()); + + // After changing the orientation to portrait the override should be applied. + activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + activity.clearSizeCompatMode(); + + // The per-package override forces the activity into a 3:2 aspect ratio + assertEquals(1200, activity.getBounds().height()); + assertEquals(1200 / ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM_VALUE, + activity.getBounds().width(), 0.5); + } + + @Test + @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO, + ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM}) + public void testOverrideMinAspectRatioScreenOrientationLandscapeThenChangedToPortrait() { + // In this test, the activity's orientation isn't fixed to portrait, therefore the override + // isn't applied. + + setUpDisplaySizeWithApp(1000, 1200); + + // Create a size compat activity on the same task. + final ActivityRecord activity = new ActivityBuilder(mAtm) + .setTask(mTask) + .setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) + .setComponent(ComponentName.createRelative(mContext, + SizeCompatTests.class.getName())) + .setUid(android.os.Process.myUid()) + .build(); + + // The per-package override should have no effect + assertEquals(1200, activity.getBounds().height()); + assertEquals(1000, activity.getBounds().width()); + + // After changing the orientation to portrait the override should be applied. + activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + activity.clearSizeCompatMode(); + + // The per-package override forces the activity into a 3:2 aspect ratio + assertEquals(1200, activity.getBounds().height()); + assertEquals(1200 / ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM_VALUE, + activity.getBounds().width(), 0.5); + } + + @Test + @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO, + ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM}) + public void testOverrideMinAspectRatioScreenOrientationPortraitThenChangedToUnspecified() { + setUpDisplaySizeWithApp(1000, 1200); + + // Create a size compat activity on the same task. + final ActivityRecord activity = new ActivityBuilder(mAtm) + .setTask(mTask) + .setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) + .setComponent(ComponentName.createRelative(mContext, + SizeCompatTests.class.getName())) + .setUid(android.os.Process.myUid()) + .build(); + + // The per-package override forces the activity into a 3:2 aspect ratio + assertEquals(1200, activity.getBounds().height()); + assertEquals(1200 / ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM_VALUE, + activity.getBounds().width(), 0.5); + + // After changing the orientation to landscape the override shouldn't be applied. + activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); + activity.clearSizeCompatMode(); + + // The per-package override should have no effect + assertEquals(1200, activity.getBounds().height()); + assertEquals(1000, activity.getBounds().width()); + } + + @Test @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM}) public void testOverrideMinAspectRatioWithoutGlobalOverride() { // In this test, only OVERRIDE_MIN_ASPECT_RATIO_1_5 is set, which has no effect without @@ -1850,7 +1946,7 @@ public class SizeCompatTests extends WindowTestsBase { // At launch. /* fixedOrientationLetterbox */ new Rect(0, 0, 700, 1400), // After 90 degree rotation. - /* sizeCompatUnscaled */ new Rect(0, 0, 700, 1400), + /* sizeCompatUnscaled */ new Rect(0, 700, 700, 2100), // After the display is resized to (700, 1400). /* sizeCompatScaled */ new Rect(0, 0, 350, 700)); } @@ -1863,7 +1959,7 @@ public class SizeCompatTests extends WindowTestsBase { // At launch. /* fixedOrientationLetterbox */ new Rect(1050, 0, 1750, 1400), // After 90 degree rotation. - /* sizeCompatUnscaled */ new Rect(350, 0, 1050, 1400), + /* sizeCompatUnscaled */ new Rect(350, 700, 1050, 2100), // After the display is resized to (700, 1400). /* sizeCompatScaled */ new Rect(525, 0, 875, 700)); } @@ -1878,7 +1974,7 @@ public class SizeCompatTests extends WindowTestsBase { // At launch. /* fixedOrientationLetterbox */ new Rect(1050, 0, 1750, 1400), // After 90 degree rotation. - /* sizeCompatUnscaled */ new Rect(350, 0, 1050, 1400), + /* sizeCompatUnscaled */ new Rect(350, 700, 1050, 2100), // After the display is resized to (700, 1400). /* sizeCompatScaled */ new Rect(525, 0, 875, 700)); @@ -1888,7 +1984,7 @@ public class SizeCompatTests extends WindowTestsBase { // At launch. /* fixedOrientationLetterbox */ new Rect(1050, 0, 1750, 1400), // After 90 degree rotation. - /* sizeCompatUnscaled */ new Rect(350, 0, 1050, 1400), + /* sizeCompatUnscaled */ new Rect(350, 700, 1050, 2100), // After the display is resized to (700, 1400). /* sizeCompatScaled */ new Rect(525, 0, 875, 700)); } @@ -1901,7 +1997,7 @@ public class SizeCompatTests extends WindowTestsBase { // At launch. /* fixedOrientationLetterbox */ new Rect(2100, 0, 2800, 1400), // After 90 degree rotation. - /* sizeCompatUnscaled */ new Rect(700, 0, 1400, 1400), + /* sizeCompatUnscaled */ new Rect(700, 700, 1400, 2100), // After the display is resized to (700, 1400). /* sizeCompatScaled */ new Rect(1050, 0, 1400, 700)); } @@ -2093,7 +2189,7 @@ public class SizeCompatTests extends WindowTestsBase { assertTrue(mActivity.inSizeCompatMode()); // Activity is in size compat mode but not scaled. - assertEquals(new Rect(0, 0, 1400, 700), mActivity.getBounds()); + assertEquals(new Rect(0, 1050, 1400, 1750), mActivity.getBounds()); } private static WindowState addWindowToActivity(ActivityRecord activity) { @@ -2126,8 +2222,7 @@ public class SizeCompatTests extends WindowTestsBase { displayContent.mWmService, mock(Session.class), new TestIWindow(), attrs, token); token.addWindow(statusBar); statusBar.setRequestedSize(displayContent.mBaseDisplayWidth, - displayContent.getDisplayUiContext().getResources().getDimensionPixelSize( - com.android.internal.R.dimen.status_bar_height)); + SystemBarUtils.getStatusBarHeight(displayContent.getDisplayUiContext())); displayPolicy.addWindowLw(statusBar, attrs); displayPolicy.layoutWindowLw(statusBar, null, displayContent.mDisplayFrames); diff --git a/services/tests/wmtests/src/com/android/server/wm/SyncEngineTests.java b/services/tests/wmtests/src/com/android/server/wm/SyncEngineTests.java index 7bac3e7b8679..420ea8e63562 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SyncEngineTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SyncEngineTests.java @@ -62,7 +62,7 @@ public class SyncEngineTests extends WindowTestsBase { public void testTrivialSyncCallback() { TestWindowContainer mockWC = new TestWindowContainer(mWm, false /* waiter */); - BLASTSyncEngine bse = new BLASTSyncEngine(mWm); + final BLASTSyncEngine bse = createTestBLASTSyncEngine(); BLASTSyncEngine.TransactionReadyListener listener = mock( BLASTSyncEngine.TransactionReadyListener.class); @@ -90,7 +90,7 @@ public class SyncEngineTests extends WindowTestsBase { public void testWaitingSyncCallback() { TestWindowContainer mockWC = new TestWindowContainer(mWm, true /* waiter */); - BLASTSyncEngine bse = new BLASTSyncEngine(mWm); + final BLASTSyncEngine bse = createTestBLASTSyncEngine(); BLASTSyncEngine.TransactionReadyListener listener = mock( BLASTSyncEngine.TransactionReadyListener.class); @@ -114,7 +114,7 @@ public class SyncEngineTests extends WindowTestsBase { public void testInvisibleSyncCallback() { TestWindowContainer mockWC = new TestWindowContainer(mWm, true /* waiter */); - BLASTSyncEngine bse = new BLASTSyncEngine(mWm); + final BLASTSyncEngine bse = createTestBLASTSyncEngine(); BLASTSyncEngine.TransactionReadyListener listener = mock( BLASTSyncEngine.TransactionReadyListener.class); @@ -142,7 +142,7 @@ public class SyncEngineTests extends WindowTestsBase { parentWC.addChild(childWC, POSITION_TOP); parentWC.addChild(childWC2, POSITION_TOP); - BLASTSyncEngine bse = new BLASTSyncEngine(mWm); + final BLASTSyncEngine bse = createTestBLASTSyncEngine(); BLASTSyncEngine.TransactionReadyListener listener = mock( BLASTSyncEngine.TransactionReadyListener.class); @@ -175,7 +175,7 @@ public class SyncEngineTests extends WindowTestsBase { TestWindowContainer childWC = new TestWindowContainer(mWm, true /* waiter */); parentWC.addChild(childWC, POSITION_TOP); - BLASTSyncEngine bse = new BLASTSyncEngine(mWm); + final BLASTSyncEngine bse = createTestBLASTSyncEngine(); BLASTSyncEngine.TransactionReadyListener listener = mock( BLASTSyncEngine.TransactionReadyListener.class); @@ -206,7 +206,7 @@ public class SyncEngineTests extends WindowTestsBase { parentWC.addChild(topChildWC, POSITION_TOP); parentWC.addChild(botChildWC, POSITION_BOTTOM); - BLASTSyncEngine bse = new BLASTSyncEngine(mWm); + final BLASTSyncEngine bse = createTestBLASTSyncEngine(); BLASTSyncEngine.TransactionReadyListener listener = mock( BLASTSyncEngine.TransactionReadyListener.class); @@ -238,7 +238,7 @@ public class SyncEngineTests extends WindowTestsBase { parentWC.addChild(topChildWC, POSITION_TOP); parentWC.addChild(botChildWC, POSITION_BOTTOM); - BLASTSyncEngine bse = new BLASTSyncEngine(mWm); + final BLASTSyncEngine bse = createTestBLASTSyncEngine(); BLASTSyncEngine.TransactionReadyListener listener = mock( BLASTSyncEngine.TransactionReadyListener.class); @@ -273,7 +273,7 @@ public class SyncEngineTests extends WindowTestsBase { parentWC.addChild(topChildWC, POSITION_TOP); nonMemberParentWC.addChild(botChildWC, POSITION_BOTTOM); - BLASTSyncEngine bse = new BLASTSyncEngine(mWm); + final BLASTSyncEngine bse = createTestBLASTSyncEngine(); BLASTSyncEngine.TransactionReadyListener listener = mock( BLASTSyncEngine.TransactionReadyListener.class); @@ -312,7 +312,7 @@ public class SyncEngineTests extends WindowTestsBase { parentWC.addChild(topChildWC, POSITION_TOP); parentWC.addChild(botChildWC, POSITION_BOTTOM); - BLASTSyncEngine bse = new BLASTSyncEngine(mWm); + final BLASTSyncEngine bse = createTestBLASTSyncEngine(); BLASTSyncEngine.TransactionReadyListener listener = mock( BLASTSyncEngine.TransactionReadyListener.class); diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java index e528a4a23e45..168c250a8c93 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java @@ -1321,6 +1321,50 @@ public class TaskLaunchParamsModifierTests extends WindowTestsBase { } @Test + public void testDefaultFreeformSizeRespectsMinAspectRatio() { + final TestDisplayContent freeformDisplay = createNewDisplayContent( + WINDOWING_MODE_FREEFORM); + + final ActivityOptions options = ActivityOptions.makeBasic(); + options.setLaunchDisplayId(freeformDisplay.mDisplayId); + + mActivity.info.applicationInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP; + mActivity.info.setMinAspectRatio(5f); + + assertEquals(RESULT_CONTINUE, + new CalculateRequestBuilder() + .setOptions(options).calculate()); + + final float aspectRatio = + (float) Math.max(mResult.mBounds.width(), mResult.mBounds.height()) + / (float) Math.min(mResult.mBounds.width(), mResult.mBounds.height()); + assertTrue("Bounds aspect ratio should be at least 5.0, but was " + aspectRatio, + aspectRatio >= 5f); + } + + @Test + public void testDefaultFreeformSizeRespectsMaxAspectRatio() { + final TestDisplayContent freeformDisplay = createNewDisplayContent( + WINDOWING_MODE_FREEFORM); + + final ActivityOptions options = ActivityOptions.makeBasic(); + options.setLaunchDisplayId(freeformDisplay.mDisplayId); + + mActivity.info.applicationInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP; + mActivity.info.setMaxAspectRatio(1.5f); + + assertEquals(RESULT_CONTINUE, + new CalculateRequestBuilder() + .setOptions(options).calculate()); + + final float aspectRatio = + (float) Math.max(mResult.mBounds.width(), mResult.mBounds.height()) + / (float) Math.min(mResult.mBounds.width(), mResult.mBounds.height()); + assertTrue("Bounds aspect ratio should be at most 1.5, but was " + aspectRatio, + aspectRatio <= 1.5f); + } + + @Test public void testCascadesToSourceSizeForFreeform() { final TestDisplayContent freeformDisplay = createNewDisplayContent( WINDOWING_MODE_FREEFORM); @@ -1348,6 +1392,72 @@ public class TaskLaunchParamsModifierTests extends WindowTestsBase { } @Test + public void testCascadesToSourceSizeForFreeformRespectingMinAspectRatio() { + final TestDisplayContent freeformDisplay = createNewDisplayContent( + WINDOWING_MODE_FREEFORM); + + final ActivityOptions options = ActivityOptions.makeBasic(); + options.setLaunchDisplayId(freeformDisplay.mDisplayId); + + final ActivityRecord source = createSourceActivity(freeformDisplay); + source.setBounds(0, 0, 412, 732); + + mActivity.info.applicationInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP; + mActivity.info.setMinAspectRatio(5f); + + assertEquals(RESULT_CONTINUE, + new CalculateRequestBuilder().setSource(source).setOptions(options).calculate()); + + final Rect displayBounds = freeformDisplay.getBounds(); + assertTrue("Left bounds should be larger than 0.", mResult.mBounds.left > 0); + assertTrue("Top bounds should be larger than 0.", mResult.mBounds.top > 0); + assertTrue("Bounds should be centered at somewhere in the left half, but it's " + + "centerX is " + mResult.mBounds.centerX(), + mResult.mBounds.centerX() < displayBounds.centerX()); + assertTrue("Bounds should be centered at somewhere in the top half, but it's " + + "centerY is " + mResult.mBounds.centerY(), + mResult.mBounds.centerY() < displayBounds.centerY()); + final float aspectRatio = + (float) Math.max(mResult.mBounds.width(), mResult.mBounds.height()) + / (float) Math.min(mResult.mBounds.width(), mResult.mBounds.height()); + assertTrue("Bounds aspect ratio should be at least 5.0, but was " + aspectRatio, + aspectRatio >= 5f); + } + + @Test + public void testCascadesToSourceSizeForFreeformRespectingMaxAspectRatio() { + final TestDisplayContent freeformDisplay = createNewDisplayContent( + WINDOWING_MODE_FREEFORM); + + final ActivityOptions options = ActivityOptions.makeBasic(); + options.setLaunchDisplayId(freeformDisplay.mDisplayId); + + final ActivityRecord source = createSourceActivity(freeformDisplay); + source.setBounds(0, 0, 412, 732); + + mActivity.info.applicationInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP; + mActivity.info.setMaxAspectRatio(1.5f); + + assertEquals(RESULT_CONTINUE, + new CalculateRequestBuilder().setSource(source).setOptions(options).calculate()); + + final Rect displayBounds = freeformDisplay.getBounds(); + assertTrue("Left bounds should be larger than 0.", mResult.mBounds.left > 0); + assertTrue("Top bounds should be larger than 0.", mResult.mBounds.top > 0); + assertTrue("Bounds should be centered at somewhere in the left half, but it's " + + "centerX is " + mResult.mBounds.centerX(), + mResult.mBounds.centerX() < displayBounds.centerX()); + assertTrue("Bounds should be centered at somewhere in the top half, but it's " + + "centerY is " + mResult.mBounds.centerY(), + mResult.mBounds.centerY() < displayBounds.centerY()); + final float aspectRatio = + (float) Math.max(mResult.mBounds.width(), mResult.mBounds.height()) + / (float) Math.min(mResult.mBounds.width(), mResult.mBounds.height()); + assertTrue("Bounds aspect ratio should be at most 1.5, but was " + aspectRatio, + aspectRatio <= 1.5f); + } + + @Test public void testAdjustBoundsToFitDisplay_TopLeftOutOfDisplay() { final TestDisplayContent freeformDisplay = createNewDisplayContent( WINDOWING_MODE_FREEFORM); diff --git a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java index acadb74d333f..9001578cf37a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java +++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java @@ -128,10 +128,6 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { } @Override - public void setKeyguardCandidateLw(WindowState win) { - } - - @Override public Animation createHiddenByKeyguardExit(boolean onWallpaper, boolean goingToNotificationShade, boolean subtleAnimation) { return null; @@ -368,7 +364,7 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { } @Override - public int applyKeyguardOcclusionChange() { + public int applyKeyguardOcclusionChange(boolean keyguardOccludingStarted) { return 0; } diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java index a1c24c26af35..4e77fa73fd09 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java @@ -21,7 +21,6 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; import static android.view.WindowManager.TRANSIT_CLOSE; -import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN; import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_TO_BACK; import static android.window.TransitionInfo.FLAG_IS_WALLPAPER; @@ -44,6 +43,7 @@ import android.os.IBinder; import android.platform.test.annotations.Presubmit; import android.util.ArrayMap; import android.util.ArraySet; +import android.view.SurfaceControl; import android.window.ITaskOrganizer; import android.window.ITransitionPlayer; import android.window.TransitionInfo; @@ -53,9 +53,12 @@ import androidx.test.filters.SmallTest; import org.junit.Test; import org.junit.runner.RunWith; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + /** * Build/Install/Run: - * atest WmTests:TransitionRecordTests + * atest WmTests:TransitionTests */ @SmallTest @Presubmit @@ -64,13 +67,13 @@ public class TransitionTests extends WindowTestsBase { private Transition createTestTransition(int transitType) { TransitionController controller = mock(TransitionController.class); - BLASTSyncEngine sync = new BLASTSyncEngine(mWm); - return new Transition(transitType, 0 /* flags */, controller, sync); + final BLASTSyncEngine sync = createTestBLASTSyncEngine(); + return new Transition(transitType, 0 /* flags */, 0 /* timeoutMs */, controller, sync); } @Test public void testCreateInfo_NewTask() { - final Transition transition = createTestTransition(TRANSIT_OLD_TASK_OPEN); + final Transition transition = createTestTransition(TRANSIT_OPEN); ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges; ArraySet<WindowContainer> participants = transition.mParticipants; @@ -88,7 +91,7 @@ public class TransitionTests extends WindowTestsBase { closing.mVisibleRequested = false; opening.mVisibleRequested = true; - int transit = TRANSIT_OLD_TASK_OPEN; + final int transit = transition.mType; int flags = 0; // Check basic both tasks participating @@ -127,7 +130,7 @@ public class TransitionTests extends WindowTestsBase { @Test public void testCreateInfo_NestedTasks() { - final Transition transition = createTestTransition(TRANSIT_OLD_TASK_OPEN); + final Transition transition = createTestTransition(TRANSIT_OPEN); ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges; ArraySet<WindowContainer> participants = transition.mParticipants; @@ -152,7 +155,7 @@ public class TransitionTests extends WindowTestsBase { opening.mVisibleRequested = true; opening2.mVisibleRequested = true; - int transit = TRANSIT_OLD_TASK_OPEN; + final int transit = transition.mType; int flags = 0; // Check full promotion from leaf @@ -177,7 +180,7 @@ public class TransitionTests extends WindowTestsBase { @Test public void testCreateInfo_DisplayArea() { - final Transition transition = createTestTransition(TRANSIT_OLD_TASK_OPEN); + final Transition transition = createTestTransition(TRANSIT_OPEN); ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges; ArraySet<WindowContainer> participants = transition.mParticipants; final Task showTask = createTask(mDisplayContent); @@ -199,7 +202,7 @@ public class TransitionTests extends WindowTestsBase { showing.mVisibleRequested = true; showing2.mVisibleRequested = true; - int transit = TRANSIT_OLD_TASK_OPEN; + final int transit = transition.mType; int flags = 0; // Check promotion to DisplayArea @@ -228,7 +231,7 @@ public class TransitionTests extends WindowTestsBase { @Test public void testCreateInfo_existenceChange() { - final Transition transition = createTestTransition(TRANSIT_OLD_TASK_OPEN); + final Transition transition = createTestTransition(TRANSIT_OPEN); final Task openTask = createTask(mDisplayContent); final ActivityRecord opening = createActivityRecord(openTask); @@ -258,7 +261,7 @@ public class TransitionTests extends WindowTestsBase { @Test public void testCreateInfo_ordering() { - final Transition transition = createTestTransition(TRANSIT_OLD_TASK_OPEN); + final Transition transition = createTestTransition(TRANSIT_OPEN); // pick some number with a high enough chance of being out-of-order when added to set. final int taskCount = 6; @@ -294,7 +297,7 @@ public class TransitionTests extends WindowTestsBase { @Test public void testCreateInfo_wallpaper() { - final Transition transition = createTestTransition(TRANSIT_OLD_TASK_OPEN); + final Transition transition = createTestTransition(TRANSIT_OPEN); // pick some number with a high enough chance of being out-of-order when added to set. final int taskCount = 4; final int showWallpaperTask = 2; @@ -345,7 +348,7 @@ public class TransitionTests extends WindowTestsBase { @Test public void testTargets_noIntermediatesToWallpaper() { - final Transition transition = createTestTransition(TRANSIT_OLD_TASK_OPEN); + final Transition transition = createTestTransition(TRANSIT_OPEN); final WallpaperWindowToken wallpaperWindowToken = new WallpaperWindowToken(mWm, mock(IBinder.class), true, mDisplayContent, true /* ownerCanManageAppTokens */); @@ -419,7 +422,7 @@ public class TransitionTests extends WindowTestsBase { openInOpen.mVisibleRequested = true; openInChange.mVisibleRequested = true; - int transit = TRANSIT_OLD_TASK_OPEN; + final int transit = transition.mType; int flags = 0; // Check full promotion from leaf @@ -450,6 +453,22 @@ public class TransitionTests extends WindowTestsBase { } @Test + public void testTimeout() { + final TransitionController controller = new TransitionController(mAtm, + mock(TaskSnapshotController.class)); + final BLASTSyncEngine sync = new BLASTSyncEngine(mWm); + final CountDownLatch latch = new CountDownLatch(1); + // When the timeout is reached, it will finish the sync-group and notify transaction ready. + new Transition(TRANSIT_OPEN, 0 /* flags */, 10 /* timeoutMs */, controller, sync) { + @Override + public void onTransactionReady(int syncId, SurfaceControl.Transaction transaction) { + latch.countDown(); + } + }; + assertTrue(awaitInWmLock(() -> latch.await(3, TimeUnit.SECONDS))); + } + + @Test public void testIntermediateVisibility() { final TaskSnapshotController snapshotController = mock(TaskSnapshotController.class); final TransitionController controller = new TransitionController(mAtm, snapshotController); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java index b2d4eea4feae..ac61bb15ab06 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -789,6 +789,15 @@ class WindowTestsBase extends SystemServiceTestsBase { }; } + BLASTSyncEngine createTestBLASTSyncEngine() { + return new BLASTSyncEngine(mWm) { + @Override + void scheduleTimeout(SyncGroup s, long timeoutMs) { + // Disable timeout. + } + }; + } + /** * Avoids rotating screen disturbed by some conditions. It is usually used for the default * display that is not the instance of {@link TestDisplayContent} (it bypasses the conditions). |