diff options
248 files changed, 4127 insertions, 1020 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..47ccf10c35d1 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"; 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/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/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/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/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/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index a817119a735f..17fdb2e7054f 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,84 @@ 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]; + + 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; + boolean mInteractive; StopwatchTimer mInteractiveTimer; @@ -4308,8 +4375,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 +4976,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 +5181,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 +5203,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 +6974,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 +11000,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 +11116,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 +11150,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 +11636,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 { diff --git a/core/java/com/android/internal/policy/IKeyguardStateCallback.aidl b/core/java/com/android/internal/policy/IKeyguardStateCallback.aidl index 419b1f8feac7..8e454db4cb04 100644 --- a/core/java/com/android/internal/policy/IKeyguardStateCallback.aidl +++ b/core/java/com/android/internal/policy/IKeyguardStateCallback.aidl @@ -20,4 +20,5 @@ interface IKeyguardStateCallback { void onSimSecureStateChanged(boolean simSecure); void onInputRestrictedStateChanged(boolean inputRestricted); void onTrustedChanged(boolean trusted); + void onHasLockscreenWallpaperChanged(boolean hasLockscreenWallpaper); }
\ No newline at end of file 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..6f81b822554a 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 { 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-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/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java index d76037eb1cab..e95f6c294633 100644 --- a/core/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java @@ -47,13 +47,13 @@ public class AmbientDisplayPowerCalculatorTest { stats.updateDisplayMeasuredEnergyStatsLocked(300_000_000, 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.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, @@ -78,9 +78,9 @@ public class AmbientDisplayPowerCalculatorTest { 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 = 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..4adc09d72e94 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 @@ -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/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..73f4eb2d2be8 100644 --- a/core/tests/coretests/src/com/android/internal/os/ScreenPowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/ScreenPowerCalculatorTest.java @@ -53,7 +53,7 @@ public class ScreenPowerCalculatorTest { mStatsRule.initMeasuredEnergyStatsLocked(); BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats(); - batteryStats.noteScreenStateLocked(Display.STATE_ON, 0, 0, 0); + batteryStats.noteScreenStateLocked(0, Display.STATE_ON, 0, 0, 0); batteryStats.updateDisplayMeasuredEnergyStatsLocked(0, Display.STATE_ON, 0); setProcState(APP_UID1, ActivityManager.PROCESS_STATE_TOP, true, 0, 0); @@ -70,7 +70,7 @@ public class ScreenPowerCalculatorTest { batteryStats.updateDisplayMeasuredEnergyStatsLocked(300_000_000, 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); @@ -133,20 +133,20 @@ public class ScreenPowerCalculatorTest { 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); 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/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/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java index 0d5271924375..ec71fbee9a29 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,11 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, options = mStageCoordinator.resolveStartStage(stage, position, options, null /* wct */); try { - ActivityTaskManager.getService().startActivityFromRecents(taskId, options); + final int result = + ActivityTaskManager.getService().startActivityFromRecents(taskId, options); + if (result == START_SUCCESS || result == START_TASK_TO_FRONT) { + mStageCoordinator.evictOccludedChildren(position); + } } catch (RemoteException e) { Slog.e(TAG, "Failed to launch task", e); } @@ -229,6 +235,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, mContext.getSystemService(LauncherApps.class); launcherApps.startShortcut(packageName, shortcutId, null /* sourceBounds */, options, user); + mStageCoordinator.evictOccludedChildren(position); } catch (ActivityNotFoundException e) { Slog.e(TAG, "Failed to launch shortcut", e); } @@ -272,6 +279,10 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, Slog.e(TAG, "Error finishing legacy transition: ", e); } } + + // Launching a new app into a specific split evicts tasks previously in the same + // split. + mStageCoordinator.evictOccludedChildren(position); } }; WindowContainerTransaction wct = new WindowContainerTransaction(); 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 3e74ad38f1f1..0cff18e2ba85 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 @@ -394,6 +394,12 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE, wct, remoteTransition, this); } + void evictOccludedChildren(@SplitPosition int position) { + final WindowContainerTransaction wct = new WindowContainerTransaction(); + (position == mSideStagePosition ? mSideStage : mMainStage).evictOccludedChildren(wct); + mTaskOrganizer.applyTransaction(wct); + } + Bundle resolveStartStage(@SplitScreen.StageType int stage, @SplitPosition int position, @androidx.annotation.Nullable Bundle options, @androidx.annotation.Nullable WindowContainerTransaction wct) { @@ -471,7 +477,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(); @@ -799,13 +805,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 +870,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 +908,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..071badf2bc23 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,15 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener { wct.reorder(mChildrenTaskInfo.get(taskId).token, onTop /* onTop */); } + void evictOccludedChildren(WindowContainerTransaction wct) { + for (int i = mChildrenTaskInfo.size() - 1; i >= 0; i--) { + final ActivityManager.RunningTaskInfo taskInfo = mChildrenTaskInfo.valueAt(i); + if (!taskInfo.isVisible) { + 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/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/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/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/splitscreen/StageCoordinatorTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java index aeb2849b49b3..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 @@ -133,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); @@ -145,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/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/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/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-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/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/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 e983818ef040..17b13a235805 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/flags/Flags.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/flags/Flags.java @@ -16,6 +16,10 @@ 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. * @@ -26,4 +30,39 @@ package com.android.systemui.flags; */ public class Flags { public static final BooleanFlag THE_FIRST_FLAG = new BooleanFlag(1, false); + + + // 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/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/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/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index 522fcb299f96..ddb6b8f5c82b 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> diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index 432c557dc150..d56c3fd912ee 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> diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index 2728c980ad73..4f663562328d 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> diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml index e8158f12ee5a..3015ccd39949 100644 --- a/packages/SystemUI/res/values-as/strings.xml +++ b/packages/SystemUI/res/values-as/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> diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml index 02032883f9f0..dad7adde8b27 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> diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml index 60dee9e31fd8..1761205ba4b3 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> diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml index f234be4b020a..8bfc32fbfa61 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> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index 170a565419d3..d9d06dc1f1e4 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> diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml index f4b1935bfe7d..4ba14369746d 100644 --- a/packages/SystemUI/res/values-bn/strings.xml +++ b/packages/SystemUI/res/values-bn/strings.xml @@ -1090,6 +1090,8 @@ <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> + <!-- no translation found for controls_media_seekbar_description (4389621713616214611) --> + <skip /> <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> diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml index 4f5db012b0e9..95bca335e7b0 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> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index ace47913916e..2ca9897d325e 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> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index f4c055d18959..bb205bfaaa50 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> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index 3a6030e6b7fb..1a251d26b4ce 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> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index be501ca32eb1..ce469d57aa43 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -1090,6 +1090,8 @@ <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> + <!-- no translation found for controls_media_seekbar_description (4389621713616214611) --> + <skip /> <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> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index 145c72d3d83c..2fa648cbb1c7 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> diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml index 590033a632dc..84b24d68fa08 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> diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml index ca7099fcc4cd..c435a8367e68 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> diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml index 590033a632dc..84b24d68fa08 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> diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml index 590033a632dc..84b24d68fa08 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> diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml index 1a26024323af..1ed76dc1ddb5 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> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index bfe22c20c69d..4875e63614b8 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> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index 762c1bed1580..af328945b1b4 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> diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml index 04874d21f35d..ebab6f3825a7 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> diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml index 5c6fc3b0591d..0d5898653826 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> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index ae8fab633bce..dfc88f4b4258 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -1090,6 +1090,8 @@ <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> + <!-- no translation found for controls_media_seekbar_description (4389621713616214611) --> + <skip /> <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> diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index 9bd16bdfef60..c62f66401345 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -1090,6 +1090,8 @@ <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> + <!-- no translation found for controls_media_seekbar_description (4389621713616214611) --> + <skip /> <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> diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml index d8b312fc6468..0f60249c8871 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> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index e897a699f9c1..c31ccafc51c8 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,8 @@ <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> + <!-- no translation found for controls_media_seekbar_description (4389621713616214611) --> + <skip /> <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> diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml index 328ac9c00140..002f0a1a415e 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> diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml index 3524d85464dc..cf001fc70231 100644 --- a/packages/SystemUI/res/values-gu/strings.xml +++ b/packages/SystemUI/res/values-gu/strings.xml @@ -1090,6 +1090,8 @@ <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> + <!-- no translation found for controls_media_seekbar_description (4389621713616214611) --> + <skip /> <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> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index 3aec1f4d4bca..143152e41444 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> diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index 0b899030923e..206f297a31b2 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> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index 573fa6e64a6a..ab91233d974f 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> diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml index c6be8c0ff3a4..7638843141ca 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> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index 53c7e264b7bd..17456903d0b3 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> diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml index 76953ef56002..100b6f2f5bda 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> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index d2467b183c6b..15598f000ecb 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> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index b4566e891312..9f019b49345b 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> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index 34f9c0ca89c7..94dbd0e10354 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> diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml index bead5fea3c93..889ce247fea2 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> diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml index 14e84565617f..b4f1d926587d 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> diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml index 9bcc41a7b8eb..3896eb063a36 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> diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml index cad8abb00467..9d908841c849 100644 --- a/packages/SystemUI/res/values-kn/strings.xml +++ b/packages/SystemUI/res/values-kn/strings.xml @@ -1090,6 +1090,8 @@ <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> + <!-- no translation found for controls_media_seekbar_description (4389621713616214611) --> + <skip /> <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> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index 6541cbfddbb3..4ca855d1d77d 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> diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml index 1c6f3bee6934..77a933cc8c42 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> diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml index dfe591625561..351b19828f5f 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> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index 57af3864216f..3e4d3ffbe1ba 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> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index ced02b34b9b0..f0d1bba3382d 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> diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml index 7b54b631ff33..29feaecc8bf6 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> diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml index 6e924aa32ee0..674ed8492704 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> diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml index 55126596f655..9cce14ab25e3 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> diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml index 2864f326c8c8..9753209792cc 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> diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml index 96c7f893c9df..4418273f7399 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> diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml index 1d521dcad5d6..0fed37b454db 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> diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index 32a37400deb7..c37c81c2b48a 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -1090,6 +1090,8 @@ <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> + <!-- no translation found for controls_media_seekbar_description (4389621713616214611) --> + <skip /> <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> diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml index 8b50929baa81..2405d5038ba7 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> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index 2c9b459f9b17..b60a76dbab40 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> diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml index a69c9a90e9d2..f276a227941f 100644 --- a/packages/SystemUI/res/values-or/strings.xml +++ b/packages/SystemUI/res/values-or/strings.xml @@ -1090,6 +1090,8 @@ <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> + <!-- no translation found for controls_media_seekbar_description (4389621713616214611) --> + <skip /> <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> diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml index 72882633541a..0ca4f7dd06e5 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> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index b7fc15df8b55..73b538f3f20b 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> diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml index ceb6ff58da96..0205e8cbbc86 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> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index a103e416c947..3be4e7238742 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> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index ceb6ff58da96..0205e8cbbc86 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> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index dba5b7db65c1..9630356d6efc 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> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index 808cb54d5af2..a386d5ad8a8a 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> diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml index a81292ca95e5..ec03c53afb50 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> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index a2cb0d6d8e08..dd4721925649 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> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index 5092c030ae0b..b55c92371c27 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> diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml index adb773d168ed..b728cf2ed144 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> diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index a3f85c97801d..8658df620599 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> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index 6073c7d1a49d..e1ecff9680b8 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> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index 5856a61924b4..7b2f28761703 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> diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml index 8daa24f4731a..815a6f02d4fe 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> diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml index cab7b1c80ef2..b1639ff0c997 100644 --- a/packages/SystemUI/res/values-te/strings.xml +++ b/packages/SystemUI/res/values-te/strings.xml @@ -1090,6 +1090,8 @@ <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> + <!-- no translation found for controls_media_seekbar_description (4389621713616214611) --> + <skip /> <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> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index 6da88882859f..a551b19a2b96 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> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index a9c588699311..b8604abba62f 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> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index 8fe7862d1469..393cbee2f864 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> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index 596ba953844e..0dd178aa5d7b 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> diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml index f05c709d131b..bb2409da9d29 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> diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml index e9c20a92219f..afea9f47cd8a 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> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index 07a08ad1270c..15abead8f034 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> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index 377d15cba0e3..74b1a3996620 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> diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml index 73df468c1aa2..28e0ae9d1780 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> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index f883b1091f7b..1b07cfd2de11 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> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index e1c1f6fa219b..19e35eff0434 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> 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/src-debug/com/android/systemui/flags/FeatureFlagManager.java b/packages/SystemUI/src-debug/com/android/systemui/flags/FeatureFlagManager.java index b84c7bf0bd5f..2ed632876b06 100644 --- a/packages/SystemUI/src-debug/com/android/systemui/flags/FeatureFlagManager.java +++ b/packages/SystemUI/src-debug/com/android/systemui/flags/FeatureFlagManager.java @@ -16,32 +16,55 @@ 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.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; @Inject - public FeatureFlagManager(SystemPropertiesHelper systemPropertiesHelper) { + public FeatureFlagManager(SystemPropertiesHelper systemPropertiesHelper, Context context) { mSystemPropertiesHelper = systemPropertiesHelper; + + IntentFilter filter = new IntentFilter(ACTION_SET_FLAG); + context.registerReceiver(mReceiver, filter, FLAGS_PERMISSION, null); } /** Return a {@link BooleanFlag}'s value. */ - public boolean isEnabled(int key, boolean defaultValue) { - String data = mSystemPropertiesHelper.get(keyToSysPropKey(key)); + public boolean isEnabled(int id, boolean defaultValue) { + String data = mSystemPropertiesHelper.get(keyToSysPropKey(id)); if (data.isEmpty()) { return defaultValue; } @@ -53,22 +76,31 @@ public class FeatureFlagManager implements FlagReader, FlagWriter { } return json.getBoolean(FIELD_VALUE); } catch (JSONException e) { - // TODO: delete the property + eraseFlag(id); return defaultValue; } } - public void setEnabled(int key, boolean value) { + /** Set whether a given {@link BooleanFlag} is enabled or not. */ + public void setEnabled(int id, boolean value) { JSONObject json = new JSONObject(); try { json.put(FIELD_TYPE, TYPE_BOOLEAN); json.put(FIELD_VALUE, value); - mSystemPropertiesHelper.set(keyToSysPropKey(key), json.toString()); + mSystemPropertiesHelper.set(keyToSysPropKey(id), json.toString()); + Log.i(TAG, "Set id " + id + " to " + value); } catch (JSONException e) { // no-op } } + /** Erase a flag's overridden value if there is one. */ + public void eraseFlag(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) {} @@ -85,4 +117,41 @@ public class FeatureFlagManager implements FlagReader, FlagWriter { } } + 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/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index 5707fa7b18d7..4e35aed8e859 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; @@ -271,6 +272,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab private boolean mBouncer; // true if bouncerIsOrWillBeShowing private boolean mAuthInterruptActive; private boolean mNeedsSlowUnlockTransition; + private boolean mHasLockscreenWallpaper; private boolean mAssistantVisible; private boolean mKeyguardOccluded; private boolean mOccludingAppRequestingFp; @@ -313,6 +315,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 +1742,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 +1752,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab mBackgroundExecutor = backgroundExecutor; mBroadcastDispatcher = broadcastDispatcher; mInteractionJankMonitor = interactionJankMonitor; + mLatencyTracker = latencyTracker; mRingerModeTracker = ringerModeTracker; mStatusBarStateController = statusBarStateController; mStatusBarStateController.addCallback(mStatusBarStateControllerListener); @@ -2532,6 +2536,31 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } /** + * Update the state whether Keyguard currently has a lockscreen wallpaper. + * + * @param hasLockscreenWallpaper Whether Keyguard has a lockscreen wallpaper. + */ + public void setHasLockscreenWallpaper(boolean hasLockscreenWallpaper) { + Assert.isMainThread(); + if (hasLockscreenWallpaper != mHasLockscreenWallpaper) { + mHasLockscreenWallpaper = hasLockscreenWallpaper; + for (int i = 0; i < mCallbacks.size(); i++) { + KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); + if (cb != null) { + cb.onHasLockscreenWallpaperChanged(hasLockscreenWallpaper); + } + } + } + } + + /** + * @return Whether Keyguard has a lockscreen wallpaper. + */ + public boolean hasLockscreenWallpaper() { + return mHasLockscreenWallpaper; + } + + /** * Handle {@link #MSG_DPM_STATE_CHANGED} */ private void handleDevicePolicyManagerStateChanged(int userId) { @@ -2579,6 +2608,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/KeyguardUpdateMonitorCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java index 12431984c9b9..1e951f923f13 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java @@ -292,6 +292,11 @@ public class KeyguardUpdateMonitorCallback { public void onStrongAuthStateChanged(int userId) { } /** + * Called when the state whether we have a lockscreen wallpaper has changed. + */ + public void onHasLockscreenWallpaperChanged(boolean hasLockscreenWallpaper) { } + + /** * Called when the dream's window state is changed. * @param dreaming true if the dream's window has been created and is visible */ 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/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..aac03f8551fc 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java @@ -30,6 +30,7 @@ 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 +97,9 @@ public interface SysUIComponent { Builder setStartingSurface(Optional<StartingSurface> s); @BindsInstance + Builder setDisplayAreaHelper(Optional<DisplayAreaHelper> h); + + @BindsInstance Builder setTaskSurfaceHelper(Optional<TaskSurfaceHelper> t); SysUIComponent build(); 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/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java index a5dd6a11c388..3c580791879b 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java @@ -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/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 784346e59721..be84a82234a1 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; @@ -670,6 +673,13 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable, } } } + + @Override + public void onHasLockscreenWallpaperChanged(boolean hasLockscreenWallpaper) { + synchronized (KeyguardViewMediator.this) { + notifyHasLockscreenWallpaperChanged(hasLockscreenWallpaper); + } + } }; ViewMediatorCallback mViewMediatorCallback = new ViewMediatorCallback() { @@ -808,6 +818,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 +844,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 +879,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 +2563,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 +2611,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 +2769,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); } @@ -2860,6 +2899,21 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable, } } + private void notifyHasLockscreenWallpaperChanged(boolean hasLockscreenWallpaper) { + int size = mKeyguardStateCallbacks.size(); + for (int i = size - 1; i >= 0; i--) { + try { + mKeyguardStateCallbacks.get(i).onHasLockscreenWallpaperChanged( + hasLockscreenWallpaper); + } catch (RemoteException e) { + Slog.w(TAG, "Failed to call onHasLockscreenWallpaperChanged", e); + if (e instanceof DeadObjectException) { + mKeyguardStateCallbacks.remove(i); + } + } + } + } + public void addStateMonitorCallback(IKeyguardStateCallback callback) { synchronized (this) { mKeyguardStateCallbacks.add(callback); @@ -2869,6 +2923,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable, callback.onInputRestrictedStateChanged(mInputRestricted); callback.onTrustedChanged(mUpdateMonitor.getUserHasTrust( KeyguardUpdateMonitor.getCurrentUser())); + callback.onHasLockscreenWallpaperChanged(mUpdateMonitor.hasLockscreenWallpaper()); } catch (RemoteException e) { Slog.w(TAG, "Failed to call to IKeyguardStateCallback", e); } 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 8a383b974d77..11d4aac9dc27 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java @@ -55,6 +55,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; import com.android.systemui.util.settings.GlobalSettings; @@ -99,6 +101,8 @@ public class KeyguardModule { NavigationModeController navigationModeController, KeyguardDisplayManager keyguardDisplayManager, DozeParameters dozeParameters, + UnfoldTransitionConfig unfoldTransitionConfig, + Lazy<UnfoldLightRevealOverlayAnimation> unfoldLightRevealOverlayAnimation, SysuiStatusBarStateController statusBarStateController, KeyguardStateController keyguardStateController, Lazy<KeyguardUnlockAnimationController> keyguardUnlockAnimationController, @@ -121,6 +125,8 @@ public class KeyguardModule { navigationModeController, keyguardDisplayManager, dozeParameters, + unfoldTransitionConfig, + unfoldLightRevealOverlayAnimation, statusBarStateController, keyguardStateController, keyguardUnlockAnimationController, 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/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/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/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/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index 278f09b45b4c..c06d877751e1 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 @@ -4287,7 +4287,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable @ShadeViewRefactor(RefactorComponent.COORDINATOR) void setIntrinsicPadding(int intrinsicPadding) { mIntrinsicPadding = intrinsicPadding; - mAmbientState.setIntrinsicPadding(intrinsicPadding); } @ShadeViewRefactor(RefactorComponent.COORDINATOR) 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..7cbe78f16ceb 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,6 +24,8 @@ import android.util.MathUtils; import android.view.View; import android.view.ViewGroup; +import androidx.annotation.VisibleForTesting; + import com.android.systemui.R; import com.android.systemui.animation.Interpolators; import com.android.systemui.statusbar.NotificationShelf; @@ -54,8 +56,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 +76,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 = res.getDimensionPixelSize(R.dimen.status_bar_height); + mHeadsUpInset = statusBarHeight + res.getDimensionPixelSize( R.dimen.heads_up_status_bar_padding); mPinnedZTranslationExtra = res.getDimensionPixelSize( R.dimen.heads_up_pinned_elevation); @@ -562,13 +563,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 +604,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/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/LockscreenWallpaper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java index 2a13e6bbd37e..78fcd82dc1f5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java @@ -119,6 +119,7 @@ public class LockscreenWallpaper extends IWallpaperManagerCallback.Stub implemen LoaderResult result = loadBitmap(mCurrentUserId, mSelectedUser); if (result.success) { mCached = true; + mUpdateMonitor.setHasLockscreenWallpaper(result.bitmap != null); mCache = result.bitmap; } return mCache; @@ -234,6 +235,7 @@ public class LockscreenWallpaper extends IWallpaperManagerCallback.Stub implemen if (result.success) { mCached = true; mCache = result.bitmap; + mUpdateMonitor.setHasLockscreenWallpaper(result.bitmap != null); mMediaManager.updateMediaMetaData( true /* metaDataChanged */, true /* allowEnterAnimation */); } 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 8c8e4e7e8631..54a61402b311 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java @@ -1011,6 +1011,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); 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..2bdb0edc4398 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -3292,6 +3292,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(); } 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..5bfb2361d4a1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt @@ -179,6 +179,11 @@ class StatusBarContentInsetsProvider @Inject constructor( 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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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..6374d34294d5 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,7 +669,8 @@ 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. + // TODO (b/194107383): pass all display ordinals to mStats with + // displayScreenStates final long primaryDisplayChargeUC = displayChargeUC[0]; // If updating, pass in what BatteryExternalStatsWorker thinks screenState is. mStats.updateDisplayMeasuredEnergyStatsLocked(primaryDisplayChargeUC, 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/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/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 5b6bf1510bf2..7e5fe08d022f 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -47,6 +47,7 @@ import static android.view.KeyEvent.KEYCODE_VOLUME_UP; import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW; import static android.view.WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW; +import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW; @@ -1813,18 +1814,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 +3052,29 @@ 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); @@ -3268,7 +3276,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override public void setKeyguardCandidateLw(WindowState win) { mKeyguardCandidate = win; - setKeyguardOccludedLw(isKeyguardOccluded(), true /* force */); + setKeyguardOccludedLw(isKeyguardOccluded(), true /* force */, + false /* keyguardOccludingStarted */); } /** @@ -3277,9 +3286,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { * @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); if (isKeyguardOccluded() == isOccluded && !force) { return false; @@ -3287,8 +3298,23 @@ public class PhoneWindowManager implements WindowManagerPolicy { final boolean showing = mKeyguardDelegate.isShowing(); final boolean animate = showing && !isOccluded; - mKeyguardDelegate.setOccluded(isOccluded, animate); - return showing; + // 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); + if (!showing) { + return false; + } + if (mKeyguardCandidate != null) { + if (isOccluded) { + mKeyguardCandidate.getAttrs().flags &= ~FLAG_SHOW_WALLPAPER; + } else if (!mKeyguardDelegate.hasLockscreenWallpaper()) { + mKeyguardCandidate.getAttrs().flags |= FLAG_SHOW_WALLPAPER; + } + } + return true; } /** {@inheritDoc} */ diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java index 78b03b2b88e7..c3ec6a4ab6b5 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 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..8978fabbb9d2 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; @@ -235,6 +234,13 @@ public class KeyguardServiceDelegate { return false; } + public boolean hasLockscreenWallpaper() { + if (mKeyguardService != null) { + return mKeyguardService.hasLockscreenWallpaper(); + } + return false; + } + public boolean hasKeyguard() { return mKeyguardState.deviceHasKeyguard; } @@ -252,13 +258,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/policy/keyguard/KeyguardServiceWrapper.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java index ac650ec0f564..051f555fab95 100644 --- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java +++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java @@ -261,6 +261,10 @@ public class KeyguardServiceWrapper implements IKeyguardService { return mKeyguardStateMonitor.isTrusted(); } + public boolean hasLockscreenWallpaper() { + return mKeyguardStateMonitor.hasLockscreenWallpaper(); + } + public boolean isSecure(int userId) { return mKeyguardStateMonitor.isSecure(userId); } diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java index e6511372d62c..add0b01f1879 100644 --- a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java +++ b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java @@ -44,6 +44,7 @@ public class KeyguardStateMonitor extends IKeyguardStateCallback.Stub { private volatile boolean mSimSecure = true; private volatile boolean mInputRestricted = true; private volatile boolean mTrusted = false; + private volatile boolean mHasLockscreenWallpaper = false; private int mCurrentUserId; @@ -78,6 +79,10 @@ public class KeyguardStateMonitor extends IKeyguardStateCallback.Stub { return mTrusted; } + public boolean hasLockscreenWallpaper() { + return mHasLockscreenWallpaper; + } + @Override // Binder interface public void onShowingStateChanged(boolean showing) { mIsShowing = showing; @@ -105,6 +110,11 @@ public class KeyguardStateMonitor extends IKeyguardStateCallback.Stub { mCallback.onTrustedChanged(); } + @Override // Binder interface + public void onHasLockscreenWallpaperChanged(boolean hasLockscreenWallpaper) { + mHasLockscreenWallpaper = hasLockscreenWallpaper; + } + public interface StateCallback { void onTrustedChanged(); void onShowingChanged(); 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/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/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index aaca58ef4ac0..2f88a9800f90 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -297,7 +297,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 +329,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 +1104,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() { diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index c09db1e6fa98..50c56de49134 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -618,7 +618,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(); @@ -898,6 +899,15 @@ public class DisplayPolicy { // letterboxed. Hence always let them extend under the cutout. attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; break; + case TYPE_NOTIFICATION_SHADE: + // If the Keyguard is in a hidden state (occluded by another window), we force to + // remove the wallpaper and keyguard flag so that any change in-flight after setting + // the keyguard as occluded wouldn't set these flags again. + // See {@link #processKeyguardSetHiddenResultLw}. + if (mService.mPolicy.isKeyguardOccluded()) { + attrs.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; + } + break; case TYPE_TOAST: // While apps should use the dedicated toast APIs to add such windows 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/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java index e31a6620187a..d543c1f756c9 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(); + 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..8bd62576bd3f 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -789,7 +789,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..b849170d8f3f 100644 --- a/services/core/java/com/android/server/wm/TransitionController.java +++ b/services/core/java/com/android/server/wm/TransitionController.java @@ -388,9 +388,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); } } 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/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..4cde0489bba3 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -2583,17 +2583,13 @@ public class WindowManagerService extends IWindowManager.Stub // an exit. win.mAnimatingExit = true; } else if (win.mDisplayContent.okToAnimate() - && win.mDisplayContent.mWallpaperController.isWallpaperTarget(win) - && 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 - // the client view visibility only after both NotificationShade and the wallpaper are - // hidden. So we don't need to care about exit animation, but can destroy its surface - // immediately. + && win.mDisplayContent.mWallpaperController.isWallpaperTarget(win)) { + // If the wallpaper is currently behind this + // window, we need to change both of them inside + // of a transaction to avoid artifacts. win.mAnimatingExit = true; } else { - boolean stopped = win.mActivityRecord == null || win.mActivityRecord.mAppStopped; + boolean stopped = win.mActivityRecord != null ? win.mActivityRecord.mAppStopped : true; // We set mDestroying=true so ActivityRecord#notifyAppStopped in-to destroy surfaces // will later actually destroy the surface if we do not do so here. Normally we leave // this to the exit animation. @@ -6422,6 +6418,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/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/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/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/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/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..16d75ca884f1 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java +++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java @@ -368,7 +368,7 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { } @Override - public int applyKeyguardOcclusionChange() { + public int applyKeyguardOcclusionChange(boolean keyguardOccludingStarted) { return 0; } |