diff options
204 files changed, 4714 insertions, 1893 deletions
diff --git a/core/java/android/animation/AnimationHandler.java b/core/java/android/animation/AnimationHandler.java index 19606c16cb70..df8a50a1fa5c 100644 --- a/core/java/android/animation/AnimationHandler.java +++ b/core/java/android/animation/AnimationHandler.java @@ -19,10 +19,10 @@ package android.animation; import android.os.SystemClock; import android.os.SystemProperties; import android.util.ArrayMap; -import android.util.ArraySet; import android.util.Log; import android.view.Choreographer; +import java.lang.ref.WeakReference; import java.util.ArrayList; /** @@ -40,7 +40,7 @@ import java.util.ArrayList; public class AnimationHandler { private static final String TAG = "AnimationHandler"; - private static final boolean LOCAL_LOGV = true; + private static final boolean LOCAL_LOGV = false; /** * Internal per-thread collections used to avoid set collisions as animations start and end @@ -78,7 +78,7 @@ public class AnimationHandler { * store visible (foreground) requestors; if the set size reaches zero, there are no * objects in the foreground and it is time to pause animators. */ - private final ArraySet<Object> mAnimatorRequestors = new ArraySet<>(); + private final ArrayList<WeakReference<Object>> mAnimatorRequestors = new ArrayList<>(); private final Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() { @Override @@ -141,24 +141,9 @@ public class AnimationHandler { * tracking obsolete+enabled requestors. */ public static void removeRequestor(Object requestor) { - getInstance().removeRequestorImpl(requestor); - } - - private void removeRequestorImpl(Object requestor) { - // Also request disablement, in case that requestor was the sole object keeping - // animators un-paused - long startTime = System.nanoTime(); - requestAnimatorsEnabled(false, requestor); - Log.d(TAG, "removeRequestorImpl called requestAnimatorsEnabled after " + - (System.nanoTime() - startTime)); - mAnimatorRequestors.remove(requestor); - Log.d(TAG, "removeRequestorImpl removed requestor after " + - (System.nanoTime() - startTime)); + getInstance().requestAnimatorsEnabledImpl(false, requestor); if (LOCAL_LOGV) { - Log.v(TAG, "removeRequestorImpl for " + requestor); - for (int i = 0; i < mAnimatorRequestors.size(); ++i) { - Log.v(TAG, "animatorRequesters " + i + " = " + mAnimatorRequestors.valueAt(i)); - } + Log.v(TAG, "removeRequestor for " + requestor); } } @@ -176,25 +161,44 @@ public class AnimationHandler { } private void requestAnimatorsEnabledImpl(boolean enable, Object requestor) { - long startTime = System.nanoTime(); boolean wasEmpty = mAnimatorRequestors.isEmpty(); setAnimatorPausingEnabled(isPauseBgAnimationsEnabledInSystemProperties()); - Log.d(TAG, "requestAnimatorsEnabledImpl called setAnimatorPausingEnabled after " + - (System.nanoTime() - startTime)); - if (enable) { - mAnimatorRequestors.add(requestor); - } else { - mAnimatorRequestors.remove(requestor); + synchronized (mAnimatorRequestors) { + // Only store WeakRef objects to avoid leaks + if (enable) { + // First, check whether such a reference is already on the list + WeakReference<Object> weakRef = null; + for (int i = mAnimatorRequestors.size() - 1; i >= 0; --i) { + WeakReference<Object> ref = mAnimatorRequestors.get(i); + Object referent = ref.get(); + if (referent == requestor) { + weakRef = ref; + } else if (referent == null) { + // Remove any reference that has been cleared + mAnimatorRequestors.remove(i); + } + } + if (weakRef == null) { + weakRef = new WeakReference<>(requestor); + mAnimatorRequestors.add(weakRef); + } + } else { + for (int i = mAnimatorRequestors.size() - 1; i >= 0; --i) { + WeakReference<Object> ref = mAnimatorRequestors.get(i); + Object referent = ref.get(); + if (referent == requestor || referent == null) { + // remove requested item or item that has been cleared + mAnimatorRequestors.remove(i); + } + } + // If a reference to the requestor wasn't in the list, nothing to remove + } } - Log.d(TAG, "requestAnimatorsEnabledImpl added/removed after " + - (System.nanoTime() - startTime)); if (!sAnimatorPausingEnabled) { // Resume any animators that have been paused in the meantime, otherwise noop // Leave logic above so that if pausing gets re-enabled, the state of the requestors // list is valid resumeAnimators(); - Log.d(TAG, "requestAnimatorsEnabledImpl resumed, returning after " + - (System.nanoTime() - startTime)); return; } boolean isEmpty = mAnimatorRequestors.isEmpty(); @@ -209,12 +213,13 @@ public class AnimationHandler { Animator.getBackgroundPauseDelay()); } } - Log.d(TAG, "requestAnimatorsEnabledImpl post was/is check after " + - (System.nanoTime() - startTime)); if (LOCAL_LOGV) { - Log.v(TAG, enable ? "enable" : "disable" + " animators for " + requestor); + Log.v(TAG, (enable ? "enable" : "disable") + " animators for " + requestor + + " with pauseDelay of " + Animator.getBackgroundPauseDelay()); for (int i = 0; i < mAnimatorRequestors.size(); ++i) { - Log.v(TAG, "animatorRequesters " + i + " = " + mAnimatorRequestors.valueAt(i)); + Log.v(TAG, "animatorRequestors " + i + " = " + + mAnimatorRequestors.get(i) + " with referent " + + mAnimatorRequestors.get(i).get()); } } } diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java index 13fc2e6977ea..3c0a724b9ff7 100644 --- a/core/java/android/app/StatusBarManager.java +++ b/core/java/android/app/StatusBarManager.java @@ -511,10 +511,26 @@ public class StatusBarManager { @SystemApi public static final int MEDIA_TRANSFER_RECEIVER_STATE_FAR_FROM_SENDER = 1; + /** + * State indicating that media transfer to this receiver device is succeeded. + * + * @hide + */ + public static final int MEDIA_TRANSFER_RECEIVER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED = 2; + + /** + * State indicating that media transfer to this receiver device is failed. + * + * @hide + */ + public static final int MEDIA_TRANSFER_RECEIVER_STATE_TRANSFER_TO_RECEIVER_FAILED = 3; + /** @hide */ @IntDef(prefix = {"MEDIA_TRANSFER_RECEIVER_STATE_"}, value = { MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER, MEDIA_TRANSFER_RECEIVER_STATE_FAR_FROM_SENDER, + MEDIA_TRANSFER_RECEIVER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED, + MEDIA_TRANSFER_RECEIVER_STATE_TRANSFER_TO_RECEIVER_FAILED, }) @Retention(RetentionPolicy.SOURCE) public @interface MediaTransferReceiverState {} diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java index b0b3e9e743cf..ff80ffdadff0 100644 --- a/core/java/android/hardware/display/DisplayManagerInternal.java +++ b/core/java/android/hardware/display/DisplayManagerInternal.java @@ -427,9 +427,6 @@ public abstract class DisplayManagerInternal { // 1 (brighter). Set to Float.NaN if there's no override. public float screenAutoBrightnessAdjustmentOverride; - // If true, enables automatic brightness control. - public boolean useAutoBrightness; - // If true, scales the brightness to a fraction of desired (as defined by // screenLowPowerBrightnessFactor). public boolean lowPowerMode; @@ -459,7 +456,6 @@ public abstract class DisplayManagerInternal { policy = POLICY_BRIGHT; useProximitySensor = false; screenBrightnessOverride = PowerManager.BRIGHTNESS_INVALID_FLOAT; - useAutoBrightness = false; screenAutoBrightnessAdjustmentOverride = Float.NaN; screenLowPowerBrightnessFactor = 0.5f; blockScreenOn = false; @@ -483,7 +479,6 @@ public abstract class DisplayManagerInternal { policy = other.policy; useProximitySensor = other.useProximitySensor; screenBrightnessOverride = other.screenBrightnessOverride; - useAutoBrightness = other.useAutoBrightness; screenAutoBrightnessAdjustmentOverride = other.screenAutoBrightnessAdjustmentOverride; screenLowPowerBrightnessFactor = other.screenLowPowerBrightnessFactor; blockScreenOn = other.blockScreenOn; @@ -505,7 +500,6 @@ public abstract class DisplayManagerInternal { && useProximitySensor == other.useProximitySensor && floatEquals(screenBrightnessOverride, other.screenBrightnessOverride) - && useAutoBrightness == other.useAutoBrightness && floatEquals(screenAutoBrightnessAdjustmentOverride, other.screenAutoBrightnessAdjustmentOverride) && screenLowPowerBrightnessFactor @@ -531,7 +525,6 @@ public abstract class DisplayManagerInternal { return "policy=" + policyToString(policy) + ", useProximitySensor=" + useProximitySensor + ", screenBrightnessOverride=" + screenBrightnessOverride - + ", useAutoBrightness=" + useAutoBrightness + ", screenAutoBrightnessAdjustmentOverride=" + screenAutoBrightnessAdjustmentOverride + ", screenLowPowerBrightnessFactor=" + screenLowPowerBrightnessFactor diff --git a/core/java/android/service/autofill/FillRequest.java b/core/java/android/service/autofill/FillRequest.java index 1507c87c0452..6e6dac5766e9 100644 --- a/core/java/android/service/autofill/FillRequest.java +++ b/core/java/android/service/autofill/FillRequest.java @@ -111,6 +111,12 @@ public final class FillRequest implements Parcelable { */ public static final @RequestFlags int FLAG_IME_SHOWING = 0x80; + /** + * Indicates whether autofill session should reset the fill dialog state. + * @hide + */ + public static final @RequestFlags int FLAG_RESET_FILL_DIALOG_STATE = 0x100; + /** @hide */ public static final int INVALID_REQUEST_ID = Integer.MIN_VALUE; @@ -208,7 +214,8 @@ public final class FillRequest implements Parcelable { FLAG_PASSWORD_INPUT_TYPE, FLAG_VIEW_NOT_FOCUSED, FLAG_SUPPORTS_FILL_DIALOG, - FLAG_IME_SHOWING + FLAG_IME_SHOWING, + FLAG_RESET_FILL_DIALOG_STATE }) @Retention(RetentionPolicy.SOURCE) @DataClass.Generated.Member @@ -236,6 +243,8 @@ public final class FillRequest implements Parcelable { return "FLAG_SUPPORTS_FILL_DIALOG"; case FLAG_IME_SHOWING: return "FLAG_IME_SHOWING"; + case FLAG_RESET_FILL_DIALOG_STATE: + return "FLAG_RESET_FILL_DIALOG_STATE"; default: return Integer.toHexString(value); } } @@ -312,7 +321,8 @@ public final class FillRequest implements Parcelable { | FLAG_PASSWORD_INPUT_TYPE | FLAG_VIEW_NOT_FOCUSED | FLAG_SUPPORTS_FILL_DIALOG - | FLAG_IME_SHOWING); + | FLAG_IME_SHOWING + | FLAG_RESET_FILL_DIALOG_STATE); this.mInlineSuggestionsRequest = inlineSuggestionsRequest; this.mDelayedFillIntentSender = delayedFillIntentSender; @@ -473,7 +483,8 @@ public final class FillRequest implements Parcelable { | FLAG_PASSWORD_INPUT_TYPE | FLAG_VIEW_NOT_FOCUSED | FLAG_SUPPORTS_FILL_DIALOG - | FLAG_IME_SHOWING); + | FLAG_IME_SHOWING + | FLAG_RESET_FILL_DIALOG_STATE); this.mInlineSuggestionsRequest = inlineSuggestionsRequest; this.mDelayedFillIntentSender = delayedFillIntentSender; @@ -495,10 +506,10 @@ public final class FillRequest implements Parcelable { }; @DataClass.Generated( - time = 1647856966565L, + time = 1663290803064L, codegenVersion = "1.0.23", sourceFile = "frameworks/base/core/java/android/service/autofill/FillRequest.java", - inputSignatures = "public static final @android.service.autofill.FillRequest.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_PASSWORD_INPUT_TYPE\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_VIEW_NOT_FOCUSED\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_SUPPORTS_FILL_DIALOG\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_IME_SHOWING\npublic static final int INVALID_REQUEST_ID\nprivate final int mId\nprivate final @android.annotation.NonNull java.util.List<android.service.autofill.FillContext> mFillContexts\nprivate final @android.annotation.Nullable android.os.Bundle mClientState\nprivate final @android.service.autofill.FillRequest.RequestFlags int mFlags\nprivate final @android.annotation.Nullable android.view.inputmethod.InlineSuggestionsRequest mInlineSuggestionsRequest\nprivate final @android.annotation.Nullable android.content.IntentSender mDelayedFillIntentSender\nprivate void onConstructed()\nclass FillRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)") + inputSignatures = "public static final @android.service.autofill.FillRequest.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_PASSWORD_INPUT_TYPE\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_VIEW_NOT_FOCUSED\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_SUPPORTS_FILL_DIALOG\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_IME_SHOWING\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_RESET_FILL_DIALOG_STATE\npublic static final int INVALID_REQUEST_ID\nprivate final int mId\nprivate final @android.annotation.NonNull java.util.List<android.service.autofill.FillContext> mFillContexts\nprivate final @android.annotation.Nullable android.os.Bundle mClientState\nprivate final @android.service.autofill.FillRequest.RequestFlags int mFlags\nprivate final @android.annotation.Nullable android.view.inputmethod.InlineSuggestionsRequest mInlineSuggestionsRequest\nprivate final @android.annotation.Nullable android.content.IntentSender mDelayedFillIntentSender\nprivate void onConstructed()\nclass FillRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)") @Deprecated private void __metadata() {} diff --git a/core/java/android/service/voice/HotwordAudioStream.java b/core/java/android/service/voice/HotwordAudioStream.java index 5442860df007..1dceb7a08c13 100644 --- a/core/java/android/service/voice/HotwordAudioStream.java +++ b/core/java/android/service/voice/HotwordAudioStream.java @@ -37,6 +37,21 @@ import java.util.Objects; public final class HotwordAudioStream implements Parcelable { /** + * Key for int value to be read from {@link #getMetadata()}. The value is read by the system and + * is the length (in bytes) of the byte buffers created to copy bytes in the + * {@link #getAudioStreamParcelFileDescriptor()} written by the {@link HotwordDetectionService}. + * The buffer length should be chosen such that no additional latency is introduced. Typically, + * this should be <em>at least</em> the size of byte chunks written by the + * {@link HotwordDetectionService}. + * + * <p>If no value specified in the metadata for the buffer length, or if the value is less than + * 1, or if it is greater than 65,536, or if it is not an int, the default value of 2,560 will + * be used.</p> + */ + public static final String KEY_AUDIO_STREAM_COPY_BUFFER_LENGTH_BYTES = + "android.service.voice.key.AUDIO_STREAM_COPY_BUFFER_LENGTH_BYTES"; + + /** * The {@link AudioFormat} of the audio stream. */ @NonNull diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index c0183ad48139..af070238787f 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -1417,7 +1417,11 @@ public final class ViewRootImpl implements ViewParent, mFirstPostImeInputStage = earlyPostImeStage; mPendingInputEventQueueLengthCounterName = "aq:pending:" + counterSuffix; - AnimationHandler.requestAnimatorsEnabled(mAppVisible, this); + if (!mRemoved || !mAppVisible) { + AnimationHandler.requestAnimatorsEnabled(mAppVisible, this); + } else if (LOCAL_LOGV) { + Log.v(mTag, "setView() enabling visibility when removed"); + } } } } @@ -1755,7 +1759,12 @@ public final class ViewRootImpl implements ViewParent, if (!mAppVisible) { WindowManagerGlobal.trimForeground(); } - AnimationHandler.requestAnimatorsEnabled(mAppVisible, this); + // Only enable if the window is not already removed (via earlier call to doDie()) + if (!mRemoved || !mAppVisible) { + AnimationHandler.requestAnimatorsEnabled(mAppVisible, this); + } else if (LOCAL_LOGV) { + Log.v(mTag, "handleAppVisibility() enabling visibility when removed"); + } } } diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java index 7d7270d1ef76..79c3839a967e 100644 --- a/core/java/android/view/autofill/AutofillManager.java +++ b/core/java/android/view/autofill/AutofillManager.java @@ -19,6 +19,7 @@ package android.view.autofill; import static android.service.autofill.FillRequest.FLAG_IME_SHOWING; import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST; import static android.service.autofill.FillRequest.FLAG_PASSWORD_INPUT_TYPE; +import static android.service.autofill.FillRequest.FLAG_RESET_FILL_DIALOG_STATE; import static android.service.autofill.FillRequest.FLAG_SUPPORTS_FILL_DIALOG; import static android.service.autofill.FillRequest.FLAG_VIEW_NOT_FOCUSED; import static android.view.ContentInfo.SOURCE_AUTOFILL; @@ -715,7 +716,7 @@ public final class AutofillManager { * Autofill will automatically trigger a fill request after activity * start if there is any field is autofillable. But if there is a field that * triggered autofill, it is unnecessary to trigger again through - * AutofillManager#notifyViewEnteredForActivityStarted. + * AutofillManager#notifyViewEnteredForFillDialog. */ private AtomicBoolean mIsFillRequested; @@ -728,6 +729,10 @@ public final class AutofillManager { private final String[] mFillDialogEnabledHints; + // Tracked all views that have appeared, including views that there are no + // dataset in responses. Used to avoid request pre-fill request again and again. + private final ArraySet<AutofillId> mAllTrackedViews = new ArraySet<>(); + /** @hide */ public interface AutofillClient { /** @@ -1173,6 +1178,16 @@ public final class AutofillManager { * @hide */ public void notifyViewEnteredForFillDialog(View v) { + synchronized (mLock) { + if (mTrackedViews != null) { + // To support the fill dialog can show for the autofillable Views in + // different pages but in the same Activity. We need to reset the + // mIsFillRequested flag to allow asking for a new FillRequest when + // user switches to other page + mTrackedViews.checkViewState(v.getAutofillId()); + } + } + // Skip if the fill request has been performed for a view. if (mIsFillRequested.get()) { return; @@ -1299,6 +1314,10 @@ public final class AutofillManager { } mForAugmentedAutofillOnly = false; } + + if ((flags & FLAG_SUPPORTS_FILL_DIALOG) != 0) { + flags |= FLAG_RESET_FILL_DIALOG_STATE; + } updateSessionLocked(id, null, value, ACTION_VIEW_ENTERED, flags); } addEnteredIdLocked(id); @@ -2165,6 +2184,7 @@ public final class AutofillManager { mIsFillRequested.set(false); mShowAutofillDialogCalled = false; mFillDialogTriggerIds = null; + mAllTrackedViews.clear(); if (resetEnteredIds) { mEnteredIds = null; } @@ -2702,14 +2722,9 @@ public final class AutofillManager { + ", mFillableIds=" + mFillableIds + ", mEnabled=" + mEnabled + ", mSessionId=" + mSessionId); - } + if (mEnabled && mSessionId == sessionId) { - if (saveOnAllViewsInvisible) { - mTrackedViews = new TrackedViews(trackedIds); - } else { - mTrackedViews = null; - } mSaveOnFinish = saveOnFinish; if (fillableIds != null) { if (mFillableIds == null) { @@ -2731,6 +2746,27 @@ public final class AutofillManager { mSaveTriggerId = saveTriggerId; setNotifyOnClickLocked(mSaveTriggerId, true); } + + if (!saveOnAllViewsInvisible) { + trackedIds = null; + } + + final ArraySet<AutofillId> allFillableIds = new ArraySet<>(); + if (mFillableIds != null) { + allFillableIds.addAll(mFillableIds); + } + if (trackedIds != null) { + for (AutofillId id : trackedIds) { + id.resetSessionId(); + allFillableIds.add(id); + } + } + + if (!allFillableIds.isEmpty()) { + mTrackedViews = new TrackedViews(trackedIds, Helper.toArray(allFillableIds)); + } else { + mTrackedViews = null; + } } } } @@ -3502,10 +3538,19 @@ public final class AutofillManager { */ private class TrackedViews { /** Visible tracked views */ - @Nullable private ArraySet<AutofillId> mVisibleTrackedIds; + @NonNull private final ArraySet<AutofillId> mVisibleTrackedIds; /** Invisible tracked views */ - @Nullable private ArraySet<AutofillId> mInvisibleTrackedIds; + @NonNull private final ArraySet<AutofillId> mInvisibleTrackedIds; + + /** Visible tracked views for fill dialog */ + @NonNull private final ArraySet<AutofillId> mVisibleDialogTrackedIds; + + /** Invisible tracked views for fill dialog */ + @NonNull private final ArraySet<AutofillId> mInvisibleDialogTrackedIds; + + boolean mHasNewTrackedView; + boolean mIsTrackedSaveView; /** * Check if set is null or value is in set. @@ -3571,43 +3616,65 @@ public final class AutofillManager { * * @param trackedIds The views to be tracked */ - TrackedViews(@Nullable AutofillId[] trackedIds) { - final AutofillClient client = getClient(); - if (!ArrayUtils.isEmpty(trackedIds) && client != null) { - final boolean[] isVisible; - - if (client.autofillClientIsVisibleForAutofill()) { - if (sVerbose) Log.v(TAG, "client is visible, check tracked ids"); - isVisible = client.autofillClientGetViewVisibility(trackedIds); - } else { - // All false - isVisible = new boolean[trackedIds.length]; - } - - final int numIds = trackedIds.length; - for (int i = 0; i < numIds; i++) { - final AutofillId id = trackedIds[i]; - id.resetSessionId(); + TrackedViews(@Nullable AutofillId[] trackedIds, @Nullable AutofillId[] allTrackedIds) { + mVisibleTrackedIds = new ArraySet<>(); + mInvisibleTrackedIds = new ArraySet<>(); + if (!ArrayUtils.isEmpty(trackedIds)) { + mIsTrackedSaveView = true; + initialTrackedViews(trackedIds, mVisibleTrackedIds, mInvisibleTrackedIds); + } - if (isVisible[i]) { - mVisibleTrackedIds = addToSet(mVisibleTrackedIds, id); - } else { - mInvisibleTrackedIds = addToSet(mInvisibleTrackedIds, id); - } - } + mVisibleDialogTrackedIds = new ArraySet<>(); + mInvisibleDialogTrackedIds = new ArraySet<>(); + if (!ArrayUtils.isEmpty(allTrackedIds)) { + initialTrackedViews(allTrackedIds, mVisibleDialogTrackedIds, + mInvisibleDialogTrackedIds); + mAllTrackedViews.addAll(Arrays.asList(allTrackedIds)); } if (sVerbose) { Log.v(TAG, "TrackedViews(trackedIds=" + Arrays.toString(trackedIds) + "): " + " mVisibleTrackedIds=" + mVisibleTrackedIds - + " mInvisibleTrackedIds=" + mInvisibleTrackedIds); + + " mInvisibleTrackedIds=" + mInvisibleTrackedIds + + " allTrackedIds=" + Arrays.toString(allTrackedIds) + + " mVisibleDialogTrackedIds=" + mVisibleDialogTrackedIds + + " mInvisibleDialogTrackedIds=" + mInvisibleDialogTrackedIds); } - if (mVisibleTrackedIds == null) { + if (mIsTrackedSaveView && mVisibleTrackedIds.isEmpty()) { finishSessionLocked(/* commitReason= */ COMMIT_REASON_VIEW_CHANGED); } } + private void initialTrackedViews(AutofillId[] trackedIds, + @NonNull ArraySet<AutofillId> visibleSet, + @NonNull ArraySet<AutofillId> invisibleSet) { + final boolean[] isVisible; + final AutofillClient client = getClient(); + if (ArrayUtils.isEmpty(trackedIds) || client == null) { + return; + } + if (client.autofillClientIsVisibleForAutofill()) { + if (sVerbose) Log.v(TAG, "client is visible, check tracked ids"); + isVisible = client.autofillClientGetViewVisibility(trackedIds); + } else { + // All false + isVisible = new boolean[trackedIds.length]; + } + + final int numIds = trackedIds.length; + for (int i = 0; i < numIds; i++) { + final AutofillId id = trackedIds[i]; + id.resetSessionId(); + + if (isVisible[i]) { + addToSet(visibleSet, id); + } else { + addToSet(invisibleSet, id); + } + } + } + /** * Called when a {@link View view's} visibility changes. * @@ -3624,22 +3691,37 @@ public final class AutofillManager { if (isClientVisibleForAutofillLocked()) { if (isVisible) { if (isInSet(mInvisibleTrackedIds, id)) { - mInvisibleTrackedIds = removeFromSet(mInvisibleTrackedIds, id); - mVisibleTrackedIds = addToSet(mVisibleTrackedIds, id); + removeFromSet(mInvisibleTrackedIds, id); + addToSet(mVisibleTrackedIds, id); + } + if (isInSet(mInvisibleDialogTrackedIds, id)) { + removeFromSet(mInvisibleDialogTrackedIds, id); + addToSet(mVisibleDialogTrackedIds, id); } } else { if (isInSet(mVisibleTrackedIds, id)) { - mVisibleTrackedIds = removeFromSet(mVisibleTrackedIds, id); - mInvisibleTrackedIds = addToSet(mInvisibleTrackedIds, id); + removeFromSet(mVisibleTrackedIds, id); + addToSet(mInvisibleTrackedIds, id); + } + if (isInSet(mVisibleDialogTrackedIds, id)) { + removeFromSet(mVisibleDialogTrackedIds, id); + addToSet(mInvisibleDialogTrackedIds, id); } } } - if (mVisibleTrackedIds == null) { + if (mIsTrackedSaveView && mVisibleTrackedIds.isEmpty()) { if (sVerbose) { Log.v(TAG, "No more visible ids. Invisible = " + mInvisibleTrackedIds); } finishSessionLocked(/* commitReason= */ COMMIT_REASON_VIEW_CHANGED); + + } + if (mVisibleDialogTrackedIds.isEmpty()) { + if (sVerbose) { + Log.v(TAG, "No more visible ids. Invisible = " + mInvisibleDialogTrackedIds); + } + processNoVisibleTrackedAllViews(); } } @@ -3653,66 +3735,66 @@ public final class AutofillManager { // The visibility of the views might have changed while the client was not be visible, // hence update the visibility state for all views. AutofillClient client = getClient(); - ArraySet<AutofillId> updatedVisibleTrackedIds = null; - ArraySet<AutofillId> updatedInvisibleTrackedIds = null; if (client != null) { if (sVerbose) { Log.v(TAG, "onVisibleForAutofillChangedLocked(): inv= " + mInvisibleTrackedIds + " vis=" + mVisibleTrackedIds); } - if (mInvisibleTrackedIds != null) { - final ArrayList<AutofillId> orderedInvisibleIds = - new ArrayList<>(mInvisibleTrackedIds); - final boolean[] isVisible = client.autofillClientGetViewVisibility( - Helper.toArray(orderedInvisibleIds)); - - final int numInvisibleTrackedIds = orderedInvisibleIds.size(); - for (int i = 0; i < numInvisibleTrackedIds; i++) { - final AutofillId id = orderedInvisibleIds.get(i); - if (isVisible[i]) { - updatedVisibleTrackedIds = addToSet(updatedVisibleTrackedIds, id); - if (sDebug) { - Log.d(TAG, "onVisibleForAutofill() " + id + " became visible"); - } - } else { - updatedInvisibleTrackedIds = addToSet(updatedInvisibleTrackedIds, id); - } - } - } + onVisibleForAutofillChangedInternalLocked(mVisibleTrackedIds, mInvisibleTrackedIds); + onVisibleForAutofillChangedInternalLocked( + mVisibleDialogTrackedIds, mInvisibleDialogTrackedIds); + } - if (mVisibleTrackedIds != null) { - final ArrayList<AutofillId> orderedVisibleIds = - new ArrayList<>(mVisibleTrackedIds); - final boolean[] isVisible = client.autofillClientGetViewVisibility( - Helper.toArray(orderedVisibleIds)); + if (mIsTrackedSaveView && mVisibleTrackedIds.isEmpty()) { + if (sVerbose) { + Log.v(TAG, "onVisibleForAutofillChangedLocked(): no more visible ids"); + } + finishSessionLocked(/* commitReason= */ COMMIT_REASON_VIEW_CHANGED); + } + if (mVisibleDialogTrackedIds.isEmpty()) { + if (sVerbose) { + Log.v(TAG, "onVisibleForAutofillChangedLocked(): no more visible ids"); + } + processNoVisibleTrackedAllViews(); + } + } - final int numVisibleTrackedIds = orderedVisibleIds.size(); - for (int i = 0; i < numVisibleTrackedIds; i++) { - final AutofillId id = orderedVisibleIds.get(i); + void onVisibleForAutofillChangedInternalLocked(@NonNull ArraySet<AutofillId> visibleSet, + @NonNull ArraySet<AutofillId> invisibleSet) { + // The visibility of the views might have changed while the client was not be visible, + // hence update the visibility state for all views. + if (sVerbose) { + Log.v(TAG, "onVisibleForAutofillChangedLocked(): inv= " + invisibleSet + + " vis=" + visibleSet); + } - if (isVisible[i]) { - updatedVisibleTrackedIds = addToSet(updatedVisibleTrackedIds, id); - } else { - updatedInvisibleTrackedIds = addToSet(updatedInvisibleTrackedIds, id); + ArraySet<AutofillId> allTrackedIds = new ArraySet<>(); + allTrackedIds.addAll(visibleSet); + allTrackedIds.addAll(invisibleSet); + if (!allTrackedIds.isEmpty()) { + visibleSet.clear(); + invisibleSet.clear(); + initialTrackedViews(Helper.toArray(allTrackedIds), visibleSet, invisibleSet); + } + } - if (sDebug) { - Log.d(TAG, "onVisibleForAutofill() " + id + " became invisible"); - } - } - } - } + private void processNoVisibleTrackedAllViews() { + mShowAutofillDialogCalled = false; + } - mInvisibleTrackedIds = updatedInvisibleTrackedIds; - mVisibleTrackedIds = updatedVisibleTrackedIds; + void checkViewState(AutofillId id) { + if (mAllTrackedViews.contains(id)) { + return; } - - if (mVisibleTrackedIds == null) { - if (sVerbose) { - Log.v(TAG, "onVisibleForAutofillChangedLocked(): no more visible ids"); - } - finishSessionLocked(/* commitReason= */ COMMIT_REASON_VIEW_CHANGED); + // Add the id as tracked to avoid triggering fill request again and again. + mAllTrackedViews.add(id); + if (mHasNewTrackedView) { + return; } + // First one new tracks view + mIsFillRequested.set(false); + mHasNewTrackedView = true; } } diff --git a/core/java/com/android/internal/app/IVoiceInteractionSessionListener.aidl b/core/java/com/android/internal/app/IVoiceInteractionSessionListener.aidl index 6e409885fa13..46f78e2ee8a2 100644 --- a/core/java/com/android/internal/app/IVoiceInteractionSessionListener.aidl +++ b/core/java/com/android/internal/app/IVoiceInteractionSessionListener.aidl @@ -31,6 +31,8 @@ /** * Called when a voice session window is shown/hidden. + * Caution that there could be duplicated visibility change callbacks, it's up to the listener + * to dedup those events. */ void onVoiceSessionWindowVisibilityChanged(boolean visible); diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index 1235b602cde9..2dfe89397ea5 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -1522,7 +1522,8 @@ public class LockPatternUtils { STRONG_AUTH_REQUIRED_AFTER_LOCKOUT, STRONG_AUTH_REQUIRED_AFTER_TIMEOUT, STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN, - STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT}) + STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT, + SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED}) @Retention(RetentionPolicy.SOURCE) public @interface StrongAuthFlags {} @@ -1575,11 +1576,18 @@ public class LockPatternUtils { public static final int STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT = 0x80; /** + * Some authentication is required because the trustagent either timed out or was disabled + * manually. + */ + public static final int SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED = 0x100; + + /** * Strong auth flags that do not prevent biometric methods from being accepted as auth. * If any other flags are set, biometric authentication is disabled. */ private static final int ALLOWING_BIOMETRIC = STRONG_AUTH_NOT_REQUIRED - | SOME_AUTH_REQUIRED_AFTER_USER_REQUEST; + | SOME_AUTH_REQUIRED_AFTER_USER_REQUEST + | SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED; private final SparseIntArray mStrongAuthRequiredForUser = new SparseIntArray(); private final H mHandler; diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml index c527e59e7c10..2d8f21d5c62c 100644 --- a/core/res/res/values-be/strings.xml +++ b/core/res/res/values-be/strings.xml @@ -1974,7 +1974,7 @@ <string name="pin_specific_target" msgid="7824671240625957415">"Замацаваць праграму \"<xliff:g id="LABEL">%1$s</xliff:g>\""</string> <string name="unpin_target" msgid="3963318576590204447">"Адмацаваць"</string> <string name="unpin_specific_target" msgid="3859828252160908146">"Адмацаваць праграму \"<xliff:g id="LABEL">%1$s</xliff:g>\""</string> - <string name="app_info" msgid="6113278084877079851">"Інфармацыя пра праграму"</string> + <string name="app_info" msgid="6113278084877079851">"Звесткі аб праграме"</string> <string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="demo_starting_message" msgid="6577581216125805905">"Ідзе запуск дэманстрацыі…"</string> <string name="demo_restarting_message" msgid="1160053183701746766">"Ідзе скід налад прылады…"</string> diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml index 0ec4f1d8e757..40b265af02db 100644 --- a/core/res/res/values-fr-rCA/strings.xml +++ b/core/res/res/values-fr-rCA/strings.xml @@ -1167,8 +1167,8 @@ <string name="no" msgid="5122037903299899715">"Annuler"</string> <string name="dialog_alert_title" msgid="651856561974090712">"Attention"</string> <string name="loading" msgid="3138021523725055037">"Chargement en cours..."</string> - <string name="capital_on" msgid="2770685323900821829">"OUI"</string> - <string name="capital_off" msgid="7443704171014626777">"NON"</string> + <string name="capital_on" msgid="2770685323900821829">"ACTIVÉ"</string> + <string name="capital_off" msgid="7443704171014626777">"DÉSACTIVÉ"</string> <string name="checked" msgid="9179896827054513119">"coché"</string> <string name="not_checked" msgid="7972320087569023342">"non coché"</string> <string name="selected" msgid="6614607926197755875">"sélectionné"</string> diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index 38a7c7b44474..b02345ac9945 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -626,15 +626,15 @@ </string-array> <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Terjadi error. Coba lagi."</string> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikon sidik jari"</string> - <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Face Unlock"</string> - <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Masalah pada Face Unlock"</string> + <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Buka dengan Wajah"</string> + <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Masalah pada Buka dengan Wajah"</string> <string name="face_recalibrate_notification_content" msgid="3064513770251355594">"Ketuk untuk menghapus model wajah, lalu tambahkan wajah Anda lagi"</string> - <string name="face_setup_notification_title" msgid="8843461561970741790">"Siapkan Face Unlock"</string> + <string name="face_setup_notification_title" msgid="8843461561970741790">"Siapkan Buka dengan Wajah"</string> <string name="face_setup_notification_content" msgid="5463999831057751676">"Buka kunci ponsel dengan melihat ke ponsel"</string> - <string name="face_sensor_privacy_enabled" msgid="7407126963510598508">"Untuk menggunakan Face Unlock, aktifkan "<b>"Akses kamera"</b>" di Setelan > Privasi"</string> + <string name="face_sensor_privacy_enabled" msgid="7407126963510598508">"Untuk menggunakan Buka dengan Wajah, aktifkan "<b>"Akses kamera"</b>" di Setelan > Privasi"</string> <string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Siapkan lebih banyak cara untuk membuka kunci"</string> <string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Ketuk untuk menambahkan sidik jari"</string> - <string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Fingerprint Unlock"</string> + <string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Buka dengan Sidik Jari"</string> <string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Tidak dapat menggunakan sensor sidik jari"</string> <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Kunjungi penyedia reparasi."</string> <string name="face_acquired_insufficient" msgid="6889245852748492218">"Tidak dapat membuat model wajah Anda. Coba lagi."</string> @@ -667,19 +667,19 @@ <string-array name="face_acquired_vendor"> </string-array> <string name="face_error_hw_not_available" msgid="5085202213036026288">"Tidak dapat memverifikasi wajah. Hardware tidak tersedia."</string> - <string name="face_error_timeout" msgid="2598544068593889762">"Coba Face Unlock lagi"</string> + <string name="face_error_timeout" msgid="2598544068593889762">"Coba Buka dengan Wajah lagi"</string> <string name="face_error_no_space" msgid="5649264057026021723">"Tidak dapat menyimpan data wajah. Hapus dahulu data lama."</string> <string name="face_error_canceled" msgid="2164434737103802131">"Pemrosesan wajah dibatalkan."</string> - <string name="face_error_user_canceled" msgid="5766472033202928373">"Face Unlock dibatalkan oleh pengguna"</string> + <string name="face_error_user_canceled" msgid="5766472033202928373">"Buka dengan Wajah dibatalkan oleh pengguna"</string> <string name="face_error_lockout" msgid="7864408714994529437">"Terlalu banyak percobaan. Coba lagi nanti."</string> - <string name="face_error_lockout_permanent" msgid="3277134834042995260">"Terlalu banyak upaya gagal. Face Unlock dinonaktifkan."</string> + <string name="face_error_lockout_permanent" msgid="3277134834042995260">"Terlalu banyak upaya gagal. Buka dengan Wajah dinonaktifkan."</string> <string name="face_error_lockout_screen_lock" msgid="5062609811636860928">"Terlalu banyak upaya gagal. Masukkan kunci layar."</string> <string name="face_error_unable_to_process" msgid="5723292697366130070">"Tidak dapat memverifikasi wajah. Coba lagi."</string> - <string name="face_error_not_enrolled" msgid="1134739108536328412">"Anda belum menyiapkan Face Unlock"</string> - <string name="face_error_hw_not_present" msgid="7940978724978763011">"Face Unlock tidak didukung di perangkat ini"</string> + <string name="face_error_not_enrolled" msgid="1134739108536328412">"Anda belum menyiapkan Buka dengan Wajah"</string> + <string name="face_error_hw_not_present" msgid="7940978724978763011">"Buka dengan Wajah tidak didukung di perangkat ini"</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor dinonaktifkan untuk sementara."</string> <string name="face_name_template" msgid="3877037340223318119">"<xliff:g id="FACEID">%d</xliff:g> wajah"</string> - <string name="face_app_setting_name" msgid="5854024256907828015">"Gunakan Face Unlock"</string> + <string name="face_app_setting_name" msgid="5854024256907828015">"Gunakan Buka dengan Wajah"</string> <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Gunakan face lock atau kunci layar"</string> <string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Gunakan wajah untuk melanjutkan"</string> <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Gunakan face lock atau kunci layar untuk melanjutkan"</string> @@ -928,7 +928,7 @@ <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Coba lagi"</string> <string name="lockscreen_password_wrong" msgid="8605355913868947490">"Coba lagi"</string> <string name="lockscreen_storage_locked" msgid="634993789186443380">"Membuka kunci untuk semua fitur dan data"</string> - <string name="faceunlock_multiple_failures" msgid="681991538434031708">"Percobaan Face Unlock melebihi batas maksimum"</string> + <string name="faceunlock_multiple_failures" msgid="681991538434031708">"Percobaan Buka dengan Wajah melebihi batas maksimum"</string> <string name="lockscreen_missing_sim_message_short" msgid="1248431165144893792">"Tidak ada kartu SIM"</string> <string name="lockscreen_missing_sim_message" product="tablet" msgid="8596805728510570760">"Tidak ada kartu SIM dalam tablet."</string> <string name="lockscreen_missing_sim_message" product="tv" msgid="2582768023352171073">"Tidak ada kartu SIM di perangkat Android TV."</string> @@ -998,7 +998,7 @@ <string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Luaskan area buka kunci."</string> <string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Buka kunci dengan menggeser."</string> <string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Buka kunci dengan pola."</string> - <string name="keyguard_accessibility_face_unlock" msgid="4533832120787386728">"Face Unlock."</string> + <string name="keyguard_accessibility_face_unlock" msgid="4533832120787386728">"Buka dengan Wajah."</string> <string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Buka kunci dengan PIN."</string> <string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"PIN SIM terbuka."</string> <string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"PUK SIM terbuka."</string> diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml index 6b88f8ef39c2..42a477b4b1a8 100644 --- a/core/res/res/values-pt-rBR/strings.xml +++ b/core/res/res/values-pt-rBR/strings.xml @@ -897,7 +897,7 @@ <string name="relationTypeFriend" msgid="3192092625893980574">"Amigo(a)"</string> <string name="relationTypeManager" msgid="2272860813153171857">"Gerente"</string> <string name="relationTypeMother" msgid="2331762740982699460">"Mãe"</string> - <string name="relationTypeParent" msgid="4177920938333039882">"Pai/Mãe"</string> + <string name="relationTypeParent" msgid="4177920938333039882">"familiar responsável"</string> <string name="relationTypePartner" msgid="4018017075116766194">"Parceiro"</string> <string name="relationTypeReferredBy" msgid="5285082289602849400">"Indicado por"</string> <string name="relationTypeRelative" msgid="3396498519818009134">"Parente"</string> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index 6b88f8ef39c2..42a477b4b1a8 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -897,7 +897,7 @@ <string name="relationTypeFriend" msgid="3192092625893980574">"Amigo(a)"</string> <string name="relationTypeManager" msgid="2272860813153171857">"Gerente"</string> <string name="relationTypeMother" msgid="2331762740982699460">"Mãe"</string> - <string name="relationTypeParent" msgid="4177920938333039882">"Pai/Mãe"</string> + <string name="relationTypeParent" msgid="4177920938333039882">"familiar responsável"</string> <string name="relationTypePartner" msgid="4018017075116766194">"Parceiro"</string> <string name="relationTypeReferredBy" msgid="5285082289602849400">"Indicado por"</string> <string name="relationTypeRelative" msgid="3396498519818009134">"Parente"</string> diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index bfb7a38fa269..01e57e130420 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -993,7 +993,7 @@ <string name="keyguard_accessibility_user_selector" msgid="1466067610235696600">"Výber používateľa"</string> <string name="keyguard_accessibility_status" msgid="6792745049712397237">"Stav"</string> <string name="keyguard_accessibility_camera" msgid="7862557559464986528">"Fotoaparát"</string> - <string name="keygaurd_accessibility_media_controls" msgid="2267379779900620614">"Ovládacie prvky médií"</string> + <string name="keygaurd_accessibility_media_controls" msgid="2267379779900620614">"Ovládanie médií"</string> <string name="keyguard_accessibility_widget_reorder_start" msgid="7066213328912939191">"Zmena usporiadania miniaplikácií sa začala."</string> <string name="keyguard_accessibility_widget_reorder_end" msgid="1083806817600593490">"Zmena usporiadania miniaplikácií sa skončila."</string> <string name="keyguard_accessibility_widget_deleted" msgid="1509738950119878705">"Miniaplikácia <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> bola odstránená."</string> diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml index 8647c5c7b538..f0470220e2fa 100644 --- a/core/res/res/values-te/strings.xml +++ b/core/res/res/values-te/strings.xml @@ -364,7 +364,7 @@ <string name="permdesc_receiveMms" msgid="958102423732219710">"MMS మెసేజ్లను స్వీకరించడానికి, ప్రాసెస్ చేయడానికి యాప్ను అనుమతిస్తుంది. మీ డివైజ్కు వచ్చిన మెసేజ్లను మీకు చూపకుండానే యాప్ పర్యవేక్షించగలదని లేదా తొలగించగలదని దీని అర్థం."</string> <string name="permlab_bindCellBroadcastService" msgid="586746677002040651">"సెల్ ప్రసార మెసేజ్లను ఫార్వర్డ్ చేయడం"</string> <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"సెల్ ప్రసార మెసేజ్లను స్వీకరించినప్పుడు, వాటిని ఫార్వర్డ్ చేయడానికి సెల్ ప్రసార మాడ్యూల్కు కట్టుబడి ఉండేందుకు యాప్ను అనుమతిస్తుంది. ఎమర్జెన్సీ పరిస్థితుల గురించి మిమ్మల్ని హెచ్చరించడానికి కొన్ని లొకేషన్లలో సెల్ ప్రసార అలర్ట్లు డెలివరీ చేయబడతాయి. ఎమర్జెన్సీ సెల్ ప్రసార అలర్ట్ను స్వీకరించినప్పుడు హానికరమైన యాప్లు మీ పరికరం పనితీరుకు లేదా నిర్వహణకు ఆటంకం కలిగించే అవకాశం ఉంది."</string> - <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"కొనసాగుతున్న కాల్స్ను మేనేజ్ చేయి"</string> + <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"కొనసాగుతున్న కాల్స్ను మేనేజ్ చేయండి"</string> <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"మీ పరికరంలో కొనసాగుతున్న కాల్స్ను చూడటానికి అలాగే వాటిని కంట్రోల్ చేయడానికి ఒక యాప్కు అనుమతిస్తోంది."</string> <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"సెల్ ప్రసార మెసేజ్లను చదవడం"</string> <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"మీ పరికరం స్వీకరించిన సెల్ ప్రసార మెసేజ్లను చదవడానికి యాప్ను అనుమతిస్తుంది. ఎమర్జెన్సీ పరిస్థితుల గురించి మిమ్మల్ని హెచ్చరించడానికి కొన్ని లొకేషన్లలో సెల్ ప్రసార అలర్ట్లు డెలివరీ చేయబడతాయి. ఎమర్జెన్సీ సెల్ ప్రసార అలర్ట్ను స్వీకరించినప్పుడు హానికరమైన యాప్లు మీ పరికరం పనితీరుకు లేదా నిర్వహణకు ఆటంకం కలిగించే అవకాశం ఉంది."</string> @@ -1149,7 +1149,7 @@ <string name="redo" msgid="7231448494008532233">"చర్యను రిపీట్ చేయి"</string> <string name="autofill" msgid="511224882647795296">"ఆటోఫిల్"</string> <string name="textSelectionCABTitle" msgid="5151441579532476940">"వచన ఎంపిక"</string> - <string name="addToDictionary" msgid="8041821113480950096">"నిఘంటువుకు జోడించు"</string> + <string name="addToDictionary" msgid="8041821113480950096">"నిఘంటువుకు జోడించండి"</string> <string name="deleteText" msgid="4200807474529938112">"తొలగించండి"</string> <string name="inputMethod" msgid="1784759500516314751">"ఇన్పుట్ పద్ధతి"</string> <string name="editTextMenuTitle" msgid="857666911134482176">"వచనానికి సంబంధించిన చర్యలు"</string> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index bbbb79c79527..22f42980d858 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -4789,11 +4789,11 @@ <integer name="config_defaultPeakRefreshRate">0</integer> <!-- The display uses different gamma curves for different refresh rates. It's hard for panel - vendor to tune the curves to have exact same brightness for different refresh rate. So + vendors to tune the curves to have exact same brightness for different refresh rate. So flicker could be observed at switch time. The issue is worse at the gamma lower end. In addition, human eyes are more sensitive to the flicker at darker environment. To prevent flicker, we only support higher refresh rates if the display brightness is above - a threshold. And the darker environment could have higher threshold. + a threshold. For example, no higher refresh rate if display brightness <= disp0 && ambient brightness <= amb0 || display brightness <= disp1 && ambient brightness <= amb1 --> @@ -4815,13 +4815,12 @@ <integer name="config_defaultRefreshRateInZone">0</integer> <!-- The display uses different gamma curves for different refresh rates. It's hard for panel - vendor to tune the curves to have exact same brightness for different refresh rate. So + vendors to tune the curves to have exact same brightness for different refresh rate. So flicker could be observed at switch time. The issue can be observed on the screen with even full white content at the high brightness. To prevent flickering, we support fixed refresh rates if the display and ambient brightness are equal to or above the provided thresholds. You can define multiple threshold levels as higher brightness environments - may have lower display brightness requirements for the flickering is visible. And the - high brightness environment could have higher threshold. + may have lower display brightness requirements for the flickering is visible. For example, fixed refresh rate if display brightness >= disp0 && ambient brightness >= amb0 || display brightness >= disp1 && ambient brightness >= amb1 --> diff --git a/core/tests/utiltests/src/com/android/internal/util/LockPatternUtilsTest.java b/core/tests/utiltests/src/com/android/internal/util/LockPatternUtilsTest.java index 4679a9ea6f66..0b7019995acb 100644 --- a/core/tests/utiltests/src/com/android/internal/util/LockPatternUtilsTest.java +++ b/core/tests/utiltests/src/com/android/internal/util/LockPatternUtilsTest.java @@ -19,6 +19,9 @@ package com.android.internal.util; import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_MANAGED; import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; +import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED; +import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT; + import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertFalse; @@ -37,6 +40,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.ContextWrapper; import android.content.pm.UserInfo; +import android.os.Looper; import android.os.RemoteException; import android.os.UserManager; import android.provider.Settings; @@ -233,6 +237,45 @@ public class LockPatternUtilsTest { ComponentName.unflattenFromString("com.test/.TestAgent")); } + @Test + public void isBiometricAllowedForUser_afterTrustagentExpired_returnsTrue() + throws RemoteException { + TestStrongAuthTracker tracker = createStrongAuthTracker(); + tracker.changeStrongAuth(SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED); + + assertTrue(tracker.isBiometricAllowedForUser( + /* isStrongBiometric = */ true, + DEMO_USER_ID)); + } + + @Test + public void isBiometricAllowedForUser_afterLockout_returnsFalse() + throws RemoteException { + TestStrongAuthTracker tracker = createStrongAuthTracker(); + tracker.changeStrongAuth(STRONG_AUTH_REQUIRED_AFTER_LOCKOUT); + + assertFalse(tracker.isBiometricAllowedForUser( + /* isStrongBiometric = */ true, + DEMO_USER_ID)); + } + + + private TestStrongAuthTracker createStrongAuthTracker() { + final Context context = new ContextWrapper(InstrumentationRegistry.getTargetContext()); + return new TestStrongAuthTracker(context, Looper.getMainLooper()); + } + + private static class TestStrongAuthTracker extends LockPatternUtils.StrongAuthTracker { + + TestStrongAuthTracker(Context context, Looper looper) { + super(context, looper); + } + + public void changeStrongAuth(@StrongAuthFlags int strongAuthFlags) { + handleStrongAuthRequiredChanged(strongAuthFlags, DEMO_USER_ID); + } + } + private ILockSettings createTestLockSettings() { final Context context = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext())); mLockPatternUtils = spy(new LockPatternUtils(context)); diff --git a/libs/WindowManager/Shell/res/values-ne/strings.xml b/libs/WindowManager/Shell/res/values-ne/strings.xml index 4a937cf92d12..4b10f5a1a886 100644 --- a/libs/WindowManager/Shell/res/values-ne/strings.xml +++ b/libs/WindowManager/Shell/res/values-ne/strings.xml @@ -33,8 +33,7 @@ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"अनस्ट्यास गर्नुहोस्"</string> <string name="dock_forced_resizable" msgid="1749750436092293116">"एप विभाजित स्क्रिनमा काम नगर्न सक्छ।"</string> <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"अनुप्रयोगले विभाजित-स्क्रिनलाई समर्थन गर्दैन।"</string> - <!-- no translation found for dock_multi_instances_not_supported_text (5242868470666346929) --> - <skip /> + <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"यो एप एउटा विन्डोमा मात्र खोल्न मिल्छ।"</string> <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"यो एपले सहायक प्रदर्शनमा काम नगर्नसक्छ।"</string> <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"अनुप्रयोगले सहायक प्रदर्शनहरूमा लञ्च सुविधालाई समर्थन गर्दैन।"</string> <string name="accessibility_divider" msgid="703810061635792791">"विभाजित-स्क्रिन छुट्याउने"</string> 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 5be29db12b25..717ae91f74c5 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 @@ -1613,7 +1613,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, mSplitLayout.flingDividerToDismiss( mSideStagePosition != SPLIT_POSITION_BOTTOM_OR_RIGHT, EXIT_REASON_APP_FINISHED); - } else if (!isSplitScreenVisible()) { + } else if (!isSplitScreenVisible() && !mIsSplitEntering) { exitSplitScreen(null /* childrenToTop */, EXIT_REASON_APP_FINISHED); } } else if (isSideStage && hasChildren && !mMainStage.isActive()) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java index 92154968855f..7f85988d1377 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java @@ -33,6 +33,7 @@ import android.view.View; import android.view.ViewRootImpl; import android.view.WindowManager; import android.view.WindowlessWindowManager; +import android.window.TaskConstants; import android.window.WindowContainerTransaction; import com.android.wm.shell.ShellTaskOrganizer; @@ -195,7 +196,9 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> .setParent(mTaskSurface) .build(); - startT.setTrustedOverlay(mDecorationContainerSurface, true); + startT.setTrustedOverlay(mDecorationContainerSurface, true) + .setLayer(mDecorationContainerSurface, + TaskConstants.TASK_CHILD_LAYER_WINDOW_DECORATIONS); } final Rect taskBounds = taskConfig.windowConfiguration.getBounds(); @@ -213,8 +216,6 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> outResult.mDecorContainerOffsetX, outResult.mDecorContainerOffsetY) .setWindowCrop(mDecorationContainerSurface, outResult.mWidth, outResult.mHeight) - // TODO(b/244455401): Change the z-order when it's better organized - .setLayer(mDecorationContainerSurface, mTaskInfo.numActivities + 1) .show(mDecorationContainerSurface); // TaskBackgroundSurface @@ -225,6 +226,8 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> .setEffectLayer() .setParent(mTaskSurface) .build(); + + startT.setLayer(mTaskBackgroundSurface, TaskConstants.TASK_CHILD_LAYER_TASK_BACKGROUND); } float shadowRadius = loadDimension(resources, params.mShadowRadiusId); @@ -236,8 +239,6 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> taskBounds.height()) .setShadowRadius(mTaskBackgroundSurface, shadowRadius) .setColor(mTaskBackgroundSurface, mTmpColor) - // TODO(b/244455401): Change the z-order when it's better organized - .setLayer(mTaskBackgroundSurface, -1) .show(mTaskBackgroundSurface); // CaptionContainerSurface, CaptionWindowManager diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml index adbdf228aea1..ad4c32e3af8c 100644 --- a/packages/SettingsLib/res/values-am/strings.xml +++ b/packages/SettingsLib/res/values-am/strings.xml @@ -479,8 +479,7 @@ <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - እስኪሞላ ድረስ <xliff:g id="TIME">%2$s</xliff:g> ይቀራል"</string> <!-- no translation found for power_charging_limited (6732738149313642521) --> <skip /> - <!-- no translation found for power_charging_future_paused (6829683663982987290) --> - <skip /> + <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> - እስከ <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g> ድረስ ኃይል መሙላት"</string> <string name="battery_info_status_unknown" msgid="268625384868401114">"ያልታወቀ"</string> <string name="battery_info_status_charging" msgid="4279958015430387405">"ኃይል በመሙላት ላይ"</string> <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ኃይል በፍጥነት በመሙላት ላይ"</string> diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml index ca2f14327df6..730247dde2d5 100644 --- a/packages/SettingsLib/res/values-te/strings.xml +++ b/packages/SettingsLib/res/values-te/strings.xml @@ -342,7 +342,7 @@ <string name="bluetooth_enable_gabeldorsche_summary" msgid="2054730331770712629">"బ్లూటూత్ Gabeldorsche ఫీచర్ స్ట్యాక్ను ఎనేబుల్ చేస్తుంది."</string> <string name="enhanced_connectivity_summary" msgid="1576414159820676330">"మెరుగైన కనెక్టివిటీ ఫీచర్ను ఎనేబుల్ చేస్తుంది."</string> <string name="enable_terminal_title" msgid="3834790541986303654">"స్థానిక టెర్మినల్"</string> - <string name="enable_terminal_summary" msgid="2481074834856064500">"స్థానిక షెల్ యాక్సెస్ను అందించే టెర్మినల్ యాప్ను ప్రారంభించు"</string> + <string name="enable_terminal_summary" msgid="2481074834856064500">"స్థానిక షెల్ యాక్సెస్ను అందించే టెర్మినల్ యాప్ను ప్రారంభించండి"</string> <string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP చెకింగ్"</string> <string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"HDCP తనిఖీ ప్రవర్తనను సెట్ చేయండి"</string> <string name="debug_debugging_category" msgid="535341063709248842">"డీబగ్గింగ్"</string> diff --git a/packages/SoundPicker/res/values-te/strings.xml b/packages/SoundPicker/res/values-te/strings.xml index feaf4c83b51e..2d03ac0e844c 100644 --- a/packages/SoundPicker/res/values-te/strings.xml +++ b/packages/SoundPicker/res/values-te/strings.xml @@ -19,9 +19,9 @@ <string name="ringtone_default" msgid="798836092118824500">"ఆటోమేటిక్ రింగ్టోన్"</string> <string name="notification_sound_default" msgid="8133121186242636840">"నోటిఫికేషన్ ఆటోమేటిక్ సౌండ్"</string> <string name="alarm_sound_default" msgid="4787646764557462649">"అలారం ఆటోమేటిక్ సౌండ్"</string> - <string name="add_ringtone_text" msgid="6642389991738337529">"రింగ్టోన్ను జోడించు"</string> - <string name="add_alarm_text" msgid="3545497316166999225">"అలారాన్ని జోడించు"</string> - <string name="add_notification_text" msgid="4431129543300614788">"నోటిఫికేషన్ని జోడించు"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"రింగ్టోన్ను జోడించండి"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"అలారాన్ని జోడించండి"</string> + <string name="add_notification_text" msgid="4431129543300614788">"నోటిఫికేషన్ని జోడించండి"</string> <string name="delete_ringtone_text" msgid="201443984070732499">"తొలగించండి"</string> <string name="unable_to_add_ringtone" msgid="4583511263449467326">"అనుకూల రింగ్టోన్ను జోడించలేకపోయింది"</string> <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"అనుకూల రింగ్టోన్ను తొలగించలేకపోయింది"</string> diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt index ebabdf571dfd..fe349f21e36e 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt @@ -49,12 +49,12 @@ private const val TAG = "ActivityLaunchAnimator" */ class ActivityLaunchAnimator( /** The animator used when animating a View into an app. */ - private val launchAnimator: LaunchAnimator = LaunchAnimator(TIMINGS, INTERPOLATORS), + private val launchAnimator: LaunchAnimator = DEFAULT_LAUNCH_ANIMATOR, /** The animator used when animating a Dialog into an app. */ // TODO(b/218989950): Remove this animator and instead set the duration of the dim fade out to // TIMINGS.contentBeforeFadeOutDuration. - private val dialogToAppAnimator: LaunchAnimator = LaunchAnimator(DIALOG_TIMINGS, INTERPOLATORS) + private val dialogToAppAnimator: LaunchAnimator = DEFAULT_DIALOG_TO_APP_ANIMATOR ) { companion object { /** The timings when animating a View into an app. */ @@ -85,6 +85,9 @@ class ActivityLaunchAnimator( contentAfterFadeInInterpolator = PathInterpolator(0f, 0f, 0.6f, 1f) ) + private val DEFAULT_LAUNCH_ANIMATOR = LaunchAnimator(TIMINGS, INTERPOLATORS) + private val DEFAULT_DIALOG_TO_APP_ANIMATOR = LaunchAnimator(DIALOG_TIMINGS, INTERPOLATORS) + /** Durations & interpolators for the navigation bar fading in & out. */ private const val ANIMATION_DURATION_NAV_FADE_IN = 266L private const val ANIMATION_DURATION_NAV_FADE_OUT = 133L @@ -117,6 +120,22 @@ class ActivityLaunchAnimator( /** The set of [Listener] that should be notified of any animation started by this animator. */ private val listeners = LinkedHashSet<Listener>() + /** Top-level listener that can be used to notify all registered [listeners]. */ + private val lifecycleListener = + object : Listener { + override fun onLaunchAnimationStart() { + listeners.forEach { it.onLaunchAnimationStart() } + } + + override fun onLaunchAnimationEnd() { + listeners.forEach { it.onLaunchAnimationEnd() } + } + + override fun onLaunchAnimationProgress(linearProgress: Float) { + listeners.forEach { it.onLaunchAnimationProgress(linearProgress) } + } + } + /** * Start an intent and animate the opening window. The intent will be started by running * [intentStarter], which should use the provided [RemoteAnimationAdapter] and return the launch @@ -156,7 +175,7 @@ class ActivityLaunchAnimator( ?: throw IllegalStateException( "ActivityLaunchAnimator.callback must be set before using this animator" ) - val runner = Runner(controller) + val runner = createRunner(controller) val hideKeyguardWithAnimation = callback.isOnKeyguard() && !showOverLockscreen // Pass the RemoteAnimationAdapter to the intent starter only if we are not hiding the @@ -256,7 +275,18 @@ class ActivityLaunchAnimator( } /** Create a new animation [Runner] controlled by [controller]. */ - @VisibleForTesting fun createRunner(controller: Controller): Runner = Runner(controller) + @VisibleForTesting + fun createRunner(controller: Controller): Runner { + // Make sure we use the modified timings when animating a dialog into an app. + val launchAnimator = + if (controller.isDialogLaunch) { + dialogToAppAnimator + } else { + launchAnimator + } + + return Runner(controller, callback!!, launchAnimator, lifecycleListener) + } interface PendingIntentStarter { /** @@ -353,14 +383,20 @@ class ActivityLaunchAnimator( * this if the animation was already started, i.e. if [onLaunchAnimationStart] was called * before the cancellation. * - * If this launch animation affected the occlusion state of the keyguard, WM will provide - * us with [newKeyguardOccludedState] so that we can set the occluded state appropriately. + * If this launch animation affected the occlusion state of the keyguard, WM will provide us + * with [newKeyguardOccludedState] so that we can set the occluded state appropriately. */ fun onLaunchAnimationCancelled(newKeyguardOccludedState: Boolean? = null) {} } - @VisibleForTesting - inner class Runner(private val controller: Controller) : IRemoteAnimationRunner.Stub() { + class Runner( + private val controller: Controller, + private val callback: Callback, + /** The animator to use to animate the window launch. */ + private val launchAnimator: LaunchAnimator = DEFAULT_LAUNCH_ANIMATOR, + /** Listener for animation lifecycle events. */ + private val listener: Listener? = null + ) : IRemoteAnimationRunner.Stub() { private val launchContainer = controller.launchContainer private val context = launchContainer.context private val transactionApplierView = @@ -448,18 +484,9 @@ class ActivityLaunchAnimator( left = windowBounds.left, right = windowBounds.right ) - val callback = this@ActivityLaunchAnimator.callback!! val windowBackgroundColor = window.taskInfo?.let { callback.getBackgroundColor(it) } ?: window.backgroundColor - // Make sure we use the modified timings when animating a dialog into an app. - val launchAnimator = - if (controller.isDialogLaunch) { - dialogToAppAnimator - } else { - launchAnimator - } - // TODO(b/184121838): We should somehow get the top and bottom radius of the window // instead of recomputing isExpandingFullyAbove here. val isExpandingFullyAbove = @@ -483,12 +510,12 @@ class ActivityLaunchAnimator( val controller = object : Controller by delegate { override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) { - listeners.forEach { it.onLaunchAnimationStart() } + listener?.onLaunchAnimationStart() delegate.onLaunchAnimationStart(isExpandingFullyAbove) } override fun onLaunchAnimationEnd(isExpandingFullyAbove: Boolean) { - listeners.forEach { it.onLaunchAnimationEnd() } + listener?.onLaunchAnimationEnd() iCallback?.invoke() delegate.onLaunchAnimationEnd(isExpandingFullyAbove) } @@ -505,7 +532,7 @@ class ActivityLaunchAnimator( } navigationBar?.let { applyStateToNavigationBar(it, state, linearProgress) } - listeners.forEach { it.onLaunchAnimationProgress(linearProgress) } + listener?.onLaunchAnimationProgress(linearProgress) delegate.onLaunchAnimationProgress(state, progress, linearProgress) } } diff --git a/packages/SystemUI/compose/features/AndroidManifest.xml b/packages/SystemUI/compose/features/AndroidManifest.xml index 278a89f7dba3..c1a9ec55c227 100644 --- a/packages/SystemUI/compose/features/AndroidManifest.xml +++ b/packages/SystemUI/compose/features/AndroidManifest.xml @@ -16,43 +16,6 @@ --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:tools="http://schemas.android.com/tools" - package="com.android.systemui.compose.features"> - <application - android:name="android.app.Application" - android:appComponentFactory="androidx.core.app.AppComponentFactory" - tools:replace="android:name,android:appComponentFactory"> - <!-- Disable providers from SystemUI --> - <provider android:name="com.android.systemui.keyguard.KeyguardSliceProvider" - android:authorities="com.android.systemui.test.keyguard.disabled" - android:enabled="false" - tools:replace="android:authorities" - tools:node="remove" /> - <provider android:name="com.google.android.systemui.keyguard.KeyguardSliceProviderGoogle" - android:authorities="com.android.systemui.test.keyguard.disabled" - android:enabled="false" - tools:replace="android:authorities" - tools:node="remove" /> - <provider android:name="com.android.systemui.keyguard.KeyguardQuickAffordanceProvider" - android:authorities="com.android.systemui.test.keyguard.quickaffordance.disabled" - android:enabled="false" - tools:replace="android:authorities" - tools:node="remove" /> - <provider android:name="com.android.keyguard.clock.ClockOptionsProvider" - android:authorities="com.android.systemui.test.keyguard.clock.disabled" - android:enabled="false" - tools:replace="android:authorities" - tools:node="remove" /> - <provider android:name="com.android.systemui.people.PeopleProvider" - android:authorities="com.android.systemui.test.people.disabled" - android:enabled="false" - tools:replace="android:authorities" - tools:node="remove" /> - <provider android:name="androidx.core.content.FileProvider" - android:authorities="com.android.systemui.test.fileprovider.disabled" - android:enabled="false" - tools:replace="android:authorities" - tools:node="remove"/> - </application> + </manifest> diff --git a/packages/SystemUI/compose/features/tests/AndroidManifest.xml b/packages/SystemUI/compose/features/tests/AndroidManifest.xml index 5e54c1f353d2..2fa475d63607 100644 --- a/packages/SystemUI/compose/features/tests/AndroidManifest.xml +++ b/packages/SystemUI/compose/features/tests/AndroidManifest.xml @@ -15,10 +15,46 @@ --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" package="com.android.systemui.compose.features.tests" > - <application> + <application + android:name="android.app.Application" + android:appComponentFactory="androidx.core.app.AppComponentFactory" + tools:replace="android:name,android:appComponentFactory"> <uses-library android:name="android.test.runner" /> + + <!-- Disable providers from SystemUI --> + <provider android:name="com.android.systemui.keyguard.KeyguardSliceProvider" + android:authorities="com.android.systemui.test.keyguard.disabled" + android:enabled="false" + tools:replace="android:authorities" + tools:node="remove" /> + <provider android:name="com.google.android.systemui.keyguard.KeyguardSliceProviderGoogle" + android:authorities="com.android.systemui.test.keyguard.disabled" + android:enabled="false" + tools:replace="android:authorities" + tools:node="remove" /> + <provider android:name="com.android.systemui.keyguard.KeyguardQuickAffordanceProvider" + android:authorities="com.android.systemui.test.keyguard.quickaffordance.disabled" + android:enabled="false" + tools:replace="android:authorities" + tools:node="remove" /> + <provider android:name="com.android.keyguard.clock.ClockOptionsProvider" + android:authorities="com.android.systemui.test.keyguard.clock.disabled" + android:enabled="false" + tools:replace="android:authorities" + tools:node="remove" /> + <provider android:name="com.android.systemui.people.PeopleProvider" + android:authorities="com.android.systemui.test.people.disabled" + android:enabled="false" + tools:replace="android:authorities" + tools:node="remove" /> + <provider android:name="androidx.core.content.FileProvider" + android:authorities="com.android.systemui.test.fileprovider.disabled" + android:enabled="false" + tools:replace="android:authorities" + tools:node="remove"/> </application> <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/quickaffordance/shared/model/KeyguardQuickAffordancePreviewConstants.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/quickaffordance/shared/model/KeyguardQuickAffordancePreviewConstants.kt new file mode 100644 index 000000000000..18e8a962dc70 --- /dev/null +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/quickaffordance/shared/model/KeyguardQuickAffordancePreviewConstants.kt @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.android.systemui.shared.quickaffordance.shared.model + +object KeyguardQuickAffordancePreviewConstants { + const val MESSAGE_ID_SLOT_SELECTED = 1337 + const val KEY_SLOT_ID = "slot_id" + const val KEY_INITIALLY_SELECTED_SLOT_ID = "initially_selected_slot_id" +} diff --git a/packages/SystemUI/res-keyguard/values-in/strings.xml b/packages/SystemUI/res-keyguard/values-in/strings.xml index 20d32f187d2e..12f96739071c 100644 --- a/packages/SystemUI/res-keyguard/values-in/strings.xml +++ b/packages/SystemUI/res-keyguard/values-in/strings.xml @@ -84,7 +84,7 @@ <string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Perangkat dikunci oleh admin"</string> <string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Perangkat dikunci secara manual"</string> <string name="kg_face_not_recognized" msgid="7903950626744419160">"Tidak dikenali"</string> - <string name="kg_face_sensor_privacy_enabled" msgid="939511161763558512">"Untuk pakai Face Unlock, beri akses kamera di Setelan"</string> + <string name="kg_face_sensor_privacy_enabled" msgid="939511161763558512">"Untuk pakai Buka dengan Wajah, beri akses kamera di Setelan"</string> <string name="kg_password_default_pin_message" msgid="1434544655827987873">"{count,plural, =1{Masukkan PIN SIM. Tersisa # percobaan lagi sebelum Anda harus menghubungi operator untuk membuka kunci perangkat.}other{Masukkan PIN SIM. Tersisa # percobaan lagi.}}"</string> <string name="kg_password_default_puk_message" msgid="1025139786449741950">"{count,plural, =1{SIM kini dinonaktifkan. Masukkan kode PUK untuk melanjutkan. Tersisa # percobaan lagi sebelum SIM tidak dapat digunakan secara permanen. Hubungi operator untuk mengetahui detailnya.}other{SIM kini dinonaktifkan. Masukkan kode PUK untuk melanjutkan. Tersisa # percobaan lagi sebelum SIM tidak dapat digunakan secara permanen. Hubungi operator untuk mengetahui detailnya.}}"</string> <string name="clock_title_default" msgid="6342735240617459864">"Default"</string> diff --git a/packages/SystemUI/res/drawable/keyguard_bottom_affordance_bg.xml b/packages/SystemUI/res/drawable/keyguard_bottom_affordance_bg.xml index 41123c84ded1..18fcebbb65a0 100644 --- a/packages/SystemUI/res/drawable/keyguard_bottom_affordance_bg.xml +++ b/packages/SystemUI/res/drawable/keyguard_bottom_affordance_bg.xml @@ -16,13 +16,53 @@ * limitations under the License. */ --> -<shape +<selector xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" - android:shape="rectangle"> - <solid android:color="?androidprv:attr/colorSurface"/> - <size - android:width="@dimen/keyguard_affordance_width" - android:height="@dimen/keyguard_affordance_height"/> - <corners android:radius="@dimen/keyguard_affordance_fixed_radius"/> -</shape> + xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> + + <item android:state_selected="true"> + <layer-list> + <item + android:left="3dp" + android:top="3dp" + android:right="3dp" + android:bottom="3dp"> + <shape android:shape="oval"> + <solid android:color="?androidprv:attr/colorSurface"/> + <size + android:width="@dimen/keyguard_affordance_width" + android:height="@dimen/keyguard_affordance_height"/> + </shape> + </item> + + <item> + <shape android:shape="oval"> + <stroke + android:color="@color/control_primary_text" + android:width="2dp"/> + <size + android:width="@dimen/keyguard_affordance_width" + android:height="@dimen/keyguard_affordance_height"/> + </shape> + </item> + </layer-list> + </item> + + <item> + <layer-list> + <item + android:left="3dp" + android:top="3dp" + android:right="3dp" + android:bottom="3dp"> + <shape android:shape="oval"> + <solid android:color="?androidprv:attr/colorSurface"/> + <size + android:width="@dimen/keyguard_affordance_width" + android:height="@dimen/keyguard_affordance_height"/> + </shape> + </item> + </layer-list> + </item> + +</selector> diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index 16c615b9059d..fe6aebca7e21 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Hou op uitsaai"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Beskikbare toestelle vir oudio-uitsette."</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volume"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Hoe uitsaai werk"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"Saai uit"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Mense in jou omtrek met versoenbare Bluetooth-toestelle kan na die media luister wat jy uitsaai"</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera en mikrofoon is af"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# kennisgewing}other{# kennisgewings}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"Neem notas"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Uitsaai"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Hou op om <xliff:g id="APP_NAME">%1$s</xliff:g> uit te saai?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"As jy <xliff:g id="SWITCHAPP">%1$s</xliff:g> uitsaai of die uitvoer verander, sal jou huidige uitsending stop"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Saai <xliff:g id="SWITCHAPP">%1$s</xliff:g> uit"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Verander uitvoer"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Onbekend"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EE. d MMM."</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Maak <xliff:g id="APPNAME">%1$s</xliff:g> oop"</string> diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index 966701a26ff5..93d63791a710 100644 --- a/packages/SystemUI/res/values-am/strings.xml +++ b/packages/SystemUI/res/values-am/strings.xml @@ -998,7 +998,6 @@ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> ያሰራጩ"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"ውፅዓትን ይቀይሩ"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"ያልታወቀ"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE፣ MMM d"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> ይክፈቱ"</string> diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index eae26f050e90..dad19abb1d54 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"إيقاف البث"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"الأجهزة المتاحة لإخراج الصوت"</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"مستوى الصوت"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"%%<xliff:g id="PERCENTAGE">%1$d</xliff:g>"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"كيفية عمل البث"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"البث"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"يمكن للأشخاص القريبين منك الذين لديهم أجهزة متوافقة تتضمّن بلوتوث الاستماع إلى الوسائط التي تبثها."</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"الكاميرا والميكروفون غير مفعّلين."</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{إشعار واحد}zero{# إشعار}two{إشعاران}few{# إشعارات}many{# إشعارًا}other{# إشعار}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>، <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"تدوين الملاحظات"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"البث"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"هل تريد إيقاف بث تطبيق <xliff:g id="APP_NAME">%1$s</xliff:g>؟"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"إذا أجريت بث تطبيق <xliff:g id="SWITCHAPP">%1$s</xliff:g> أو غيَّرت جهاز الإخراج، سيتوقَف البث الحالي."</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"بث تطبيق <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"تغيير جهاز الإخراج"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"غير معروف"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE، d MMM"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"فتح \"<xliff:g id="APPNAME">%1$s</xliff:g>\""</string> diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml index 6fc82be36941..9c8aed6dc1eb 100644 --- a/packages/SystemUI/res/values-as/strings.xml +++ b/packages/SystemUI/res/values-as/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"কাষ্ট বন্ধ কৰক"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"অডিঅ\' আউটপুটৰ বাবে উপলব্ধ ডিভাইচ।"</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"ভলিউম"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"সম্প্ৰচাৰ কৰাটোৱে কেনেকৈ কাম কৰে"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"সম্প্ৰচাৰ"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"সমিল ব্লুটুথ ডিভাইচৰ সৈতে আপোনাৰ নিকটৱৰ্তী স্থানত থকা লোকসকলে আপুনি সম্প্ৰচাৰ কৰা মিডিয়াটো শুনিব পাৰে"</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"কেমেৰা আৰু মাইক অফ হৈ আছে"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# টা জাননী}one{# টা জাননী}other{# টা জাননী}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"টোকাগ্ৰহণ"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"সম্প্ৰচাৰণ"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g>ৰ সম্প্ৰচাৰ কৰা বন্ধ কৰিবনে?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"যদি আপুনি <xliff:g id="SWITCHAPP">%1$s</xliff:g>ৰ সম্প্ৰচাৰ কৰে অথবা আউটপুট সলনি কৰে, তেন্তে, আপোনাৰ বৰ্তমানৰ সম্প্ৰচাৰ বন্ধ হৈ যাব"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> সম্প্ৰচাৰ কৰক"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"আউটপুট সলনি কৰক"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"অজ্ঞাত"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, MMM d"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> খোলক"</string> diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml index e4e031a417cb..8870b6167055 100644 --- a/packages/SystemUI/res/values-az/strings.xml +++ b/packages/SystemUI/res/values-az/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Yayımı dayandırın"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Audio çıxış üçün əlçatan cihazlar."</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Səs"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Yayım necə işləyir"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"Yayım"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Uyğun Bluetooth cihazları olan yaxınlığınızdakı insanlar yayımladığınız medianı dinləyə bilər"</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera və mikrofon deaktivdir"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# bildiriş}other{# bildiriş}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"Qeyd tutma"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Yayım"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> tətbiqinin yayımlanması dayandırılsın?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> tətbiqini yayımlasanız və ya nəticəni dəyişsəniz, cari yayımınız dayandırılacaq"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> tətbiqini yayımlayın"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Nəticəni dəyişdirin"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Naməlum"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"HHH, AAA g"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"s:dd"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"ss:dd"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> tətbiqini açın"</string> @@ -1011,8 +1008,6 @@ <string name="rear_display_unfold_bottom_sheet_title" msgid="2137403802960396357">"Daha yaxşı selfi üçün ön displeyə çevrilsin?"</string> <string name="rear_display_bottom_sheet_description" msgid="1852662982816810352">"Daha yüksək ayırdetmə dəqiqliyi ilə daha geniş şəkil üçün arxaya baxan kameradan istifadə edin."</string> <string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Bu ekran deaktiv ediləcək"</b></string> - <!-- no translation found for rear_display_accessibility_folded_animation (1538121649587978179) --> - <skip /> - <!-- no translation found for rear_display_accessibility_unfolded_animation (1946153682258289040) --> - <skip /> + <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Qatlana bilən cihaz açılır"</string> + <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Qatlana bilən cihaz fırladılır"</string> </resources> diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml index bd964f955a00..35cbed93d906 100644 --- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml +++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml @@ -993,7 +993,6 @@ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Emitujte aplikaciju <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Promenite izlaz"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Nepoznato"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"DDD, d. MMM"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"s:min"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"č:min"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Otvorite: <xliff:g id="APPNAME">%1$s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml index 31c9bcc49ebb..c653c7a4857c 100644 --- a/packages/SystemUI/res/values-be/strings.xml +++ b/packages/SystemUI/res/values-be/strings.xml @@ -723,7 +723,7 @@ <string name="instant_apps_title" msgid="8942706782103036910">"Праграма \"<xliff:g id="APP">%1$s</xliff:g>\" запушчана"</string> <string name="instant_apps_message" msgid="6112428971833011754">"Праграма адкрыта без усталёўкі."</string> <string name="instant_apps_message_with_help" msgid="1816952263531203932">"Праграма адкрыта без усталёўкі. Націсніце, каб даведацца больш."</string> - <string name="app_info" msgid="5153758994129963243">"Звесткі пра праграму"</string> + <string name="app_info" msgid="5153758994129963243">"Звесткі аб праграме"</string> <string name="go_to_web" msgid="636673528981366511">"Перайсці ў браўзер"</string> <string name="mobile_data" msgid="4564407557775397216">"Маб. перадача даных"</string> <string name="mobile_data_text_format" msgid="6806501540022589786">"<xliff:g id="ID_1">%1$s</xliff:g> — <xliff:g id="ID_2">%2$s</xliff:g>"</string> @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Спыніць трансляцыю"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Даступныя прылады для вываду аўдыя."</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Гучнасць"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Як адбываецца трансляцыя"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"Трансляцыя"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Людзі паблізу, у якіх ёсць прылады з Bluetooth, змогуць праслухваць мультымедыйнае змесціва, якое вы трансліруеце"</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Камера і мікрафон выключаны"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# апавяшчэнне}one{# апавяшчэнне}few{# апавяшчэнні}many{# апавяшчэнняў}other{# апавяшчэння}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"Стварэнне нататак"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Перадача даных"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Спыніць трансляцыю праграмы \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Пры пераключэнні на праграму \"<xliff:g id="SWITCHAPP">%1$s</xliff:g>\" ці змяненні вываду бягучая трансляцыя спыняецца"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Трансляцыя праграмы \"<xliff:g id="SWITCHAPP">%1$s</xliff:g>\""</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Змяненне вываду"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Невядома"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, d MMM"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Адкрыць праграму \"<xliff:g id="APPNAME">%1$s</xliff:g>\""</string> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index c2860e95a807..cd2ad4d1c590 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Спиране на предаването"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Налични устройства за аудиоизход."</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Сила на звука"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Как работи предаването"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"Предаване"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Хората в близост със съвместими устройства с Bluetooth могат да слушат мултимедията, която предавате"</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Камерата и микрофонът са изключени"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# известие}other{# известия}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"Водене на бележки"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Излъчване"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Да се спре ли предаването на <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Ако предавате <xliff:g id="SWITCHAPP">%1$s</xliff:g> или промените изхода, текущото ви предаване ще бъде прекратено"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Предаване на <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Промяна на изхода"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Неизвестно"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, d MMM"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Отваряне на <xliff:g id="APPNAME">%1$s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml index 42fc489dff54..4d5e2a3f4945 100644 --- a/packages/SystemUI/res/values-bn/strings.xml +++ b/packages/SystemUI/res/values-bn/strings.xml @@ -993,7 +993,6 @@ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> সম্প্রচার করুন"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"আউটপুট পরিবর্তন করুন"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"অজানা"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, MMM d"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> খুলুন"</string> diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml index 62f0c5f9c507..cb4b2a563d31 100644 --- a/packages/SystemUI/res/values-bs/strings.xml +++ b/packages/SystemUI/res/values-bs/strings.xml @@ -986,14 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera i mikrofon su isključeni"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# obavještenje}one{# obavještenje}few{# obavještenja}other{# obavještenja}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <string name="note_task_button_label" msgid="8718616095800343136">"Pisanje bilježaka"</string> + <string name="note_task_button_label" msgid="8718616095800343136">"Pisanje bilješki"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Emitiranje"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Zaustaviti emitiranje aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Ako emitirate aplikaciju <xliff:g id="SWITCHAPP">%1$s</xliff:g> ili promijenite izlaz, trenutno emitiranje će se zaustaviti"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Emitiraj aplikaciju <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Promijeni izlaz"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Nepoznato"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"DDD, MMM d"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Otvori aplikaciju <xliff:g id="APPNAME">%1$s</xliff:g>"</string> @@ -1009,8 +1008,6 @@ <string name="rear_display_unfold_bottom_sheet_title" msgid="2137403802960396357">"Obrnuti na prednji ekran radi boljeg selfija?"</string> <string name="rear_display_bottom_sheet_description" msgid="1852662982816810352">"Koristite stražnju kameru za širu fotografiju veće rezolucije."</string> <string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Ekran će se isključiti"</b></string> - <!-- no translation found for rear_display_accessibility_folded_animation (1538121649587978179) --> - <skip /> - <!-- no translation found for rear_display_accessibility_unfolded_animation (1946153682258289040) --> - <skip /> + <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Rasklopljen sklopivi uređaj"</string> + <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Okretanje sklopivog uređaja sa svih strana"</string> </resources> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index 8f591bcb991a..68fa2dcff6f6 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Atura l\'emissió"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Dispositius disponibles per a la sortida d\'àudio."</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volum"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Com funciona l\'emissió"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"Emet"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Les persones properes amb dispositius Bluetooth compatibles poden escoltar el contingut multimèdia que emets"</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Càmera i micròfon desactivats"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificació}many{# notifications}other{# notificacions}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"Presa de notes"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"S\'està emetent"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Vols deixar d\'emetre <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Si emets <xliff:g id="SWITCHAPP">%1$s</xliff:g> o canvies la sortida, l\'emissió actual s\'aturarà"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Emet <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Canvia la sortida"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Desconeguda"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, d MMM"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"hh:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Obre <xliff:g id="APPNAME">%1$s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index c417d4460d31..6eb360bc9fb9 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Zastavit odesílání"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Dostupná zařízení pro zvukový výstup."</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Hlasitost"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Jak vysílání funguje"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"Vysílání"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Lidé ve vašem okolí s kompatibilními zařízeními Bluetooth mohou poslouchat média, která vysíláte"</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Fotoaparát a mikrofon jsou vypnuté"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# oznámení}few{# oznámení}many{# oznámení}other{# oznámení}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g> <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"Poznámky"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Vysílání"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Zastavit vysílání v aplikaci <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Pokud budete vysílat v aplikaci <xliff:g id="SWITCHAPP">%1$s</xliff:g> nebo změníte výstup, aktuální vysílání se zastaví"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Vysílat v aplikaci <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Změna výstupu"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Neznámé"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE d. MMMM"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"H:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Otevřít <xliff:g id="APPNAME">%1$s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index d4277a7dea85..3ba90870e93c 100644 --- a/packages/SystemUI/res/values-da/strings.xml +++ b/packages/SystemUI/res/values-da/strings.xml @@ -993,7 +993,6 @@ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Udsend <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Skift output"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Ukendt"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE d. MMM"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"tt.mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk.mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Åbn <xliff:g id="APPNAME">%1$s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index d1c88fb65c9c..c2d868c9b874 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Streaming beenden"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Für die Audioausgabe verfügbare Geräte."</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Lautstärke"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Funktionsweise von Nachrichten an alle"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"Nachricht an alle"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Personen, die in der Nähe sind und kompatible Bluetooth-Geräten haben, können sich die Medien anhören, die du per Nachricht an alle sendest"</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera und Mikrofon ausgeschaltet"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# Benachrichtigung}other{# Benachrichtigungen}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"Notizen machen"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Übertragung läuft"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> nicht mehr streamen?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Wenn du <xliff:g id="SWITCHAPP">%1$s</xliff:g> streamst oder die Ausgabe änderst, wird dein aktueller Stream beendet"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> streamen"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Ausgabe ändern"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Unbekannt"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, d. MMM"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> öffnen"</string> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index 84e18f0596ed..fd694885f0f0 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -993,7 +993,6 @@ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Μετάδοση με την εφαρμογή <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Αλλαγή εξόδου"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Άγνωστο"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"ΗΗΗ, ΜΜΜ η"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"ώ:λλ"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:λλ"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Άνοιγμα <xliff:g id="APPNAME">%1$s</xliff:g>"</string> @@ -1009,8 +1008,6 @@ <string name="rear_display_unfold_bottom_sheet_title" msgid="2137403802960396357">"Αναστροφή στην μπροστ. οθόνη για καλύτερη selfie;"</string> <string name="rear_display_bottom_sheet_description" msgid="1852662982816810352">"Χρησιμοποιήστε την πίσω κάμερα για να βγάλετε μια φωτογραφία με μεγαλύτερο εύρος και υψηλότερη ανάλυση."</string> <string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"* Αυτή η οθόνη θα απενεργοποιηθεί"</b></string> - <!-- no translation found for rear_display_accessibility_folded_animation (1538121649587978179) --> - <skip /> - <!-- no translation found for rear_display_accessibility_unfolded_animation (1946153682258289040) --> - <skip /> + <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Αναδιπλούμενη συσκευή που ξεδιπλώνει"</string> + <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Αναδιπλούμενη συσκευή που διπλώνει"</string> </resources> diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml index 133bb64ef08a..244865b79111 100644 --- a/packages/SystemUI/res/values-en-rAU/strings.xml +++ b/packages/SystemUI/res/values-en-rAU/strings.xml @@ -993,7 +993,6 @@ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Broadcast <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Change output"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Unknown"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, MMM d"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Open <xliff:g id="APPNAME">%1$s</xliff:g>"</string> @@ -1009,8 +1008,6 @@ <string name="rear_display_unfold_bottom_sheet_title" msgid="2137403802960396357">"Flip to front display for a better selfie?"</string> <string name="rear_display_bottom_sheet_description" msgid="1852662982816810352">"Use the rear-facing camera for a wider photo with higher resolution."</string> <string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ This screen will turn off"</b></string> - <!-- no translation found for rear_display_accessibility_folded_animation (1538121649587978179) --> - <skip /> - <!-- no translation found for rear_display_accessibility_unfolded_animation (1946153682258289040) --> - <skip /> + <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Foldable device being unfolded"</string> + <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Foldable device being flipped around"</string> </resources> diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml index 4caf4e042258..5cc99f97c172 100644 --- a/packages/SystemUI/res/values-en-rCA/strings.xml +++ b/packages/SystemUI/res/values-en-rCA/strings.xml @@ -993,7 +993,6 @@ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Broadcast <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Change output"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Unknown"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, MMM d"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Open <xliff:g id="APPNAME">%1$s</xliff:g>"</string> @@ -1009,8 +1008,6 @@ <string name="rear_display_unfold_bottom_sheet_title" msgid="2137403802960396357">"Flip to front display for a better selfie?"</string> <string name="rear_display_bottom_sheet_description" msgid="1852662982816810352">"Use the rear-facing camera for a wider photo with higher resolution."</string> <string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ This screen will turn off"</b></string> - <!-- no translation found for rear_display_accessibility_folded_animation (1538121649587978179) --> - <skip /> - <!-- no translation found for rear_display_accessibility_unfolded_animation (1946153682258289040) --> - <skip /> + <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Foldable device being unfolded"</string> + <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Foldable device being flipped around"</string> </resources> diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml index 133bb64ef08a..244865b79111 100644 --- a/packages/SystemUI/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/res/values-en-rGB/strings.xml @@ -993,7 +993,6 @@ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Broadcast <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Change output"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Unknown"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, MMM d"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Open <xliff:g id="APPNAME">%1$s</xliff:g>"</string> @@ -1009,8 +1008,6 @@ <string name="rear_display_unfold_bottom_sheet_title" msgid="2137403802960396357">"Flip to front display for a better selfie?"</string> <string name="rear_display_bottom_sheet_description" msgid="1852662982816810352">"Use the rear-facing camera for a wider photo with higher resolution."</string> <string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ This screen will turn off"</b></string> - <!-- no translation found for rear_display_accessibility_folded_animation (1538121649587978179) --> - <skip /> - <!-- no translation found for rear_display_accessibility_unfolded_animation (1946153682258289040) --> - <skip /> + <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Foldable device being unfolded"</string> + <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Foldable device being flipped around"</string> </resources> diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml index 133bb64ef08a..244865b79111 100644 --- a/packages/SystemUI/res/values-en-rIN/strings.xml +++ b/packages/SystemUI/res/values-en-rIN/strings.xml @@ -993,7 +993,6 @@ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Broadcast <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Change output"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Unknown"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, MMM d"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Open <xliff:g id="APPNAME">%1$s</xliff:g>"</string> @@ -1009,8 +1008,6 @@ <string name="rear_display_unfold_bottom_sheet_title" msgid="2137403802960396357">"Flip to front display for a better selfie?"</string> <string name="rear_display_bottom_sheet_description" msgid="1852662982816810352">"Use the rear-facing camera for a wider photo with higher resolution."</string> <string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ This screen will turn off"</b></string> - <!-- no translation found for rear_display_accessibility_folded_animation (1538121649587978179) --> - <skip /> - <!-- no translation found for rear_display_accessibility_unfolded_animation (1946153682258289040) --> - <skip /> + <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Foldable device being unfolded"</string> + <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Foldable device being flipped around"</string> </resources> diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml index abb548b4ad6a..cb79d1134512 100644 --- a/packages/SystemUI/res/values-en-rXC/strings.xml +++ b/packages/SystemUI/res/values-en-rXC/strings.xml @@ -993,7 +993,6 @@ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Broadcast <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Change output"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Unknown"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, MMM d"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Open <xliff:g id="APPNAME">%1$s</xliff:g>"</string> @@ -1009,8 +1008,6 @@ <string name="rear_display_unfold_bottom_sheet_title" msgid="2137403802960396357">"Flip to front display for a better selfie?"</string> <string name="rear_display_bottom_sheet_description" msgid="1852662982816810352">"Use the rear-facing camera for a wider photo with higher resolution."</string> <string name="rear_display_bottom_sheet_warning" msgid="800995919558238930">""<b>"✱ This screen will turn off"</b>""</string> - <!-- no translation found for rear_display_accessibility_folded_animation (1538121649587978179) --> - <skip /> - <!-- no translation found for rear_display_accessibility_unfolded_animation (1946153682258289040) --> - <skip /> + <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Foldable device being unfolded"</string> + <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Foldable device being flipped around"</string> </resources> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index 3527aaf4cee5..b91d1d62b398 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Detener transmisión"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Dispositivos disponibles para salida de audio."</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volumen"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Cómo funciona la transmisión"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"Transmisión"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Las personas cercanas con dispositivos Bluetooth compatibles pueden escuchar el contenido multimedia que transmites"</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"La cámara y el micrófono están apagados"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificación}many{# notificaciones}other{# notificaciones}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"Tomar notas"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Transmitiendo"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"¿Quieres dejar de transmitir <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Si transmites <xliff:g id="SWITCHAPP">%1$s</xliff:g> o cambias la salida, tu transmisión actual se detendrá"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Transmitir <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Cambia la salida"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Desconocido"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, d de MMM"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Abrir <xliff:g id="APPNAME">%1$s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index dcc52b558a74..e30b0e9fb804 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Dejar de enviar contenido"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Dispositivos disponibles para la salida de audio."</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volumen"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Cómo funciona la emisión"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"Emisión"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Las personas cercanas con dispositivos Bluetooth compatibles pueden escuchar el contenido multimedia que emites"</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"La cámara y el micrófono están desactivados"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificación}many{# notificaciones}other{# notificaciones}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"Tomar notas"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Emitiendo"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"¿Dejar de emitir <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Si emites <xliff:g id="SWITCHAPP">%1$s</xliff:g> o cambias la salida, tu emisión actual se detendrá"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Emitir <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Cambiar salida"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Desconocido"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, d MMM"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Abrir <xliff:g id="APPNAME">%1$s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml index afba616a85bd..cd1445b5b4df 100644 --- a/packages/SystemUI/res/values-et/strings.xml +++ b/packages/SystemUI/res/values-et/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Lõpeta ülekanne"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Saadaolevad seadmed heli esitamiseks."</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Helitugevus"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Kuidas ülekandmine toimib?"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"Ülekanne"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Teie läheduses olevad inimesed, kellel on ühilduvad Bluetooth-seadmed, saavad kuulata teie ülekantavat meediat"</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kaamera ja mikrofon on välja lülitatud"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# märguanne}other{# märguannet}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"Märkmete tegemine"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Edastamine"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Kas peatada rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> ülekandmine?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Kui kannate rakendust <xliff:g id="SWITCHAPP">%1$s</xliff:g> üle või muudate väljundit, peatatakse teie praegune ülekanne"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Rakenduse <xliff:g id="SWITCHAPP">%1$s</xliff:g> ülekandmine"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Väljundi muutmine"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Tundmatu"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, d. MMM"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Ava <xliff:g id="APPNAME">%1$s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml index 9ded73a98c26..f9508d17106d 100644 --- a/packages/SystemUI/res/values-eu/strings.xml +++ b/packages/SystemUI/res/values-eu/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Gelditu igorpena"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Audio-irteerarako gailu erabilgarriak."</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Bolumena"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"%% <xliff:g id="PERCENTAGE">%1$d</xliff:g>"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Nola funtzionatzen dute iragarpenek?"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"Iragarri"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Bluetooth bidezko gailu bateragarriak dituzten inguruko pertsonek iragartzen ari zaren multimedia-edukia entzun dezakete"</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera eta mikrofonoa desaktibatuta daude"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# jakinarazpen}other{# jakinarazpen}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"Oharrak idaztea"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Igortzen"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioaren audioa igortzeari utzi nahi diozu?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> aplikazioaren audioa igortzen baduzu, edo audio-irteera aldatzen baduzu, une hartako igorpena eten egingo da"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Igorri <xliff:g id="SWITCHAPP">%1$s</xliff:g> aplikazioaren audioa"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Aldatu audio-irteera"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Ezezaguna"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, MMM d"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Ireki <xliff:g id="APPNAME">%1$s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index c93803e96ce5..bb195ce9d659 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"توقف پخش محتوا"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"دستگاههای دردسترس برای خروجی صدا."</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"میزان صدا"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"همهفرتستی چطور کار میکند"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"همهفرستی"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"افرادی که در اطرافتان دستگاههای Bluetooth سازگار دارند میتوانند به رسانهای که همهفرستی میکنید گوش کنند"</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"دوربین و میکروفون خاموش هستند"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# اعلان}one{# اعلان}other{# اعلان}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>، <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"یادداشتبرداری"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"همهفرستی"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"همهفرستی <xliff:g id="APP_NAME">%1$s</xliff:g> متوقف شود؟"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"اگر <xliff:g id="SWITCHAPP">%1$s</xliff:g> را همهفرستی کنید یا خروجی را تغییر دهید، همهفرستی کنونی متوقف خواهد شد"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"همهفرستی <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"تغییر خروجی"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"نامشخص"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE d MMM"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"باز کردن <xliff:g id="APPNAME">%1$s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index d3b2da3577c0..0783c15871e9 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Lopeta striimaus"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Käytettävissä olevat audiolaitteet"</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Äänenvoimakkuus"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Miten lähetys toimii"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"Lähetys"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Lähistöllä olevat ihmiset, joilla on yhteensopiva Bluetooth-laite, voivat kuunnella lähettämääsi mediaa"</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera ja mikrofoni ovat pois päältä"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# ilmoitus}other{# ilmoitusta}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"Muistiinpanojen tekeminen"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Lähettää"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Lopetetaanko <xliff:g id="APP_NAME">%1$s</xliff:g>-sovelluksen lähettäminen?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Jos lähetät <xliff:g id="SWITCHAPP">%1$s</xliff:g>-sovellusta tai muutat ulostuloa, nykyinen lähetyksesi loppuu"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Lähetä <xliff:g id="SWITCHAPP">%1$s</xliff:g>-sovellusta"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Muuta ulostuloa"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Tuntematon"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"VKP, KKK p"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Avaa <xliff:g id="APPNAME">%1$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 0300e9cb4c78..15a57b0a1b23 100644 --- a/packages/SystemUI/res/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Arrêter la diffusion"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Appareils disponibles pour la sortie audio."</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volume"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Fonctionnement de la diffusion"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"Diffusion"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Les personnes à proximité disposant d\'appareils Bluetooth compatibles peuvent écouter le contenu multimédia que vous diffusez"</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"L\'appareil photo et le micro sont désactivés"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notification}one{# notification}many{# de notifications}other{# notifications}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"Prise de note"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Diffusion en cours…"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Arrêter la diffusion de <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Si vous diffusez <xliff:g id="SWITCHAPP">%1$s</xliff:g> ou changez la sortie, votre diffusion actuelle s\'arrêtera"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Diffuser <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Changer la sortie"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Inconnue"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, d MMM"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Ouvrir <xliff:g id="APPNAME">%1$s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index c1d58ebcaa5a..a1c6e36b5a25 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Arrêter la diffusion"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Appareils disponibles pour la sortie audio."</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volume"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Fonctionnement des annonces"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"Annonce"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Les personnes à proximité équipées d\'appareils Bluetooth compatibles peuvent écouter le contenu multimédia que vous diffusez"</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Appareil photo et micro désactivés"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notification}one{# notification}many{# notifications}other{# notifications}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"Prendre des notes"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Diffusion…"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Arrêter la diffusion de <xliff:g id="APP_NAME">%1$s</xliff:g> ?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Si vous diffusez <xliff:g id="SWITCHAPP">%1$s</xliff:g> ou que vous modifiez le résultat, votre annonce actuelle s\'arrêtera"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Diffuser <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Modifier le résultat"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Inconnue"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, MMM j"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"hh:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Ouvrir <xliff:g id="APPNAME">%1$s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml index c1daa9863b60..60d2e0a3ee2f 100644 --- a/packages/SystemUI/res/values-gl/strings.xml +++ b/packages/SystemUI/res/values-gl/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Deter emisión"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Dispositivos dispoñibles para a saída de audio."</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volume"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Como funcionan as difusións?"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"Difusión"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"As persoas que estean preto de ti e que dispoñan de dispositivos Bluetooth compatibles poden escoitar o contido multimedia que difundas"</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"A cámara e o micrófono están desactivados"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificación}other{# notificacións}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"Toma de notas"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Difusión"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Queres deixar de emitir contido a través de <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Se emites contido a través de <xliff:g id="SWITCHAPP">%1$s</xliff:g> ou cambias de saída, a emisión en curso deterase"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Emitir contido a través de <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Cambiar de saída"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Descoñecida"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, d MMM"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Abrir <xliff:g id="APPNAME">%1$s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml index 6e306c826166..d9572efc160f 100644 --- a/packages/SystemUI/res/values-gu/strings.xml +++ b/packages/SystemUI/res/values-gu/strings.xml @@ -993,7 +993,6 @@ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> બ્રોડકાસ્ટ કરો"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"આઉટપુટ બદલો"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"અજાણ"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, d MMM"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> ખોલો"</string> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index 5dba4665cac8..6f34cff12d17 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"कास्टिंग करना रोकें"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"ऑडियो आउटपुट के लिए उपलब्ध डिवाइस."</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"वॉल्यूम"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ब्रॉडकास्ट करने की सुविधा कैसे काम करती है"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"ब्रॉडकास्ट करें"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"आपके आस-पास मौजूद लोग, ब्रॉडकास्ट किए जा रहे मीडिया को सुन सकते हैं. हालांकि, इसके लिए उनके पास ऐसे ब्लूटूथ डिवाइस होने चाहिए जिन पर मीडिया चलाया जा सके"</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"कैमरा और माइक बंद हैं"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# सूचना}one{# सूचना}other{# सूचनाएं}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"नोट बनाएं"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"ब्रॉडकास्ट ऐप्लिकेशन"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> पर ब्रॉडकास्ट करना रोकें?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> पर ब्रॉडकास्ट शुरू करने पर या आउटपुट बदलने पर, आपका मौजूदा ब्रॉडकास्ट बंद हो जाएगा"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> पर ब्रॉडकास्ट करें"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"आउटपुट बदलें"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"कोई जानकारी नहीं"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, MMM d"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> खोलें"</string> diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index 13f43be0e650..7e7a0d9e343d 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -993,7 +993,6 @@ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Emitiranje aplikacije <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Promjena izlaza"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Nepoznato"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE., d. MMM."</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Otvorite <xliff:g id="APPNAME">%1$s</xliff:g>"</string> @@ -1009,8 +1008,6 @@ <string name="rear_display_unfold_bottom_sheet_title" msgid="2137403802960396357">"Prebaciti na prednji zaslon za bolji selfie?"</string> <string name="rear_display_bottom_sheet_description" msgid="1852662982816810352">"Upotrijebite stražnji fotoaparat za širu fotografiju s višom razlučivošću."</string> <string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Ovaj će se zaslon isključiti"</b></string> - <!-- no translation found for rear_display_accessibility_folded_animation (1538121649587978179) --> - <skip /> - <!-- no translation found for rear_display_accessibility_unfolded_animation (1946153682258289040) --> - <skip /> + <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Rasklopljen sklopivi uređaj"</string> + <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Okretanje sklopivog uređaja sa svih strana"</string> </resources> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index 7c816c739217..9624acd79847 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Átküldés leállítása"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Rendelkezésre álló eszközök a hangkimenethez."</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Hangerő"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"A közvetítés működése"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"Közvetítés"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"A közelben tartózkodó, kompatibilis Bluetooth-eszközzel rendelkező személyek meghallgathatják az Ön közvetített médiatartalmait"</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"A kamera és a mikrofon ki vannak kapcsolva"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# értesítés}other{# értesítés}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"Jegyzetelés"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Sugárzás"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Leállítja a(z) <xliff:g id="APP_NAME">%1$s</xliff:g> közvetítését?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"A(z) <xliff:g id="SWITCHAPP">%1$s</xliff:g> közvetítése vagy a kimenet módosítása esetén a jelenlegi közvetítés leáll"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> közvetítése"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Kimenet módosítása"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Ismeretlen"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, HHH n"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"ó:pp"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"óó:pp"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"A(z) <xliff:g id="APPNAME">%1$s</xliff:g> megnyitása"</string> diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml index ea6023734fba..61357e51c351 100644 --- a/packages/SystemUI/res/values-hy/strings.xml +++ b/packages/SystemUI/res/values-hy/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Կանգնեցնել հեռարձակումը"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Հասանելի սարքեր ձայնի արտածման համար։"</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Ձայնի ուժգնություն"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Ինչպես է աշխատում հեռարձակումը"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"Հեռարձակում"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Ձեր մոտակայքում գտնվող՝ համատեղելի Bluetooth սարքերով մարդիկ կարող են լսել մեդիա ֆայլերը, որոնք դուք հեռարձակում եք։"</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Տեսախցիկը և խոսափողն անջատված են"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# ծանուցում}one{# ծանուցում}other{# ծանուցում}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"Նշումների ստեղծում"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Հեռարձակում"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Կանգնեցնել <xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածի հեռարձակումը"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Եթե հեռարձակեք <xliff:g id="SWITCHAPP">%1$s</xliff:g> հավելվածը կամ փոխեք աուդիո ելքը, ձեր ընթացիկ հեռարձակումը կկանգնեցվի։"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Հեռարձակել <xliff:g id="SWITCHAPP">%1$s</xliff:g> հավելվածը"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Փոխել աուդիո ելքը"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Անհայտ"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, MMM d"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Բացել <xliff:g id="APPNAME">%1$s</xliff:g> հավելվածը"</string> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index 3cdb26e4ed5e..84ae4d44d4a2 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Hentikan transmisi"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Perangkat yang tersedia untuk output audio."</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volume"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Cara kerja siaran"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"Siaran"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Orang di dekat Anda dengan perangkat Bluetooth yang kompatibel dapat mendengarkan media yang sedang Anda siarkan"</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera dan mikrofon nonaktif"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notifikasi}other{# notifikasi}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"Pembuatan catatan"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Menyiarkan"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Hentikan siaran <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Jika Anda menyiarkan <xliff:g id="SWITCHAPP">%1$s</xliff:g> atau mengubah output, siaran saat ini akan dihentikan"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Siarkan <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Ubah output"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Tidak diketahui"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, d MMM"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Buka <xliff:g id="APPNAME">%1$s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml index 7c715382c008..85f7b721fc3a 100644 --- a/packages/SystemUI/res/values-is/strings.xml +++ b/packages/SystemUI/res/values-is/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Stöðva útsendingu"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Tæki í boði fyrir hljóðúttak."</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Hljóðstyrkur"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Svona virkar útsending"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"Útsending"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Fólk nálægt þér með samhæf Bluetooth-tæki getur hlustað á efnið sem þú sendir út"</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Slökkt á myndavél og hljóðnema"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# tilkynning}one{# tilkynning}other{# tilkynningar}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"Glósugerð"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Útsending í gangi"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Hætta að senda út <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Ef þú sendir út <xliff:g id="SWITCHAPP">%1$s</xliff:g> eða skiptir um úttak lýkur yfirstandandi útsendingu"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Senda út <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Skipta um úttak"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Óþekkt"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, MMM d"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"k:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Opna <xliff:g id="APPNAME">%1$s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index f6c83543b2ff..0ca503df4ae0 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Interrompi trasmissione"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Dispositivi disponibili per l\'uscita audio."</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volume"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Come funziona la trasmissione"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"Annuncio"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Le persone vicine a te che hanno dispositivi Bluetooth compatibili possono ascoltare i contenuti multimediali che stai trasmettendo"</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Fotocamera e microfono non attivi"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notifica}many{# notifiche}other{# notifiche}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"Aggiunta di note"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Trasmissione in corso…"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Vuoi interrompere la trasmissione dell\'app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Se trasmetti l\'app <xliff:g id="SWITCHAPP">%1$s</xliff:g> o cambi l\'uscita, la trasmissione attuale viene interrotta"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Trasmetti l\'app <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Cambia uscita"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Unknown"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, MMM g"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Apri <xliff:g id="APPNAME">%1$s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index 8e12a0b92f24..5df872b350c7 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"עצירת ההעברה (casting)"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"מכשירים זמינים לפלט אודיו."</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"עוצמת הקול"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"הסבר על שידורים"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"שידור"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"אנשים בקרבת מקום עם מכשירי Bluetooth תואמים יכולים להאזין למדיה שמשודרת על ידך"</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"המצלמה והמיקרופון כבויים"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{התראה אחת}one{# התראות}two{# התראות}other{# התראות}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"כתיבת הערות"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"שידור"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"האם להפסיק לשדר את התוכן מאפליקציית <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"אם משדרים את התוכן מאפליקציית <xliff:g id="SWITCHAPP">%1$s</xliff:g> או משנים את הפלט, השידור הנוכחי יפסיק לפעול"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"שידור תוכן מאפליקציית <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"שינוי הפלט"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"לא ידוע"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"יום EEE, d בMMM"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"פתיחת <xliff:g id="APPNAME">%1$s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index 0cacdbdaa724..f15540cc28ef 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -993,7 +993,6 @@ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> をブロードキャスト"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"出力を変更"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"不明"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, MMM d"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> を開く"</string> diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml index 038937dd1027..0626dd62d931 100644 --- a/packages/SystemUI/res/values-ka/strings.xml +++ b/packages/SystemUI/res/values-ka/strings.xml @@ -993,7 +993,6 @@ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g>-ის ტრანსლაცია"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"აუდიოს გამოსასვლელის შეცვლა"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"უცნობი"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"დდდ, თთთ თ"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"სთ:წთ"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"სთ:წთ"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> აპის გახსნა"</string> diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml index 91c0b3596de5..1692bd4c392c 100644 --- a/packages/SystemUI/res/values-kk/strings.xml +++ b/packages/SystemUI/res/values-kk/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Трансляцияны тоқтату"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Аудио шығыс үшін қолжетімді құрылғылар бар."</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Дыбыс деңгейі"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Тарату қалай жүзеге асады"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"Тарату"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Үйлесімді Bluetooth құрылғылары бар маңайдағы адамдар сіз таратып жатқан медиамазмұнды тыңдай алады."</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Камера мен микрофон өшірулі"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# хабарландыру}other{# хабарландыру}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"Ескертпе жазу"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Таратуда"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасын таратуды тоқтатасыз ба?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> қолданбасын таратсаңыз немесе аудио шығысын өзгертсеңіз, қазіргі тарату сеансы тоқтайды."</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> қолданбасын тарату"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Аудио шығысын өзгерту"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Белгісіз"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"d MMM EEEE"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> ашу"</string> diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml index 51e5b53c7f22..9158663983c7 100644 --- a/packages/SystemUI/res/values-km/strings.xml +++ b/packages/SystemUI/res/values-km/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"បញ្ឈប់ការភ្ជាប់"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"ឧបករណ៍ដែលអាចប្រើបានសម្រាប់ឧបករណ៍បញ្ចេញសំឡេង។"</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"កម្រិតសំឡេង"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"របៀបដែលការផ្សាយដំណើរការ"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"ការផ្សាយ"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"មនុស្សនៅជិតអ្នកដែលមានឧបករណ៍ប៊្លូធូសត្រូវគ្នាអាចស្តាប់មេឌៀដែលអ្នកកំពុងផ្សាយបាន"</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"កាមេរ៉ា និងមីក្រូហ្វូនត្រូវបានបិទ"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{ការជូនដំណឹង #}other{ការជូនដំណឹង #}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"ការកត់ត្រា"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"ការផ្សាយ"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"បញ្ឈប់ការផ្សាយ <xliff:g id="APP_NAME">%1$s</xliff:g> ឬ?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"ប្រសិនបើអ្នកផ្សាយ <xliff:g id="SWITCHAPP">%1$s</xliff:g> ឬប្ដូរឧបករណ៍បញ្ចេញសំឡេង ការផ្សាយបច្ចុប្បន្នរបស់អ្នកនឹងបញ្ឈប់"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"ការផ្សាយ <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"ប្ដូរឧបករណ៍បញ្ចេញសំឡេង"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"មិនស្គាល់"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, MMM d"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"បើក <xliff:g id="APPNAME">%1$s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml index 5baf68fae084..abfa865390c3 100644 --- a/packages/SystemUI/res/values-kn/strings.xml +++ b/packages/SystemUI/res/values-kn/strings.xml @@ -993,7 +993,6 @@ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> ಅನ್ನು ಪ್ರಸಾರ ಮಾಡಿ"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"ಔಟ್ಪುಟ್ ಅನ್ನು ಬದಲಾಯಿಸಿ"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"ಅಪರಿಚಿತ"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, MMM d"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> ಅನ್ನು ತೆರೆಯಿರಿ"</string> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index 9b8e46a38df0..d1ca240bc60e 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"전송 중지"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"오디오 출력에 사용 가능한 기기입니다."</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"볼륨"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"브로드캐스팅 작동 원리"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"브로드캐스트"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"호환되는 블루투스 기기를 가진 근처의 사용자가 내가 브로드캐스트 중인 미디어를 수신 대기할 수 있습니다."</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"카메라 및 마이크가 사용 중지되었습니다."</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{알림 #개}other{알림 #개}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"메모"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"방송 중"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> 방송을 중지하시겠습니까?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> 앱을 방송하거나 출력을 변경하면 기존 방송이 중단됩니다"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> 방송"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"출력 변경"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"알 수 없음"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"MMM d일 EEE"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> 열기"</string> diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml index bb55c627df73..93092ce0643d 100644 --- a/packages/SystemUI/res/values-ky/strings.xml +++ b/packages/SystemUI/res/values-ky/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Тышкы экранга чыгарууну токтотуу"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Аудио чыгаруу үчүн жеткиликтүү түзмөктөр."</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Үндүн катуулугу"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Кабарлоо кантип иштейт"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"Кабарлоо"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Шайкеш Bluetooth түзмөктөрү болгон жакын жердеги кишилер кабарлап жаткан медиаңызды уга алышат"</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Камера жана микрофон өчүк"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# билдирме}other{# билдирме}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"Эскертме жазуу"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Кеңири таратуу"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосунда кабарлоо токтотулсунбу?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Эгер <xliff:g id="SWITCHAPP">%1$s</xliff:g> колдонмосунда кабарласаңыз же аудионун чыгуусун өзгөртсөңүз, учурдагы кабарлоо токтотулат"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> колдонмосунда кабарлоо"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Аудионун чыгуусун өзгөртүү"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Белгисиз"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, MMM d"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> ачуу"</string> diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml index da353e644b65..906c72308cda 100644 --- a/packages/SystemUI/res/values-lo/strings.xml +++ b/packages/SystemUI/res/values-lo/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"ຢຸດການສົ່ງສັນຍານ"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"ອຸປະກອນທີ່ສາມາດໃຊ້ໄດ້ສຳລັບເອົ້າພຸດສຽງ."</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"ລະດັບສຽງ"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ການອອກອາກາດເຮັດວຽກແນວໃດ"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"ອອກອາກາດ"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"ຄົນທີ່ຢູ່ໃກ້ທ່ານທີ່ມີອຸປະກອນ Bluetooth ທີ່ເຂົ້າກັນໄດ້ຈະສາມາດຟັງມີເດຍທີ່ທ່ານກຳລັງອອກອາກາດຢູ່ໄດ້"</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"ປິດກ້ອງຖ່າຍຮູບ ແລະ ໄມແລ້ວ"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# ການແຈ້ງເຕືອນ}other{# ການແຈ້ງເຕືອນ}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"ການຈົດບັນທຶກ"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"ກຳລັງອອກອາກາດ"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"ຢຸດການອອກອາກາດ <xliff:g id="APP_NAME">%1$s</xliff:g> ບໍ?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"ຫາກທ່ານອອກອາກາດ <xliff:g id="SWITCHAPP">%1$s</xliff:g> ຫຼື ປ່ຽນເອົ້າພຸດ, ການອອກອາກາດປັດຈຸບັນຂອງທ່ານຈະຢຸດ"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"ອອກອາກາດ <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"ປ່ຽນເອົ້າພຸດ"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"ບໍ່ຮູ້ຈັກ"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, MMM d"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"ຊມ:ນທ"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"ຊມ:ນທ"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"ເປີດ <xliff:g id="APPNAME">%1$s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index 96c43712a2f6..789b2b94345b 100644 --- a/packages/SystemUI/res/values-lt/strings.xml +++ b/packages/SystemUI/res/values-lt/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Sustabdyti perdavimą"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Pasiekiami garso išvesties įrenginiai."</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Garsumas"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Kaip veikia transliacija"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"Transliacija"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Netoliese esantys žmonės, turintys suderinamus „Bluetooth“ įrenginius, gali klausyti jūsų transliuojamos medijos"</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Vaizdo kamera ir mikrofonas išjungti"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# pranešimas}one{# pranešimas}few{# pranešimai}many{# pranešimo}other{# pranešimų}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"Užrašų kūrimas"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Transliavimas"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Sustabdyti „<xliff:g id="APP_NAME">%1$s</xliff:g>“ transliaciją?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Jei transliuosite „<xliff:g id="SWITCHAPP">%1$s</xliff:g>“ arba pakeisite išvestį, dabartinė transliacija bus sustabdyta"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Transliuoti „<xliff:g id="SWITCHAPP">%1$s</xliff:g>“"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Keisti išvestį"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Nežinoma"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, MMM d"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Atidaryti „<xliff:g id="APPNAME">%1$s</xliff:g>“"</string> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index 1c2238014b55..dbdbf71b2ce4 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Apturēt apraidi"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Audio izvadei pieejamās ierīces."</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Skaļums"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Kā darbojas apraide"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"Apraide"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Tuvumā esošās personas ar saderīgām Bluetooth ierīcēm var klausīties jūsu apraidīto multivides saturu."</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera un mikrofons ir izslēgti"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# paziņojums}zero{# paziņojumu}one{# paziņojums}other{# paziņojumi}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"Piezīmju pierakstīšana"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Notiek apraidīšana"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Vai apturēt lietotnes <xliff:g id="APP_NAME">%1$s</xliff:g> apraidīšanu?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Ja sāksiet lietotnes <xliff:g id="SWITCHAPP">%1$s</xliff:g> apraidīšanu vai mainīsiet izvadi, pašreizējā apraide tiks apturēta"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Lietotnes <xliff:g id="SWITCHAPP">%1$s</xliff:g> apraide"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Izvades maiņa"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Nezināms"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, d. MMM"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"hh:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Atvērt lietotni <xliff:g id="APPNAME">%1$s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml index 603151fb1aea..2d35cdb7609e 100644 --- a/packages/SystemUI/res/values-mk/strings.xml +++ b/packages/SystemUI/res/values-mk/strings.xml @@ -993,7 +993,6 @@ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Емитување на <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Променете излез"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Непознато"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, MMM d"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Отворете ја <xliff:g id="APPNAME">%1$s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml index 5df73055cef2..409b578ef2e6 100644 --- a/packages/SystemUI/res/values-ml/strings.xml +++ b/packages/SystemUI/res/values-ml/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"കാസ്റ്റ് ചെയ്യുന്നത് നിർത്തുക"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"ഓഡിയോ ഔട്ട്പുട്ടിന് ലഭ്യമായ ഉപകരണങ്ങൾ."</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"വോളിയം"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ബ്രോഡ്കാസ്റ്റ് എങ്ങനെയാണ് പ്രവർത്തിക്കുന്നത്"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"ബ്രോഡ്കാസ്റ്റ്"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"അനുയോജ്യമായ Bluetooth ഉപകരണങ്ങളോടെ സമീപമുള്ള ആളുകൾക്ക് നിങ്ങൾ ബ്രോഡ്കാസ്റ്റ് ചെയ്യുന്ന മീഡിയ കേൾക്കാനാകും"</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"ക്യാമറയും മൈക്കും ഓഫാണ്"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# അറിയിപ്പ്}other{# അറിയിപ്പുകൾ}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"കുറിപ്പ് രേഖപ്പെടുത്തൽ"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"പ്രക്ഷേപണം ചെയ്യുന്നു"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> ബ്രോഡ്കാസ്റ്റ് ചെയ്യുന്നത് അവസാനിപ്പിക്കണോ?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"നിങ്ങൾ <xliff:g id="SWITCHAPP">%1$s</xliff:g> ബ്രോഡ്കാസ്റ്റ് ചെയ്യുകയോ ഔട്ട്പുട്ട് മാറ്റുകയോ ചെയ്താൽ നിങ്ങളുടെ നിലവിലുള്ള ബ്രോഡ്കാസ്റ്റ് അവസാനിക്കും"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> ബ്രോഡ്കാസ്റ്റ് ചെയ്യുക"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"ഔട്ട്പുട്ട് മാറ്റുക"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"അജ്ഞാതം"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, MMM d"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> തുറക്കുക"</string> diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml index aa57e815b676..8c3a70ff057e 100644 --- a/packages/SystemUI/res/values-mn/strings.xml +++ b/packages/SystemUI/res/values-mn/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Дамжуулахыг зогсоох"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Аудио гаралт хийх боломжтой төхөөрөмжүүд."</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Дууны түвшин"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Нэвтрүүлэлт хэрхэн ажилладаг вэ?"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"Нэвтрүүлэлт"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Тохиромжтой Bluetooth төхөөрөмжүүдтэй таны ойролцоох хүмүүс таны нэвтрүүлж буй медиаг сонсох боломжтой"</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Камер болон микрофон унтраалттай байна"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# мэдэгдэл}other{# мэдэгдэл}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"Тэмдэглэл хөтлөх"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Нэвтрүүлэлт"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g>-г нэвтрүүлэхээ зогсоох уу?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Хэрэв та <xliff:g id="SWITCHAPP">%1$s</xliff:g>-г нэвтрүүлсэн эсвэл гаралтыг өөрчилсөн бол таны одоогийн нэвтрүүлэлтийг зогсооно"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g>-г нэвтрүүлэх"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Гаралтыг өөрчлөх"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Тодорхойгүй"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"MMM d EEE"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g>-г нээх"</string> diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml index 7f3c28cbbf7f..658305710d6a 100644 --- a/packages/SystemUI/res/values-mr/strings.xml +++ b/packages/SystemUI/res/values-mr/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"कास्ट करणे थांबवा"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"ऑडिओ आउटपुटसाठी उपलब्ध डिव्हाइस."</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"व्हॉल्यूम"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ब्रॉडकास्टिंग कसे काम करते"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"ब्रॉडकास्ट करा"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"कंपॅटिबल ब्लूटूथ डिव्हाइस असलेले तुमच्या जवळपासचे लोक हे तुम्ही ब्रॉडकास्ट करत असलेला मीडिया ऐकू शकतात"</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"कॅमेरा आणि माइक बंद आहेत"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# सूचना}other{# सूचना}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"नोटटेकिंग"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"ब्रॉडकास्ट करत आहे"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> चे प्रसारण थांबवायचे आहे का?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"तुम्ही <xliff:g id="SWITCHAPP">%1$s</xliff:g> चे प्रसारण केल्यास किंवा आउटपुट बदलल्यास, तुमचे सध्याचे प्रसारण बंद होईल"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> चे प्रसारण करा"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"आउटपूट बदला"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"अज्ञात"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, MMM d"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> उघडा"</string> diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml index bfbc8ea8a203..014011247ee8 100644 --- a/packages/SystemUI/res/values-ms/strings.xml +++ b/packages/SystemUI/res/values-ms/strings.xml @@ -993,7 +993,6 @@ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Siarkan <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Tukar output"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Tidak diketahui"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, d MMM"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Buka <xliff:g id="APPNAME">%1$s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml index 909b9ab031a7..164d662f969b 100644 --- a/packages/SystemUI/res/values-my/strings.xml +++ b/packages/SystemUI/res/values-my/strings.xml @@ -874,8 +874,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"ကာစ် ရပ်ရန်"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"အသံအထွက်အတွက် ရရှိနိုင်သောစက်များ။"</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"အသံအတိုးအကျယ်"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ထုတ်လွှင့်မှုဆောင်ရွက်ပုံ"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"ထုတ်လွှင့်ခြင်း"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"အနီးရှိတွဲသုံးနိုင်သော ဘလူးတုသ်သုံးစက် အသုံးပြုသူများက သင်ထုတ်လွှင့်နေသော မီဒီယာကို နားဆင်နိုင်သည်"</string> @@ -989,15 +988,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"ကင်မရာနှင့် မိုက် ပိတ်ထားသည်"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{အကြောင်းကြားချက် # ခု}other{အကြောင်းကြားချက် # ခု}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>၊ <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"မှတ်စုလိုက်ခြင်း"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"ထုတ်လွှင့်ခြင်း"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> ထုတ်လွှင့်ခြင်းကို ရပ်မလား။"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> ကို ထုတ်လွှင့်သောအခါ (သို့) အထွက်ကို ပြောင်းသောအခါ သင့်လက်ရှိထုတ်လွှင့်ခြင်း ရပ်သွားမည်"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> ထုတ်လွှင့်ခြင်း"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"အထွက်ကို ပြောင်းခြင်း"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"မသိ"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE၊ MMM d"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> ဖွင့်ရန်"</string> diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index 95846f05a008..6288a15b1d4e 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Stopp castingen"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Tilgjengelige enheter for lydutgang."</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volum"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Slik fungerer kringkasting"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"Kringkasting"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Folk i nærheten med kompatible Bluetooth-enheter kan lytte til mediene du kringkaster"</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera og mikrofon er av"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# varsel}other{# varsler}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"Notatskriving"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Kringkaster"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Vil du stoppe kringkastingen av <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Hvis du kringkaster <xliff:g id="SWITCHAPP">%1$s</xliff:g> eller endrer utgangen, stopper den nåværende kringkastingen din"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Kringkast <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Endre utgang"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Ukjent"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE d. MMM"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Åpne <xliff:g id="APPNAME">%1$s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml index b04e368b2905..563d6082cf9d 100644 --- a/packages/SystemUI/res/values-ne/strings.xml +++ b/packages/SystemUI/res/values-ne/strings.xml @@ -500,8 +500,7 @@ <string name="wallet_error_generic" msgid="257704570182963611">"तपाईंका कार्डहरू प्राप्त गर्ने क्रममा समस्या भयो, कृपया पछि फेरि प्रयास गर्नुहोस्"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"लक स्क्रिनसम्बन्धी सेटिङ"</string> <string name="qr_code_scanner_title" msgid="1938155688725760702">"QR कोड स्क्यानर"</string> - <!-- no translation found for qr_code_scanner_updating_secondary_label (8344598017007876352) --> - <skip /> + <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"अपडेट गरिँदै छ"</string> <string name="status_bar_work" msgid="5238641949837091056">"कार्य प्रोफाइल"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"हवाइजहाज मोड"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"तपाईँले आफ्नो अर्को अलार्म <xliff:g id="WHEN">%1$s</xliff:g> सुन्नुहुने छैन"</string> @@ -873,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"कास्ट गर्न छाड्नुहोस्"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"अडियो आउटपुटका लागि उपलब्ध डिभाइसहरू।"</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"भोल्युम"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"प्रसारण गर्ने सुविधाले कसरी काम गर्छ"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"प्रसारण"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"कम्प्याटिबल ब्लुटुथ डिभाइस भएका नजिकैका मान्छेहरू तपाईंले प्रसारण गरिरहनुभएको मिडिया सुन्न सक्छन्"</string> @@ -988,31 +986,22 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"क्यामेरा र माइक अफ छन्"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# वटा सूचना}other{# वटा सूचनाहरू}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"टिपोट गर्ने कार्य"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"प्रसारण गरिँदै छ"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> ब्रोडकास्ट गर्न छाड्ने हो?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"तपाईंले <xliff:g id="SWITCHAPP">%1$s</xliff:g> ब्रोडकास्ट गर्नुभयो वा आउटपुट परिवर्तन गर्नुभयो भने तपाईंको हालको ब्रोडकास्ट रोकिने छ"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> ब्रोडकास्ट गर्नुहोस्"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"आउटपुट परिवर्तन गर्नुहोस्"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"अज्ञात"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, MMM d"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> - <!-- no translation found for keyguard_affordance_enablement_dialog_action_template (8164857863036314664) --> - <skip /> - <!-- no translation found for keyguard_affordance_enablement_dialog_message (2790910660524887941) --> - <skip /> - <!-- no translation found for keyguard_affordance_enablement_dialog_wallet_instruction_1 (8439655049139819278) --> - <skip /> - <!-- no translation found for keyguard_affordance_enablement_dialog_wallet_instruction_2 (4321089250629477835) --> - <skip /> - <!-- no translation found for keyguard_affordance_enablement_dialog_qr_scanner_instruction (5355839079232119791) --> - <skip /> - <!-- no translation found for keyguard_affordance_enablement_dialog_home_instruction_1 (8438311171750568633) --> - <skip /> - <!-- no translation found for keyguard_affordance_enablement_dialog_home_instruction_2 (8308525385889021652) --> - <skip /> + <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> खोल्नुहोस्"</string> + <string name="keyguard_affordance_enablement_dialog_message" msgid="2790910660524887941">"<xliff:g id="APPNAME">%1$s</xliff:g> एपलाई सर्टकटका रूपमा हाल्न, निम्न कुराको सुनिश्चित गर्नुहोस्:"</string> + <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1" msgid="8439655049139819278">"• एप सेटअप गरिएको छ"</string> + <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2" msgid="4321089250629477835">"• Wallet मा कम्तीमा एउटा कार्ड हालिएको छ"</string> + <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction" msgid="5355839079232119791">"• क्यामेरा एप इन्स्टल गरिएको छ"</string> + <string name="keyguard_affordance_enablement_dialog_home_instruction_1" msgid="8438311171750568633">"• एप सेटअप गरिएको छ"</string> + <string name="keyguard_affordance_enablement_dialog_home_instruction_2" msgid="8308525385889021652">"• कम्तीमा एउटा डिभाइस उपलब्ध छ"</string> <string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"रद्द गर्नुहोस्"</string> <string name="rear_display_bottom_sheet_confirm" msgid="4383356544661421206">"अहिले नै फ्लिप गर्नुहोस्"</string> <string name="rear_display_fold_bottom_sheet_title" msgid="6081542277622721548">"अझ राम्रो सेल्फी खिच्न फोन अनफोल्ड गर्नुहोस्"</string> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index 0c05b12a8e6d..ee73a6fcc9cb 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Casten stoppen"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Beschikbare apparaten voor audio-uitvoer."</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volume"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Hoe uitzenden werkt"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"Uitzending"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Mensen bij jou in de buurt met geschikte bluetooth-apparaten kunnen luisteren naar de media die je uitzendt"</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Camera en microfoon staan uit"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# melding}other{# meldingen}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"Aantekeningen maken"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Uitzending"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Uitzending van <xliff:g id="APP_NAME">%1$s</xliff:g> stopzetten?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Als je <xliff:g id="SWITCHAPP">%1$s</xliff:g> uitzendt of de uitvoer wijzigt, wordt je huidige uitzending gestopt"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> uitzenden"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Uitvoer wijzigen"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Onbekend"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE d mmm"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"u:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> openen"</string> diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml index 307b7b9841e3..455f1f9f8374 100644 --- a/packages/SystemUI/res/values-or/strings.xml +++ b/packages/SystemUI/res/values-or/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"କାଷ୍ଟ କରିବା ବନ୍ଦ କରନ୍ତୁ"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"ଅଡିଓ ଆଉଟପୁଟ ପାଇଁ ଉପଲବ୍ଧ ଡିଭାଇସଗୁଡ଼ିକ।"</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"ଭଲ୍ୟୁମ"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ବ୍ରଡକାଷ୍ଟିଂ କିପରି କାମ କରେ"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"ବ୍ରଡକାଷ୍ଟ"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"ଆପଣଙ୍କ ଆଖପାଖର କମ୍ପାଟିବଲ ବ୍ଲୁଟୁଥ ଡିଭାଇସ ଥିବା ଲୋକମାନେ ଆପଣ ବ୍ରଡକାଷ୍ଟ କରୁଥିବା ମିଡିଆ ଶୁଣିପାରିବେ"</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"କ୍ୟାମେରା ଏବଂ ମାଇକ ବନ୍ଦ ଅଛି"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{#ଟି ବିଜ୍ଞପ୍ତି}other{#ଟି ବିଜ୍ଞପ୍ତି}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"ନୋଟଟେକିଂ"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"ବ୍ରଡକାଷ୍ଟ କରୁଛି"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> ବ୍ରଡକାଷ୍ଟ କରିବା ବନ୍ଦ କରିବେ?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"ଯଦି ଆପଣ <xliff:g id="SWITCHAPP">%1$s</xliff:g> ବ୍ରଡକାଷ୍ଟ କରନ୍ତି କିମ୍ବା ଆଉଟପୁଟ ବଦଳାନ୍ତି, ତେବେ ଆପଣଙ୍କ ବର୍ତ୍ତମାନର ବ୍ରଡକାଷ୍ଟ ବନ୍ଦ ହୋଇଯିବ"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> ବ୍ରଡକାଷ୍ଟ କରନ୍ତୁ"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"ଆଉଟପୁଟ ବଦଳାନ୍ତୁ"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"ଅଜଣା"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, MMM d"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> ଖୋଲନ୍ତୁ"</string> diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml index ccf27d731ec0..3e3d3e86a0fd 100644 --- a/packages/SystemUI/res/values-pa/strings.xml +++ b/packages/SystemUI/res/values-pa/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"ਕਾਸਟ ਕਰਨਾ ਬੰਦ ਕਰੋ"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"ਆਡੀਓ ਆਊਟਪੁੱਟ ਲਈ ਉਪਲਬਧ ਡੀਵਾਈਸ।"</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"ਅਵਾਜ਼"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ਪ੍ਰਸਾਰਨ ਕਿਵੇਂ ਕੰਮ ਕਰਦਾ ਹੈ"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"ਪ੍ਰਸਾਰਨ"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"ਅਨੁਰੂਪ ਬਲੂਟੁੱਥ ਡੀਵਾਈਸਾਂ ਨਾਲ ਨਜ਼ਦੀਕੀ ਲੋਕ ਤੁਹਾਡੇ ਵੱਲੋਂ ਪ੍ਰਸਾਰਨ ਕੀਤੇ ਜਾ ਰਹੇ ਮੀਡੀਆ ਨੂੰ ਸੁਣ ਸਕਦੇ ਹਨ"</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"ਕੈਮਰਾ ਅਤੇ ਮਾਈਕ ਬੰਦ ਹਨ"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# ਸੂਚਨਾ}one{# ਸੂਚਨਾ}other{# ਸੂਚਨਾਵਾਂ}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"ਨੋਟ ਬਣਾਉਣਾ"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"ਪ੍ਰਸਾਰਨ"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"ਕੀ <xliff:g id="APP_NAME">%1$s</xliff:g> ਦੇ ਪ੍ਰਸਾਰਨ ਨੂੰ ਰੋਕਣਾ ਹੈ?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"ਜੇ ਤੁਸੀਂ <xliff:g id="SWITCHAPP">%1$s</xliff:g> ਦਾ ਪ੍ਰਸਾਰਨ ਕਰਦੇ ਹੋ ਜਾਂ ਆਊਟਪੁੱਟ ਬਦਲਦੇ ਹੋ, ਤਾਂ ਤੁਹਾਡਾ ਮੌਜੂਦਾ ਪ੍ਰਸਾਰਨ ਰੁਕ ਜਾਵੇਗਾ"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> ਦਾ ਪ੍ਰਸਾਰਨ ਕਰੋ"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"ਆਊਟਪੁੱਟ ਬਦਲੋ"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"ਅਗਿਆਤ"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, MMM d"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> ਖੋਲ੍ਹੋ"</string> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index c82f75cd30d4..1b68eecdcae0 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Zatrzymaj przesyłanie"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Dostępne urządzenia do odtwarzania dźwięku."</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Głośność"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Jak działa transmitowanie"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"Transmisja"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Osoby w pobliżu ze zgodnymi urządzeniami Bluetooth mogą słuchać transmitowanych przez Ciebie multimediów"</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Aparat i mikrofon są wyłączone"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# powiadomienie}few{# powiadomienia}many{# powiadomień}other{# powiadomienia}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"Notatki"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Transmisja"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Zatrzymaj transmisję aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Jeśli transmitujesz aplikację <xliff:g id="SWITCHAPP">%1$s</xliff:g> lub zmieniasz dane wyjściowe, Twoja obecna transmisja zostanie zakończona"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Transmisja aplikacji <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Zmień dane wyjściowe"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Brak informacji"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, d MMM"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Otwórz: <xliff:g id="APPNAME">%1$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 f6a1c5c3ac58..0e7c68a342ff 100644 --- a/packages/SystemUI/res/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res/values-pt-rBR/strings.xml @@ -993,7 +993,6 @@ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Transmitir <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Mudar saída"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Desconhecido"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, d de MMM"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Abrir <xliff:g id="APPNAME">%1$s</xliff:g>"</string> @@ -1009,8 +1008,6 @@ <string name="rear_display_unfold_bottom_sheet_title" msgid="2137403802960396357">"Usar o display frontal para tirar uma selfie melhor?"</string> <string name="rear_display_bottom_sheet_description" msgid="1852662982816810352">"Use a câmera traseira para tirar uma foto mais ampla e com maior resolução."</string> <string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Esta tela vai ser desativada"</b></string> - <!-- no translation found for rear_display_accessibility_folded_animation (1538121649587978179) --> - <skip /> - <!-- no translation found for rear_display_accessibility_unfolded_animation (1946153682258289040) --> - <skip /> + <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Dispositivo dobrável sendo aberto"</string> + <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispositivo dobrável sendo virado"</string> </resources> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index 98b5c7695383..a38550f5ce25 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Parar transmissão"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Dispositivos disponíveis para a saída de áudio."</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volume"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Como funciona a transmissão"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"Transmissão"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"As pessoas próximas de si com dispositivos Bluetooth compatíveis podem ouvir o conteúdo multimédia que está a transmitir"</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"A câmara e o microfone estão desativados"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificação}many{# notificações}other{# notificações}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"Tomar notas"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"A transmitir"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Interromper a transmissão da app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Se transmitir a app <xliff:g id="SWITCHAPP">%1$s</xliff:g> ou alterar a saída, a sua transmissão atual é interrompida"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Transmita a app <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Altere a saída"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Desconhecida"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, d de MMM"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Abrir <xliff:g id="APPNAME">%1$s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index f6a1c5c3ac58..0e7c68a342ff 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -993,7 +993,6 @@ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Transmitir <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Mudar saída"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Desconhecido"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, d de MMM"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Abrir <xliff:g id="APPNAME">%1$s</xliff:g>"</string> @@ -1009,8 +1008,6 @@ <string name="rear_display_unfold_bottom_sheet_title" msgid="2137403802960396357">"Usar o display frontal para tirar uma selfie melhor?"</string> <string name="rear_display_bottom_sheet_description" msgid="1852662982816810352">"Use a câmera traseira para tirar uma foto mais ampla e com maior resolução."</string> <string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Esta tela vai ser desativada"</b></string> - <!-- no translation found for rear_display_accessibility_folded_animation (1538121649587978179) --> - <skip /> - <!-- no translation found for rear_display_accessibility_unfolded_animation (1946153682258289040) --> - <skip /> + <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Dispositivo dobrável sendo aberto"</string> + <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispositivo dobrável sendo virado"</string> </resources> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index e9257fb8c662..ba5eea39e7ae 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -993,7 +993,6 @@ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Transmite <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Schimbă rezultatul"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Necunoscută"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EE, z LLL"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Deschide <xliff:g id="APPNAME">%1$s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index 5128e0e0aec6..5a3f098d81e0 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -993,7 +993,6 @@ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Транслировать \"<xliff:g id="SWITCHAPP">%1$s</xliff:g>\""</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Транслировать на другое устройство"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Неизвестно"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"d MMM EEEE"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Открыть \"<xliff:g id="APPNAME">%1$s</xliff:g>\""</string> diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml index f1767957a5be..d1fa46ef0348 100644 --- a/packages/SystemUI/res/values-si/strings.xml +++ b/packages/SystemUI/res/values-si/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"විකාශය නවතන්න"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"ශ්රව්ය ප්රතිදානය සඳහා තිබෙන උපාංග."</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"හඬ පරිමාව"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"විකාශනය ක්රියා කරන ආකාරය"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"විකාශනය"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"ගැළපෙන බ්ලූටූත් උපාංග සහිත ඔබ අවට සිටින පුද්ගලයින්ට ඔබ විකාශනය කරන මාධ්යයට සවන් දිය හැකිය"</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"කැමරාව සහ මයික් ක්රියාවිරහිතයි"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{දැනුම්දීම් #ක්}one{දැනුම්දීම් #ක්}other{දැනුම්දීම් #ක්}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"සටහන් කර ගැනීම"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"විකාශනය කරමින්"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> විකාශනය කිරීම නවත්වන්නද?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"ඔබ <xliff:g id="SWITCHAPP">%1$s</xliff:g> විකාශනය කළහොත් හෝ ප්රතිදානය වෙනස් කළහොත්, ඔබගේ වත්මන් විකාශනය නවතිනු ඇත."</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> විකාශනය"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"ප්රතිදානය වෙනස් කරන්න"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"නොදනී"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, MMM d"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> විවෘත කරන්න"</string> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index e4c978b1f786..2573733fc50b 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -993,7 +993,6 @@ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Vysielanie aplikácie <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Zmena výstupu"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Neznáme"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, d. MMM"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Otvoriť <xliff:g id="APPNAME">%1$s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index ef5e63ade170..fa63f87650c6 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Ustavi predvajanje"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Razpoložljive naprave za zvočni izhod"</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Glasnost"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Kako deluje oddajanje"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"Oddajanje"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Osebe v bližini z združljivo napravo Bluetooth lahko poslušajo predstavnost, ki jo oddajate."</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Fotoaparat in mikrofon sta izklopljena."</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# obvestilo}one{# obvestilo}two{# obvestili}few{# obvestila}other{# obvestil}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"Ustvarjanje zapiskov"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Oddajanje"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Želite ustaviti oddajanje aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Če oddajate aplikacijo <xliff:g id="SWITCHAPP">%1$s</xliff:g> ali spremenite izhod, bo trenutno oddajanje ustavljeno."</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Oddajaj aplikacijo <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Sprememba izhoda"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Neznano"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, d. MMM"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Odpri aplikacijo <xliff:g id="APPNAME">%1$s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml index 24e26168a9ec..6eb745ccdfaa 100644 --- a/packages/SystemUI/res/values-sq/strings.xml +++ b/packages/SystemUI/res/values-sq/strings.xml @@ -993,7 +993,6 @@ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Transmeto <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Ndrysho daljen"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"I panjohur"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, MMM d"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Hap \"<xliff:g id="APPNAME">%1$s</xliff:g>\""</string> diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index 9464ac51a7f4..75a455997f84 100644 --- a/packages/SystemUI/res/values-sr/strings.xml +++ b/packages/SystemUI/res/values-sr/strings.xml @@ -993,7 +993,6 @@ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Емитујте апликацију <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Промените излаз"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Непознато"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"ДДД, д. МММ"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"с:мин"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"ч:мин"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Отворите: <xliff:g id="APPNAME">%1$s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index f5cf437fb1eb..39b40e97b3b3 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Sluta casta"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Enheter som är tillgängliga för ljudutdata."</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volym"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Så fungerar utsändning"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"Utsändning"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Personer i närheten med kompatibla Bluetooth-enheter kan lyssna på medieinnehåll som du sänder ut"</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kameran och mikrofonen är avstängda"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# avisering}other{# aviseringar}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"Anteckningar"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Sänder"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Vill du sluta sända från <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Om en utsändning från <xliff:g id="SWITCHAPP">%1$s</xliff:g> pågår eller om du byter ljudutgång avbryts den nuvarande utsändningen"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Sänd från <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Byt ljudutgång"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Okänt"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, d MMM"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h.mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk.mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Öppna <xliff:g id="APPNAME">%1$s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index e0043e39b99d..ccf3345e2820 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -995,7 +995,6 @@ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Tangaza kwenye <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Badilisha maudhui"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Haijulikani"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, d MMM"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"saa:dk"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:dk"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Fungua <xliff:g id="APPNAME">%1$s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml index f800cd0ebab9..9f99b76ea984 100644 --- a/packages/SystemUI/res/values-ta/strings.xml +++ b/packages/SystemUI/res/values-ta/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"அலைபரப்புவதை நிறுத்து"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"ஆடியோ அவுட்புட்டுக்குக் கிடைக்கும் சாதனங்கள்."</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"ஒலியளவு"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"பிராட்காஸ்ட் எவ்வாறு செயல்படுகிறது?"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"பிராட்காஸ்ட்"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"நீங்கள் பிராட்காஸ்ட் செய்யும் மீடியாவை அருகிலுள்ளவர்கள் இணக்கமான புளூடூத் சாதனங்கள் மூலம் கேட்கலாம்"</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"கேமராவும் மைக்கும் ஆஃப் செய்யப்பட்டுள்ளன"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# அறிவிப்பு}other{# அறிவிப்புகள்}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"குறிப்பெடுத்தல்"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"ஒலிபரப்புதல்"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸ் ஒலிபரப்பப்படுவதை நிறுத்தவா?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"நீங்கள் <xliff:g id="SWITCHAPP">%1$s</xliff:g> ஆப்ஸை ஒலிபரப்பினாலோ அவுட்புட்டை மாற்றினாலோ உங்களின் தற்போதைய ஒலிபரப்பு நிறுத்தப்படும்"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> ஆப்ஸை ஒலிபரப்பு"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"அவுட்புட்டை மாற்று"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"தெரியவில்லை"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, MMM d"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> ஆப்ஸைத் திற"</string> diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml index f707088ccef5..4e506d4eadab 100644 --- a/packages/SystemUI/res/values-te/strings.xml +++ b/packages/SystemUI/res/values-te/strings.xml @@ -66,7 +66,7 @@ <string name="usb_contaminant_title" msgid="894052515034594113">"USB పోర్ట్ నిలిపివేయబడింది"</string> <string name="usb_contaminant_message" msgid="7730476585174719805">"మీ పరికరంలోకి నీరు లేదా చెత్తాచెదారం చేరిపోకుండా కాపాడటానికి, USB పోర్ట్ నిలిపివేయబడుతుంది, అలాగే యాక్సెసరీలు వేటిని గుర్తించదు.\n\nUSB పోర్ట్ను ఉపయోగించడం సురక్షితమేనని నిర్ధారించుకున్న తర్వాత, మళ్లీ మీకో నోటిఫికేషన్ రూపంలో తెలియజేయబడుతుంది."</string> <string name="usb_port_enabled" msgid="531823867664717018">"ఛార్జర్లు, యాక్సెసరీలను గుర్తించే విధంగా USB పోర్ట్ ప్రారంభించబడింది"</string> - <string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"USBని ప్రారంభించు"</string> + <string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"USBని ప్రారంభించండి"</string> <string name="learn_more" msgid="4690632085667273811">"మరింత తెలుసుకోండి"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"స్క్రీన్షాట్"</string> <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock డిజేబుల్ చేయబడింది"</string> @@ -105,7 +105,7 @@ <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"మీ పరికరం నుండి వచ్చే మ్యూజిక్, కాల్స్, రింగ్టోన్ల వంటి ధ్వనులు"</string> <string name="screenrecord_mic_label" msgid="2111264835791332350">"మైక్రోఫోన్"</string> <string name="screenrecord_device_audio_and_mic_label" msgid="1831323771978646841">"పరికరం ఆడియో, మైక్రోఫోన్"</string> - <string name="screenrecord_start" msgid="330991441575775004">"ప్రారంభించు"</string> + <string name="screenrecord_start" msgid="330991441575775004">"ప్రారంభించండి"</string> <string name="screenrecord_ongoing_screen_only" msgid="4459670242451527727">"స్క్రీన్ రికార్డింగ్ చేయబడుతోంది"</string> <string name="screenrecord_ongoing_screen_and_audio" msgid="5351133763125180920">"స్క్రీన్, ఆడియో రికార్డింగ్ చేయబడుతున్నాయి"</string> <string name="screenrecord_taps_label" msgid="1595690528298857649">"స్క్రీన్పై తాకే స్థానాలను చూపు"</string> @@ -289,7 +289,7 @@ <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC నిలిపివేయబడింది"</string> <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC ప్రారంభించబడింది"</string> <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"స్క్రీన్ రికార్డ్"</string> - <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"ప్రారంభించు"</string> + <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"ప్రారంభించండి"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"ఆపు"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"వన్-హ్యాండెడ్ మోడ్"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"పరికరం మైక్రోఫోన్ను అన్బ్లాక్ చేయమంటారా?"</string> @@ -356,7 +356,7 @@ <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ఈ సెషన్లోని అన్ని యాప్లు మరియు డేటా తొలగించబడతాయి."</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"గెస్ట్కు తిరిగి స్వాగతం!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"మీరు మీ సెషన్ని కొనసాగించాలనుకుంటున్నారా?"</string> - <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"మొదటి నుండి ప్రారంభించు"</string> + <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"మొదటి నుండి ప్రారంభించండి"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"అవును, కొనసాగించు"</string> <string name="guest_notification_app_name" msgid="2110425506754205509">"గెస్ట్ మోడ్"</string> <string name="guest_notification_session_active" msgid="5567273684713471450">"మీరు గెస్ట్ మోడ్లో ఉన్నారు"</string> @@ -391,7 +391,7 @@ <string name="notification_section_header_conversations" msgid="821834744538345661">"సంభాషణలు"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"అన్ని నిశ్శబ్ద నోటిఫికేషన్లను క్లియర్ చేస్తుంది"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"అంతరాయం కలిగించవద్దు ద్వారా నోటిఫికేషన్లు పాజ్ చేయబడ్డాయి"</string> - <string name="media_projection_action_text" msgid="3634906766918186440">"ఇప్పుడే ప్రారంభించు"</string> + <string name="media_projection_action_text" msgid="3634906766918186440">"ఇప్పుడే ప్రారంభించండి"</string> <string name="empty_shade_text" msgid="8935967157319717412">"నోటిఫికేషన్లు లేవు"</string> <string name="no_unseen_notif_text" msgid="395512586119868682">"కొత్త నోటిఫికేషన్లు ఏవీ లేవు"</string> <string name="unlock_to_see_notif_text" msgid="7439033907167561227">"పాత నోటిఫికేషన్ల కోసం అన్లాక్ చేయండి"</string> @@ -442,7 +442,7 @@ <string name="volume_odi_captions_tip" msgid="8825655463280990941">"మీడియాకు ఆటోమేటిక్ క్యాప్షన్లు"</string> <string name="accessibility_volume_close_odi_captions_tip" msgid="8924753283621160480">"క్యాప్షన్ల చిట్కాను మూసివేయండి"</string> <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"క్యాప్షన్లు ఓవర్లే"</string> - <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"ప్రారంభించు"</string> + <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"ప్రారంభించండి"</string> <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"నిలిపివేయండి"</string> <string name="sound_settings" msgid="8874581353127418308">"సౌండ్ & వైబ్రేషన్"</string> <string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"సెట్టింగ్లు"</string> @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"ప్రసారాన్ని ఆపివేయండి"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"ఆడియో అవుట్పుట్ కోసం అందుబాటులో ఉన్న పరికరాలు."</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"వాల్యూమ్"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"ప్రసారం కావడం అనేది ఎలా పని చేస్తుంది"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"ప్రసారం"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"మీకు సమీపంలో ఉన్న వ్యక్తులు అనుకూలత ఉన్న బ్లూటూత్ పరికరాలతో మీరు ప్రసారం చేస్తున్న మీడియాను వినగలరు"</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"కెమెరా, మైక్ ఆఫ్లో ఉన్నాయి"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# నోటిఫికేషన్}other{# నోటిఫికేషన్లు}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"నోట్టేకింగ్"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"ప్రసారం చేస్తోంది"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> ప్రసారం చేయడాన్ని ఆపివేయాలా?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"మీరు <xliff:g id="SWITCHAPP">%1$s</xliff:g> ప్రసారం చేస్తే లేదా అవుట్పుట్ను మార్చినట్లయితే, మీ ప్రస్తుత ప్రసారం ఆగిపోతుంది"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> ప్రసారం చేయండి"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"అవుట్పుట్ను మార్చండి"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"తెలియదు"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, MMM d"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g>ను తెరవండి"</string> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index 40b997d3e55b..544dde40d5f3 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"หยุดแคสต์"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"อุปกรณ์ที่พร้อมใช้งานสำหรับเอาต์พุตเสียง"</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"ระดับเสียง"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"วิธีการทำงานของการออกอากาศ"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"ประกาศ"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"ผู้ที่อยู่ใกล้คุณและมีอุปกรณ์บลูทูธที่รองรับสามารถรับฟังสื่อที่คุณกำลังออกอากาศได้"</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"กล้องและไมค์ปิดอยู่"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{การแจ้งเตือน # รายการ}other{การแจ้งเตือน # รายการ}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"การจดบันทึก"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"กำลังออกอากาศ"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"หยุดการออกอากาศ <xliff:g id="APP_NAME">%1$s</xliff:g> ไหม"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"หากคุณออกอากาศ <xliff:g id="SWITCHAPP">%1$s</xliff:g> หรือเปลี่ยนแปลงเอาต์พุต การออกอากาศในปัจจุบันจะหยุดลง"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"ออกอากาศ <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"เปลี่ยนเอาต์พุต"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"ไม่ทราบ"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE d MMM"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"HH:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"เปิด <xliff:g id="APPNAME">%1$s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index a0b4e29a7e5e..c27b13308bf8 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Ihinto ang pag-cast"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Mga available na device para sa audio output."</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volume"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Paano gumagana ang pag-broadcast"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"Broadcast"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Makakapakinig ang mga taong malapit sa iyo na may mga compatible na Bluetooth device sa media na bino-broadcast mo"</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Naka-off ang camera at mikropono"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notification}one{# notification}other{# na notification}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"Pagtatala"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Nagbo-broadcast"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Ihinto ang pag-broadcast ng <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Kung magbo-broadcast ka ng <xliff:g id="SWITCHAPP">%1$s</xliff:g> o babaguhin mo ang output, hihinto ang iyong kasalukuyang broadcast"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"I-broadcast ang <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Baguhin ang output"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Hindi alam"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, MMM d"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Buksan ang <xliff:g id="APPNAME">%1$s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index 4fb45b182daf..90cd4a7e6f73 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Yayını durdur"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Ses çıkışı için kullanılabilir cihazlar."</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Ses düzeyi"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"%%<xliff:g id="PERCENTAGE">%1$d</xliff:g>"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Yayınlamanın işleyiş şekli"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"Anons"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Yakınınızda ve uyumlu Bluetooth cihazları olan kişiler yayınladığınız medya içeriğini dinleyebilir"</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Kamera ve mikrofon kapalı"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# bildirim}other{# bildirim}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"Not alma"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Yayınlama"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"<xliff:g id="APP_NAME">%1$s</xliff:g> uygulamasında anons durdurulsun mu?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> uygulamasında anons yapar veya çıkışı değiştirirseniz mevcut anonsunuz duraklatılır"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> uygulamasında anons yapın"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Çıkışı değiştirme"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Bilinmiyor"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"d MMM, EEE"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:dd"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> uygulamasını aç"</string> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index 5992b015a951..76e99ef4bc3b 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Припинити трансляцію"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Доступні пристрої для відтворення звуку."</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Гучність"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Як працює трансляція"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"Трансляція"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Люди поблизу, які мають сумісні пристрої з Bluetooth, можуть слухати медіаконтент, який ви транслюєте."</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Камеру й мікрофон вимкнено"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# сповіщення}one{# сповіщення}few{# сповіщення}many{# сповіщень}other{# сповіщення}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"Створення нотаток"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Трансляція"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Зупинити трансляцію з додатка <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Якщо ви зміните додаток (<xliff:g id="SWITCHAPP">%1$s</xliff:g>) або аудіовихід, поточну трансляцію буде припинено"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Змінити додаток для трансляції на <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Змінити аудіовихід"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Невідомо"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, d MMM"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Відкрити <xliff:g id="APPNAME">%1$s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml index 1a0ce6f21126..7f805984dc1b 100644 --- a/packages/SystemUI/res/values-ur/strings.xml +++ b/packages/SystemUI/res/values-ur/strings.xml @@ -993,7 +993,6 @@ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> پر براڈکاسٹ کریں"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"آؤٹ پٹ تبدیل کریں"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"نامعلوم"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, MMM d"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g> کھولیں"</string> diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml index 257edd4b46cb..99e8abc13b6b 100644 --- a/packages/SystemUI/res/values-uz/strings.xml +++ b/packages/SystemUI/res/values-uz/strings.xml @@ -993,7 +993,6 @@ <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> ilovasiga translatsiya"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Ovoz chiqishini oʻzgartirish"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Noaniq"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, MMM d"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"s:dd"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Ochish: <xliff:g id="APPNAME">%1$s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index 53efd2d07987..88bf8de25e09 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Dừng truyền"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Các thiết bị có sẵn để xuất âm thanh."</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Âm lượng"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Cách tính năng truyền hoạt động"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"Truyền"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Những người ở gần có thiết bị Bluetooth tương thích có thể nghe nội dung nghe nhìn bạn đang truyền"</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Máy ảnh và micrô đang tắt"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# thông báo}other{# thông báo}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"Ghi chú"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Phát sóng"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Dừng phát <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Nếu bạn phát <xliff:g id="SWITCHAPP">%1$s</xliff:g> hoặc thay đổi đầu ra, phiên truyền phát hiện tại sẽ dừng"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Phát <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Thay đổi đầu ra"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Không xác định"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, MMM d"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Mở <xliff:g id="APPNAME">%1$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 c339e8dc9a5a..81b61c6644e7 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"停止投放"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"音频输出的可用设备。"</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"音量"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"广播的运作方式"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"广播"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"附近使用兼容蓝牙设备的用户可以收听您广播的媒体内容"</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"摄像头和麦克风已关闭"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# 条通知}other{# 条通知}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>,<xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"记录"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"正在广播"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"要停止广播“<xliff:g id="APP_NAME">%1$s</xliff:g>”的内容吗?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"如果广播“<xliff:g id="SWITCHAPP">%1$s</xliff:g>”的内容或更改输出来源,当前的广播就会停止"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"广播“<xliff:g id="SWITCHAPP">%1$s</xliff:g>”的内容"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"更改输出来源"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"未知"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, MMM d"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"打开<xliff:g id="APPNAME">%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 6ed283538a5c..3d7ba058a0eb 100644 --- a/packages/SystemUI/res/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"停止投放"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"可用作音訊輸出的裝置"</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"音量"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"廣播運作方式"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"廣播"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"附近有兼容藍牙裝置的人可收聽您正在廣播的媒體內容"</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"相機和麥克風已關閉"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# 則通知}other{# 則通知}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>,<xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"做筆記"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"廣播"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"要停止廣播「<xliff:g id="APP_NAME">%1$s</xliff:g>」的內容嗎?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"如要廣播「<xliff:g id="SWITCHAPP">%1$s</xliff:g>」的內容或變更輸出來源,系統就會停止廣播目前的內容"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"廣播「<xliff:g id="SWITCHAPP">%1$s</xliff:g>」的內容"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"變更輸出來源"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"不明"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"MMM d EEE"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"開啟「<xliff:g id="APPNAME">%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 b1698d52e16d..47c0561c39a0 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"停止投放"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"可用於輸出音訊的裝置。"</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"音量"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"廣播功能的運作方式"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"廣播"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"如果附近的人有相容的藍牙裝置,就可以聽到你正在廣播的媒體內容"</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"已關閉相機和麥克風"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# 則通知}other{# 則通知}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>,<xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"做筆記"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"廣播"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"要停止播送「<xliff:g id="APP_NAME">%1$s</xliff:g>」的內容嗎?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"如果播送「<xliff:g id="SWITCHAPP">%1$s</xliff:g>」的內容或變更輸出來源,系統就會停止播送目前的內容"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"播送「<xliff:g id="SWITCHAPP">%1$s</xliff:g>」的內容"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"變更輸出來源"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"不明"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"MMM d EEE"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"開啟「<xliff:g id="APPNAME">%1$s</xliff:g>」"</string> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index 38a61365932f..b77851954f50 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -872,8 +872,7 @@ <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Misa ukusakaza"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Amadivayisi atholakalayo okukhipha umsindo."</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Ivolumu"</string> - <!-- no translation found for media_output_dialog_volume_percentage (1613984910585111798) --> - <skip /> + <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string> <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Indlela ukusakaza okusebenza ngayo"</string> <string name="media_output_broadcast" msgid="3555580945878071543">"Sakaza"</string> <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Abantu abaseduze nawe abanamadivayisi e-Bluetooth ahambisanayo bangalalela imidiya oyisakazayo"</string> @@ -987,15 +986,13 @@ <string name="dream_overlay_status_bar_camera_mic_off" msgid="3199425257833773569">"Ikhamera nemakrofoni kuvaliwe"</string> <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{Isaziso esingu-#}one{Izaziso ezingu-#}other{Izaziso ezingu-#}}"</string> <string name="dream_overlay_weather_complication_desc" msgid="824503662089783824">"<xliff:g id="WEATHER_CONDITION">%1$s</xliff:g>, <xliff:g id="TEMPERATURE">%2$s</xliff:g>"</string> - <!-- no translation found for note_task_button_label (8718616095800343136) --> - <skip /> + <string name="note_task_button_label" msgid="8718616095800343136">"Ukuthatha amanothi"</string> <string name="broadcasting_description_is_broadcasting" msgid="765627502786404290">"Ukusakaza"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Misa ukusakaza i-<xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Uma usakaza i-<xliff:g id="SWITCHAPP">%1$s</xliff:g> noma ushintsha okuphumayo, ukusakaza kwakho kwamanje kuzoma"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Sakaza i-<xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string> <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Shintsha okuphumayo"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Akwaziwa"</string> - <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE, MMM d"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string> <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Vula i-<xliff:g id="APPNAME">%1$s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 4cda8c7b5328..6d88e512eddb 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -773,15 +773,11 @@ <integer name="complicationFadeOutDelayMs">200</integer> <!-- Duration in milliseconds of the dream in un-blur animation. --> - <integer name="config_dreamOverlayInBlurDurationMs">249</integer> - <!-- Delay in milliseconds of the dream in un-blur animation. --> - <integer name="config_dreamOverlayInBlurDelayMs">133</integer> + <integer name="config_dreamOverlayInBlurDurationMs">250</integer> <!-- Duration in milliseconds of the dream in complications fade-in animation. --> - <integer name="config_dreamOverlayInComplicationsDurationMs">282</integer> - <!-- Delay in milliseconds of the dream in top complications fade-in animation. --> - <integer name="config_dreamOverlayInTopComplicationsDelayMs">216</integer> - <!-- Delay in milliseconds of the dream in bottom complications fade-in animation. --> - <integer name="config_dreamOverlayInBottomComplicationsDelayMs">299</integer> + <integer name="config_dreamOverlayInComplicationsDurationMs">250</integer> + <!-- Duration in milliseconds of the y-translation animation when entering a dream --> + <integer name="config_dreamOverlayInTranslationYDurationMs">917</integer> <!-- Icons that don't show in a collapsed non-keyguard statusbar --> <string-array name="config_collapsed_statusbar_icon_blocklist" translatable="false"> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index c10e75289cf2..e8a8534581d2 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -758,6 +758,8 @@ <dimen name="keyguard_affordance_fixed_height">48dp</dimen> <dimen name="keyguard_affordance_fixed_width">48dp</dimen> <dimen name="keyguard_affordance_fixed_radius">24dp</dimen> + <!-- Amount the button should shake when it's not long-pressed for long enough. --> + <dimen name="keyguard_affordance_shake_amplitude">8dp</dimen> <dimen name="keyguard_affordance_horizontal_offset">32dp</dimen> <dimen name="keyguard_affordance_vertical_offset">32dp</dimen> @@ -1505,6 +1507,8 @@ <dimen name="dream_overlay_status_bar_extra_margin">8dp</dimen> <!-- Dream overlay complications related dimensions --> + <!-- The blur radius applied to the dream overlay when entering and exiting dreams --> + <dimen name="dream_overlay_anim_blur_radius">50dp</dimen> <dimen name="dream_overlay_complication_clock_time_text_size">86dp</dimen> <dimen name="dream_overlay_complication_clock_time_translation_y">28dp</dimen> <dimen name="dream_overlay_complication_home_controls_padding">28dp</dimen> @@ -1558,6 +1562,7 @@ <dimen name="dream_overlay_complication_margin">0dp</dimen> <dimen name="dream_overlay_y_offset">80dp</dimen> + <dimen name="dream_overlay_entry_y_offset">40dp</dimen> <dimen name="dream_overlay_exit_y_offset">40dp</dimen> <dimen name="status_view_margin_horizontal">0dp</dimen> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 643f831c7f94..ca2cf1a56b41 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -2740,6 +2740,12 @@ --> <string name="keyguard_affordance_enablement_dialog_home_instruction_2">• At least one device is available</string> + <!-- + Error message shown when a button should be pressed and held to activate it, usually shown when + the user attempted to tap the button or held it for too short a time. [CHAR LIMIT=32]. + --> + <string name="keyguard_affordance_press_too_short">Press and hold to activate</string> + <!-- Text for education page of cancel button to hide the page. [CHAR_LIMIT=NONE] --> <string name="rear_display_bottom_sheet_cancel">Cancel</string> <!-- Text for the user to confirm they flipped the device around. [CHAR_LIMIT=NONE] --> @@ -2756,4 +2762,7 @@ <string name="rear_display_accessibility_folded_animation">Foldable device being unfolded</string> <!-- Text for education page content description for unfolded animation. [CHAR_LIMIT=NONE] --> <string name="rear_display_accessibility_unfolded_animation">Foldable device being flipped around</string> + + <!-- Title for notification of low stylus battery. [CHAR_LIMIT=NONE] --> + <string name="stylus_battery_low">Stylus battery low</string> </resources> diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java index 40423cd9ac2c..62babadc45d8 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java @@ -9,6 +9,7 @@ import android.graphics.Rect; import android.util.AttributeSet; import android.util.Log; import android.view.View; +import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.RelativeLayout; @@ -43,6 +44,21 @@ public class KeyguardClockSwitch extends RelativeLayout { public static final int LARGE = 0; public static final int SMALL = 1; + /** Returns a region for the large clock to position itself, based on the given parent. */ + public static Rect getLargeClockRegion(ViewGroup parent) { + int largeClockTopMargin = parent.getResources() + .getDimensionPixelSize(R.dimen.keyguard_large_clock_top_margin); + int targetHeight = parent.getResources() + .getDimensionPixelSize(R.dimen.large_clock_text_size) * 2; + int top = parent.getHeight() / 2 - targetHeight / 2 + + largeClockTopMargin / 2; + return new Rect( + parent.getLeft(), + top, + parent.getRight(), + top + targetHeight); + } + /** * Frame for small/large clocks */ @@ -129,17 +145,8 @@ public class KeyguardClockSwitch extends RelativeLayout { } if (mLargeClockFrame.isLaidOut()) { - int largeClockTopMargin = getResources() - .getDimensionPixelSize(R.dimen.keyguard_large_clock_top_margin); - int targetHeight = getResources() - .getDimensionPixelSize(R.dimen.large_clock_text_size) * 2; - int top = mLargeClockFrame.getHeight() / 2 - targetHeight / 2 - + largeClockTopMargin / 2; - mClock.getLargeClock().getEvents().onTargetRegionChanged(new Rect( - mLargeClockFrame.getLeft(), - top, - mLargeClockFrame.getRight(), - top + targetHeight)); + mClock.getLargeClock().getEvents().onTargetRegionChanged( + getLargeClockRegion(mLargeClockFrame)); } } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java index c985fd7bef82..c1fae9e44bd3 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java @@ -24,6 +24,7 @@ import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_NON_STRONG import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_PREPARE_FOR_UPDATE; import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_RESTART; import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TIMEOUT; +import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TRUSTAGENT_EXPIRED; import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_USER_REQUEST; import android.animation.Animator; @@ -107,6 +108,8 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView { return R.string.kg_prompt_reason_timeout_password; case PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT: return R.string.kg_prompt_reason_timeout_password; + case PROMPT_REASON_TRUSTAGENT_EXPIRED: + return R.string.kg_prompt_reason_timeout_password; case PROMPT_REASON_NONE: return 0; default: diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java index 571d2740773d..0c1748982e51 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java @@ -313,6 +313,9 @@ public class KeyguardPatternViewController case PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT: mMessageAreaController.setMessage(R.string.kg_prompt_reason_timeout_pattern); break; + case PROMPT_REASON_TRUSTAGENT_EXPIRED: + mMessageAreaController.setMessage(R.string.kg_prompt_reason_timeout_pattern); + break; case PROMPT_REASON_NONE: break; default: diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java index c46e33d9fd53..0a91150e6c39 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java @@ -22,6 +22,7 @@ import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_NON_STRONG import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_PREPARE_FOR_UPDATE; import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_RESTART; import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TIMEOUT; +import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TRUSTAGENT_EXPIRED; import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_USER_REQUEST; import android.animation.Animator; @@ -123,6 +124,8 @@ public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView return R.string.kg_prompt_reason_timeout_pin; case PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT: return R.string.kg_prompt_reason_timeout_pin; + case PROMPT_REASON_TRUSTAGENT_EXPIRED: + return R.string.kg_prompt_reason_timeout_pin; case PROMPT_REASON_NONE: return 0; default: diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java index ac00e9453c97..67d77e53738a 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java @@ -61,6 +61,12 @@ public interface KeyguardSecurityView { int PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT = 7; /** + * Some auth is required because the trustagent expired either from timeout or manually by the + * user + */ + int PROMPT_REASON_TRUSTAGENT_EXPIRED = 8; + + /** * Reset the view and prepare to take input. This should do things like clearing the * password or pattern and clear error messages. */ diff --git a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java index 7864f1901e57..ccb9557d757b 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java @@ -93,6 +93,8 @@ import android.view.accessibility.AccessibilityManager; import android.view.accessibility.CaptioningManager; import android.view.inputmethod.InputMethodManager; +import androidx.core.app.NotificationManagerCompat; + import com.android.internal.app.IBatteryStats; import com.android.internal.appwidget.IAppWidgetService; import com.android.internal.jank.InteractionJankMonitor; @@ -389,6 +391,12 @@ public class FrameworkServicesModule { return context.getSystemService(NotificationManager.class); } + @Provides + @Singleton + static NotificationManagerCompat provideNotificationManagerCompat(Context context) { + return NotificationManagerCompat.from(context); + } + /** */ @Provides @Singleton diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt index 0fbe0acb5642..a4252bbe1d68 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt @@ -42,6 +42,7 @@ import com.android.systemui.settings.dagger.MultiUserUtilsModule import com.android.systemui.shortcut.ShortcutKeyDispatcher import com.android.systemui.statusbar.notification.InstantAppNotifier import com.android.systemui.statusbar.phone.KeyguardLiftController +import com.android.systemui.stylus.StylusUsiPowerStartable import com.android.systemui.temporarydisplay.chipbar.ChipbarCoordinator import com.android.systemui.theme.ThemeOverlayController import com.android.systemui.toast.ToastUI @@ -251,4 +252,10 @@ abstract class SystemUICoreStartableModule { @IntoMap @ClassKey(RearDisplayDialogController::class) abstract fun bindRearDisplayDialogController(sysui: RearDisplayDialogController): CoreStartable + + /** Inject into StylusUsiPowerStartable) */ + @Binds + @IntoMap + @ClassKey(StylusUsiPowerStartable::class) + abstract fun bindStylusUsiPowerStartable(sysui: StylusUsiPowerStartable): CoreStartable } diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt index 0087c8439370..9b8ef71882e9 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt +++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt @@ -21,11 +21,12 @@ import android.animation.AnimatorSet import android.animation.ValueAnimator import android.view.View import android.view.animation.Interpolator -import androidx.annotation.FloatRange import androidx.core.animation.doOnEnd import com.android.systemui.animation.Interpolators import com.android.systemui.dreams.complication.ComplicationHostViewController import com.android.systemui.dreams.complication.ComplicationLayoutParams +import com.android.systemui.dreams.complication.ComplicationLayoutParams.POSITION_BOTTOM +import com.android.systemui.dreams.complication.ComplicationLayoutParams.POSITION_TOP import com.android.systemui.dreams.complication.ComplicationLayoutParams.Position import com.android.systemui.dreams.dagger.DreamOverlayModule import com.android.systemui.statusbar.BlurUtils @@ -41,16 +42,15 @@ constructor( private val mComplicationHostViewController: ComplicationHostViewController, private val mStatusBarViewController: DreamOverlayStatusBarViewController, private val mOverlayStateController: DreamOverlayStateController, + @Named(DreamOverlayModule.DREAM_BLUR_RADIUS) private val mDreamBlurRadius: Int, @Named(DreamOverlayModule.DREAM_IN_BLUR_ANIMATION_DURATION) private val mDreamInBlurAnimDurationMs: Long, - @Named(DreamOverlayModule.DREAM_IN_BLUR_ANIMATION_DELAY) - private val mDreamInBlurAnimDelayMs: Long, @Named(DreamOverlayModule.DREAM_IN_COMPLICATIONS_ANIMATION_DURATION) private val mDreamInComplicationsAnimDurationMs: Long, - @Named(DreamOverlayModule.DREAM_IN_TOP_COMPLICATIONS_ANIMATION_DELAY) - private val mDreamInTopComplicationsAnimDelayMs: Long, - @Named(DreamOverlayModule.DREAM_IN_BOTTOM_COMPLICATIONS_ANIMATION_DELAY) - private val mDreamInBottomComplicationsAnimDelayMs: Long, + @Named(DreamOverlayModule.DREAM_IN_TRANSLATION_Y_DISTANCE) + private val mDreamInTranslationYDistance: Int, + @Named(DreamOverlayModule.DREAM_IN_TRANSLATION_Y_DURATION) + private val mDreamInTranslationYDurationMs: Long, @Named(DreamOverlayModule.DREAM_OUT_TRANSLATION_Y_DISTANCE) private val mDreamOutTranslationYDistance: Int, @Named(DreamOverlayModule.DREAM_OUT_TRANSLATION_Y_DURATION) @@ -74,7 +74,7 @@ constructor( */ private var mCurrentAlphaAtPosition = mutableMapOf<Int, Float>() - @FloatRange(from = 0.0, to = 1.0) private var mBlurProgress: Float = 0f + private var mCurrentBlurRadius: Float = 0f /** Starts the dream content and dream overlay entry animations. */ @JvmOverloads @@ -86,25 +86,23 @@ constructor( playTogether( blurAnimator( view = view, - from = 1f, - to = 0f, + fromBlurRadius = mDreamBlurRadius.toFloat(), + toBlurRadius = 0f, durationMs = mDreamInBlurAnimDurationMs, - delayMs = mDreamInBlurAnimDelayMs + interpolator = Interpolators.EMPHASIZED_DECELERATE ), alphaAnimator( from = 0f, to = 1f, durationMs = mDreamInComplicationsAnimDurationMs, - delayMs = mDreamInTopComplicationsAnimDelayMs, - position = ComplicationLayoutParams.POSITION_TOP + interpolator = Interpolators.LINEAR + ), + translationYAnimator( + from = mDreamInTranslationYDistance.toFloat(), + to = 0f, + durationMs = mDreamInTranslationYDurationMs, + interpolator = Interpolators.EMPHASIZED_DECELERATE ), - alphaAnimator( - from = 0f, - to = 1f, - durationMs = mDreamInComplicationsAnimDurationMs, - delayMs = mDreamInBottomComplicationsAnimDelayMs, - position = ComplicationLayoutParams.POSITION_BOTTOM - ) ) doOnEnd { mAnimator = null @@ -130,47 +128,48 @@ constructor( view = view, // Start the blurring wherever the entry animation ended, in // case it was cancelled early. - from = mBlurProgress, - to = 1f, - durationMs = mDreamOutBlurDurationMs + fromBlurRadius = mCurrentBlurRadius, + toBlurRadius = mDreamBlurRadius.toFloat(), + durationMs = mDreamOutBlurDurationMs, + interpolator = Interpolators.EMPHASIZED_ACCELERATE ), translationYAnimator( from = 0f, to = mDreamOutTranslationYDistance.toFloat(), durationMs = mDreamOutTranslationYDurationMs, delayMs = mDreamOutTranslationYDelayBottomMs, - position = ComplicationLayoutParams.POSITION_BOTTOM, - animInterpolator = Interpolators.EMPHASIZED_ACCELERATE + positions = POSITION_BOTTOM, + interpolator = Interpolators.EMPHASIZED_ACCELERATE ), translationYAnimator( from = 0f, to = mDreamOutTranslationYDistance.toFloat(), durationMs = mDreamOutTranslationYDurationMs, delayMs = mDreamOutTranslationYDelayTopMs, - position = ComplicationLayoutParams.POSITION_TOP, - animInterpolator = Interpolators.EMPHASIZED_ACCELERATE + positions = POSITION_TOP, + interpolator = Interpolators.EMPHASIZED_ACCELERATE ), alphaAnimator( from = mCurrentAlphaAtPosition.getOrDefault( - key = ComplicationLayoutParams.POSITION_BOTTOM, + key = POSITION_BOTTOM, defaultValue = 1f ), to = 0f, durationMs = mDreamOutAlphaDurationMs, delayMs = mDreamOutAlphaDelayBottomMs, - position = ComplicationLayoutParams.POSITION_BOTTOM + positions = POSITION_BOTTOM ), alphaAnimator( from = mCurrentAlphaAtPosition.getOrDefault( - key = ComplicationLayoutParams.POSITION_TOP, + key = POSITION_TOP, defaultValue = 1f ), to = 0f, durationMs = mDreamOutAlphaDurationMs, delayMs = mDreamOutAlphaDelayTopMs, - position = ComplicationLayoutParams.POSITION_TOP + positions = POSITION_TOP ) ) doOnEnd { @@ -194,20 +193,21 @@ constructor( private fun blurAnimator( view: View, - from: Float, - to: Float, + fromBlurRadius: Float, + toBlurRadius: Float, durationMs: Long, - delayMs: Long = 0 + delayMs: Long = 0, + interpolator: Interpolator = Interpolators.LINEAR ): Animator { - return ValueAnimator.ofFloat(from, to).apply { + return ValueAnimator.ofFloat(fromBlurRadius, toBlurRadius).apply { duration = durationMs startDelay = delayMs - interpolator = Interpolators.LINEAR + this.interpolator = interpolator addUpdateListener { animator: ValueAnimator -> - mBlurProgress = animator.animatedValue as Float + mCurrentBlurRadius = animator.animatedValue as Float mBlurUtils.applyBlur( viewRootImpl = view.viewRootImpl, - radius = mBlurUtils.blurRadiusOfRatio(mBlurProgress).toInt(), + radius = mCurrentBlurRadius.toInt(), opaque = false ) } @@ -218,18 +218,24 @@ constructor( from: Float, to: Float, durationMs: Long, - delayMs: Long, - @Position position: Int + delayMs: Long = 0, + @Position positions: Int = POSITION_TOP or POSITION_BOTTOM, + interpolator: Interpolator = Interpolators.LINEAR ): Animator { return ValueAnimator.ofFloat(from, to).apply { duration = durationMs startDelay = delayMs - interpolator = Interpolators.LINEAR + this.interpolator = interpolator addUpdateListener { va: ValueAnimator -> - setElementsAlphaAtPosition( - alpha = va.animatedValue as Float, - position = position, - fadingOut = to < from + ComplicationLayoutParams.iteratePositions( + { position: Int -> + setElementsAlphaAtPosition( + alpha = va.animatedValue as Float, + position = position, + fadingOut = to < from + ) + }, + positions ) } } @@ -239,16 +245,21 @@ constructor( from: Float, to: Float, durationMs: Long, - delayMs: Long, - @Position position: Int, - animInterpolator: Interpolator + delayMs: Long = 0, + @Position positions: Int = POSITION_TOP or POSITION_BOTTOM, + interpolator: Interpolator = Interpolators.LINEAR ): Animator { return ValueAnimator.ofFloat(from, to).apply { duration = durationMs startDelay = delayMs - interpolator = animInterpolator + this.interpolator = interpolator addUpdateListener { va: ValueAnimator -> - setElementsTranslationYAtPosition(va.animatedValue as Float, position) + ComplicationLayoutParams.iteratePositions( + { position: Int -> + setElementsTranslationYAtPosition(va.animatedValue as Float, position) + }, + positions + ) } } } @@ -263,7 +274,7 @@ constructor( CrossFadeHelper.fadeIn(view, alpha, /* remap= */ false) } } - if (position == ComplicationLayoutParams.POSITION_TOP) { + if (position == POSITION_TOP) { mStatusBarViewController.setFadeAmount(alpha, fadingOut) } } @@ -273,7 +284,7 @@ constructor( mComplicationHostViewController.getViewsAtPosition(position).forEach { v -> v.translationY = translationY } - if (position == ComplicationLayoutParams.POSITION_TOP) { + if (position == POSITION_TOP) { mStatusBarViewController.setTranslationY(translationY) } } diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutParams.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutParams.java index 1755cb92da70..99e19fc96d8f 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutParams.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutParams.java @@ -251,9 +251,17 @@ public class ComplicationLayoutParams extends ViewGroup.LayoutParams { * position specified for this {@link ComplicationLayoutParams}. */ public void iteratePositions(Consumer<Integer> consumer) { + iteratePositions(consumer, mPosition); + } + + /** + * Iterates over the defined positions and invokes the specified {@link Consumer} for each + * position specified by the given {@code position}. + */ + public static void iteratePositions(Consumer<Integer> consumer, @Position int position) { for (int currentPosition = FIRST_POSITION; currentPosition <= LAST_POSITION; currentPosition <<= 1) { - if ((mPosition & currentPosition) == currentPosition) { + if ((position & currentPosition) == currentPosition) { consumer.accept(currentPosition); } } diff --git a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java index ed0e1d97e40a..4f1ac1a8abd5 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java @@ -47,14 +47,14 @@ public abstract class DreamOverlayModule { public static final String BURN_IN_PROTECTION_UPDATE_INTERVAL = "burn_in_protection_update_interval"; public static final String MILLIS_UNTIL_FULL_JITTER = "millis_until_full_jitter"; + public static final String DREAM_BLUR_RADIUS = "DREAM_BLUR_RADIUS"; public static final String DREAM_IN_BLUR_ANIMATION_DURATION = "dream_in_blur_anim_duration"; - public static final String DREAM_IN_BLUR_ANIMATION_DELAY = "dream_in_blur_anim_delay"; public static final String DREAM_IN_COMPLICATIONS_ANIMATION_DURATION = "dream_in_complications_anim_duration"; - public static final String DREAM_IN_TOP_COMPLICATIONS_ANIMATION_DELAY = - "dream_in_top_complications_anim_delay"; - public static final String DREAM_IN_BOTTOM_COMPLICATIONS_ANIMATION_DELAY = - "dream_in_bottom_complications_anim_delay"; + public static final String DREAM_IN_TRANSLATION_Y_DISTANCE = + "dream_in_complications_translation_y"; + public static final String DREAM_IN_TRANSLATION_Y_DURATION = + "dream_in_complications_translation_y_duration"; public static final String DREAM_OUT_TRANSLATION_Y_DISTANCE = "dream_out_complications_translation_y"; public static final String DREAM_OUT_TRANSLATION_Y_DURATION = @@ -139,21 +139,21 @@ public abstract class DreamOverlayModule { } /** - * Duration in milliseconds of the dream in un-blur animation. + * The blur radius applied to the dream overlay at dream entry and exit. */ @Provides - @Named(DREAM_IN_BLUR_ANIMATION_DURATION) - static long providesDreamInBlurAnimationDuration(@Main Resources resources) { - return (long) resources.getInteger(R.integer.config_dreamOverlayInBlurDurationMs); + @Named(DREAM_BLUR_RADIUS) + static int providesDreamBlurRadius(@Main Resources resources) { + return resources.getDimensionPixelSize(R.dimen.dream_overlay_anim_blur_radius); } /** - * Delay in milliseconds of the dream in un-blur animation. + * Duration in milliseconds of the dream in un-blur animation. */ @Provides - @Named(DREAM_IN_BLUR_ANIMATION_DELAY) - static long providesDreamInBlurAnimationDelay(@Main Resources resources) { - return (long) resources.getInteger(R.integer.config_dreamOverlayInBlurDelayMs); + @Named(DREAM_IN_BLUR_ANIMATION_DURATION) + static long providesDreamInBlurAnimationDuration(@Main Resources resources) { + return (long) resources.getInteger(R.integer.config_dreamOverlayInBlurDurationMs); } /** @@ -166,22 +166,23 @@ public abstract class DreamOverlayModule { } /** - * Delay in milliseconds of the dream in top complications fade-in animation. + * Provides the number of pixels to translate complications when entering a dream. */ @Provides - @Named(DREAM_IN_TOP_COMPLICATIONS_ANIMATION_DELAY) - static long providesDreamInTopComplicationsAnimationDelay(@Main Resources resources) { - return (long) resources.getInteger(R.integer.config_dreamOverlayInTopComplicationsDelayMs); + @Named(DREAM_IN_TRANSLATION_Y_DISTANCE) + @DreamOverlayComponent.DreamOverlayScope + static int providesDreamInComplicationsTranslationY(@Main Resources resources) { + return resources.getDimensionPixelSize(R.dimen.dream_overlay_entry_y_offset); } /** - * Delay in milliseconds of the dream in bottom complications fade-in animation. + * Provides the duration in ms of the y-translation when dream enters. */ @Provides - @Named(DREAM_IN_BOTTOM_COMPLICATIONS_ANIMATION_DELAY) - static long providesDreamInBottomComplicationsAnimationDelay(@Main Resources resources) { - return (long) resources.getInteger( - R.integer.config_dreamOverlayInBottomComplicationsDelayMs); + @Named(DREAM_IN_TRANSLATION_Y_DURATION) + @DreamOverlayComponent.DreamOverlayScope + static long providesDreamInComplicationsTranslationYDuration(@Main Resources resources) { + return (long) resources.getInteger(R.integer.config_dreamOverlayInTranslationYDurationMs); } /** diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardQuickAffordanceProvider.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardQuickAffordanceProvider.kt index 4ae37c51f278..cbcede023708 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardQuickAffordanceProvider.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardQuickAffordanceProvider.kt @@ -21,14 +21,18 @@ import android.content.ContentProvider import android.content.ContentValues import android.content.Context import android.content.UriMatcher +import android.content.pm.PackageManager import android.content.pm.ProviderInfo import android.database.Cursor import android.database.MatrixCursor import android.net.Uri +import android.os.Binder +import android.os.Bundle import android.util.Log import com.android.systemui.SystemUIAppComponentFactoryBase import com.android.systemui.SystemUIAppComponentFactoryBase.ContextAvailableCallback import com.android.systemui.keyguard.domain.interactor.KeyguardQuickAffordanceInteractor +import com.android.systemui.keyguard.ui.preview.KeyguardRemotePreviewManager import com.android.systemui.shared.quickaffordance.data.content.KeyguardQuickAffordanceProviderContract as Contract import javax.inject.Inject import kotlinx.coroutines.runBlocking @@ -37,6 +41,7 @@ class KeyguardQuickAffordanceProvider : ContentProvider(), SystemUIAppComponentFactoryBase.ContextInitializer { @Inject lateinit var interactor: KeyguardQuickAffordanceInteractor + @Inject lateinit var previewManager: KeyguardRemotePreviewManager private lateinit var contextAvailableCallback: ContextAvailableCallback @@ -149,6 +154,21 @@ class KeyguardQuickAffordanceProvider : return deleteSelection(uri, selectionArgs) } + override fun call(method: String, arg: String?, extras: Bundle?): Bundle? { + return if ( + requireContext() + .checkPermission( + android.Manifest.permission.BIND_WALLPAPER, + Binder.getCallingPid(), + Binder.getCallingUid(), + ) == PackageManager.PERMISSION_GRANTED + ) { + previewManager.preview(extras) + } else { + null + } + } + private fun insertSelection(values: ContentValues?): Uri? { if (values == null) { throw IllegalArgumentException("Cannot insert selection, no values passed in!") diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index d4b6386ff706..96ec43dd725e 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -25,6 +25,7 @@ import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.NAV_BA import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_OCCLUSION; import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_TRANSITION_FROM_AOD; import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_UNLOCK_ANIMATION; +import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT; @@ -142,12 +143,12 @@ import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.UserSwitcherController; import com.android.systemui.util.DeviceConfigProxy; +import dagger.Lazy; + import java.io.PrintWriter; import java.util.ArrayList; import java.util.concurrent.Executor; -import dagger.Lazy; - /** * Mediates requests related to the keyguard. This includes queries about the * state of the keyguard, power management events that effect whether the keyguard @@ -821,6 +822,9 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, } else if (trustAgentsEnabled && (strongAuth & SOME_AUTH_REQUIRED_AFTER_USER_REQUEST) != 0) { return KeyguardSecurityView.PROMPT_REASON_USER_REQUEST; + } else if (trustAgentsEnabled + && (strongAuth & SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED) != 0) { + return KeyguardSecurityView.PROMPT_REASON_TRUSTAGENT_EXPIRED; } else if (any && ((strongAuth & STRONG_AUTH_REQUIRED_AFTER_LOCKOUT) != 0 || mUpdateMonitor.isFingerprintLockedOut())) { return KeyguardSecurityView.PROMPT_REASON_AFTER_LOCKOUT; diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt index 748c6e8b75b9..57668c795d1c 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt @@ -34,7 +34,6 @@ import com.android.systemui.keyguard.shared.model.KeyguardSlotPickerRepresentati import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancePosition import com.android.systemui.plugins.ActivityStarter import com.android.systemui.settings.UserTracker -import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots import com.android.systemui.shared.quickaffordance.data.content.KeyguardQuickAffordanceProviderContract import com.android.systemui.statusbar.policy.KeyguardStateController import dagger.Lazy @@ -62,12 +61,20 @@ constructor( private val isUsingRepository: Boolean get() = featureFlags.isEnabled(Flags.CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES) + /** + * Whether the UI should use the long press gesture to activate quick affordances. + * + * If `false`, the UI goes back to using single taps. + */ + val useLongPress: Boolean + get() = featureFlags.isEnabled(Flags.CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES) + /** Returns an observable for the quick affordance at the given position. */ fun quickAffordance( position: KeyguardQuickAffordancePosition ): Flow<KeyguardQuickAffordanceModel> { return combine( - quickAffordanceInternal(position), + quickAffordanceAlwaysVisible(position), keyguardInteractor.isDozing, keyguardInteractor.isKeyguardShowing, ) { affordance, isDozing, isKeyguardShowing -> @@ -80,6 +87,19 @@ constructor( } /** + * Returns an observable for the quick affordance at the given position but always visible, + * regardless of lock screen state. + * + * This is useful for experiences like the lock screen preview mode, where the affordances must + * always be visible. + */ + fun quickAffordanceAlwaysVisible( + position: KeyguardQuickAffordancePosition, + ): Flow<KeyguardQuickAffordanceModel> { + return quickAffordanceInternal(position) + } + + /** * Notifies that a quick affordance has been "triggered" (clicked) by the user. * * @param configKey The configuration key corresponding to the [KeyguardQuickAffordanceModel] of @@ -290,15 +310,6 @@ constructor( } } - private fun KeyguardQuickAffordancePosition.toSlotId(): String { - return when (this) { - KeyguardQuickAffordancePosition.BOTTOM_START -> - KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START - KeyguardQuickAffordancePosition.BOTTOM_END -> - KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END - } - } - private fun String.encode(slotId: String): String { return "$slotId$DELIMITER$this" } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/quickaffordance/KeyguardQuickAffordancePosition.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/quickaffordance/KeyguardQuickAffordancePosition.kt index a18b036c5189..2581b595d812 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/quickaffordance/KeyguardQuickAffordancePosition.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/quickaffordance/KeyguardQuickAffordancePosition.kt @@ -16,8 +16,17 @@ package com.android.systemui.keyguard.shared.quickaffordance +import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots + /** Enumerates all possible positions for quick affordances that can appear on the lock-screen. */ enum class KeyguardQuickAffordancePosition { BOTTOM_START, - BOTTOM_END, + BOTTOM_END; + + fun toSlotId(): String { + return when (this) { + BOTTOM_START -> KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START + BOTTOM_END -> KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt index cbe512ff83ba..ae8edfece4cb 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt @@ -16,14 +16,19 @@ package com.android.systemui.keyguard.ui.binder +import android.annotation.SuppressLint import android.graphics.drawable.Animatable2 import android.util.Size import android.util.TypedValue +import android.view.MotionEvent import android.view.View +import android.view.ViewConfiguration import android.view.ViewGroup import android.view.ViewPropertyAnimator import android.widget.ImageView import android.widget.TextView +import androidx.core.animation.CycleInterpolator +import androidx.core.animation.ObjectAnimator import androidx.core.view.isVisible import androidx.core.view.updateLayoutParams import androidx.lifecycle.Lifecycle @@ -38,8 +43,10 @@ import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardQuickAffordanceViewModel import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.plugins.FalsingManager +import kotlin.math.pow +import kotlin.math.sqrt +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.map @@ -52,6 +59,7 @@ import kotlinx.coroutines.launch * view-binding, binding each view only once. It is okay and expected for the same instance of the * view-model to be reused for multiple view/view-binder bindings. */ +@OptIn(ExperimentalCoroutinesApi::class) object KeyguardBottomAreaViewBinder { private const val EXIT_DOZE_BUTTON_REVEAL_ANIMATION_DURATION_MS = 250L @@ -84,7 +92,8 @@ object KeyguardBottomAreaViewBinder { fun bind( view: ViewGroup, viewModel: KeyguardBottomAreaViewModel, - falsingManager: FalsingManager, + falsingManager: FalsingManager?, + messageDisplayer: (Int) -> Unit, ): Binding { val indicationArea: View = view.requireViewById(R.id.keyguard_indication_area) val ambientIndicationArea: View? = view.findViewById(R.id.ambient_indication_container) @@ -108,6 +117,7 @@ object KeyguardBottomAreaViewBinder { view = startButton, viewModel = buttonModel, falsingManager = falsingManager, + messageDisplayer = messageDisplayer, ) } } @@ -118,6 +128,7 @@ object KeyguardBottomAreaViewBinder { view = endButton, viewModel = buttonModel, falsingManager = falsingManager, + messageDisplayer = messageDisplayer, ) } } @@ -222,10 +233,12 @@ object KeyguardBottomAreaViewBinder { } } + @SuppressLint("ClickableViewAccessibility") private fun updateButton( view: ImageView, viewModel: KeyguardQuickAffordanceViewModel, - falsingManager: FalsingManager, + falsingManager: FalsingManager?, + messageDisplayer: (Int) -> Unit, ) { if (!viewModel.isVisible) { view.isVisible = false @@ -281,21 +294,126 @@ object KeyguardBottomAreaViewBinder { }, ) ) + view.backgroundTintList = - Utils.getColorAttr( - view.context, - if (viewModel.isActivated) { - com.android.internal.R.attr.colorAccentPrimary - } else { - com.android.internal.R.attr.colorSurface - } - ) + if (!viewModel.isSelected) { + Utils.getColorAttr( + view.context, + if (viewModel.isActivated) { + com.android.internal.R.attr.colorAccentPrimary + } else { + com.android.internal.R.attr.colorSurface + } + ) + } else { + null + } view.isClickable = viewModel.isClickable if (viewModel.isClickable) { - view.setOnClickListener(OnClickListener(viewModel, falsingManager)) + if (viewModel.useLongPress) { + view.setOnTouchListener(OnTouchListener(view, viewModel, messageDisplayer)) + } else { + view.setOnClickListener(OnClickListener(viewModel, checkNotNull(falsingManager))) + } } else { view.setOnClickListener(null) + view.setOnTouchListener(null) + } + + view.isSelected = viewModel.isSelected + } + + private class OnTouchListener( + private val view: View, + private val viewModel: KeyguardQuickAffordanceViewModel, + private val messageDisplayer: (Int) -> Unit, + ) : View.OnTouchListener { + + private val longPressDurationMs = ViewConfiguration.getLongPressTimeout().toLong() + private var longPressAnimator: ViewPropertyAnimator? = null + private var downTimestamp = 0L + + @SuppressLint("ClickableViewAccessibility") + override fun onTouch(v: View?, event: MotionEvent?): Boolean { + return when (event?.actionMasked) { + MotionEvent.ACTION_DOWN -> + if (viewModel.configKey != null) { + downTimestamp = System.currentTimeMillis() + longPressAnimator = + view + .animate() + .scaleX(PRESSED_SCALE) + .scaleY(PRESSED_SCALE) + .setDuration(longPressDurationMs) + .withEndAction { + view.setOnClickListener { + viewModel.onClicked( + KeyguardQuickAffordanceViewModel.OnClickedParameters( + configKey = viewModel.configKey, + expandable = Expandable.fromView(view), + ) + ) + } + view.performClick() + view.setOnClickListener(null) + } + true + } else { + false + } + MotionEvent.ACTION_MOVE -> { + if (event.historySize > 0) { + val distance = + sqrt( + (event.y - event.getHistoricalY(0)).pow(2) + + (event.x - event.getHistoricalX(0)).pow(2) + ) + if (distance > ViewConfiguration.getTouchSlop()) { + cancel() + } + } + true + } + MotionEvent.ACTION_UP -> { + if (System.currentTimeMillis() - downTimestamp < longPressDurationMs) { + messageDisplayer.invoke(R.string.keyguard_affordance_press_too_short) + val shakeAnimator = + ObjectAnimator.ofFloat( + view, + "translationX", + 0f, + view.context.resources + .getDimensionPixelSize( + R.dimen.keyguard_affordance_shake_amplitude + ) + .toFloat(), + 0f, + ) + shakeAnimator.duration = 300 + shakeAnimator.interpolator = CycleInterpolator(5f) + shakeAnimator.start() + } + cancel() + true + } + MotionEvent.ACTION_CANCEL -> { + cancel() + true + } + else -> false + } + } + + private fun cancel() { + downTimestamp = 0L + longPressAnimator?.cancel() + longPressAnimator = null + view.animate().scaleX(1f).scaleY(1f) + } + + companion object { + private const val PRESSED_SCALE = 1.5f } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt new file mode 100644 index 000000000000..a5ae8ba58d45 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt @@ -0,0 +1,207 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.android.systemui.keyguard.ui.preview + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.hardware.display.DisplayManager +import android.os.Bundle +import android.os.IBinder +import android.view.Gravity +import android.view.LayoutInflater +import android.view.SurfaceControlViewHost +import android.view.View +import android.view.ViewGroup +import android.view.WindowManager +import android.widget.FrameLayout +import com.android.keyguard.ClockEventController +import com.android.keyguard.KeyguardClockSwitch +import com.android.systemui.R +import com.android.systemui.broadcast.BroadcastDispatcher +import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel +import com.android.systemui.shared.clocks.ClockRegistry +import com.android.systemui.shared.quickaffordance.shared.model.KeyguardQuickAffordancePreviewConstants +import com.android.systemui.statusbar.phone.KeyguardBottomAreaView +import dagger.assisted.Assisted +import dagger.assisted.AssistedInject +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.DisposableHandle +import kotlinx.coroutines.runBlocking + +/** Renders the preview of the lock screen. */ +class KeyguardPreviewRenderer +@AssistedInject +constructor( + @Application private val context: Context, + @Main private val mainDispatcher: CoroutineDispatcher, + private val bottomAreaViewModel: KeyguardBottomAreaViewModel, + displayManager: DisplayManager, + private val windowManager: WindowManager, + private val clockController: ClockEventController, + private val clockRegistry: ClockRegistry, + private val broadcastDispatcher: BroadcastDispatcher, + @Assisted bundle: Bundle, +) { + + val hostToken: IBinder? = bundle.getBinder(KEY_HOST_TOKEN) + private val width: Int = bundle.getInt(KEY_VIEW_WIDTH) + private val height: Int = bundle.getInt(KEY_VIEW_HEIGHT) + + private var host: SurfaceControlViewHost + + val surfacePackage: SurfaceControlViewHost.SurfacePackage + get() = host.surfacePackage + + private var clockView: View? = null + + private val disposables = mutableSetOf<DisposableHandle>() + private var isDestroyed = false + + init { + bottomAreaViewModel.enablePreviewMode( + initiallySelectedSlotId = + bundle.getString( + KeyguardQuickAffordancePreviewConstants.KEY_INITIALLY_SELECTED_SLOT_ID, + ), + ) + runBlocking(mainDispatcher) { + host = + SurfaceControlViewHost( + context, + displayManager.getDisplay(bundle.getInt(KEY_DISPLAY_ID)), + hostToken, + ) + disposables.add(DisposableHandle { host.release() }) + } + } + + fun render() { + runBlocking(mainDispatcher) { + val rootView = FrameLayout(context) + + setUpBottomArea(rootView) + setUpClock(rootView) + + rootView.measure( + View.MeasureSpec.makeMeasureSpec( + windowManager.currentWindowMetrics.bounds.width(), + View.MeasureSpec.EXACTLY + ), + View.MeasureSpec.makeMeasureSpec( + windowManager.currentWindowMetrics.bounds.height(), + View.MeasureSpec.EXACTLY + ), + ) + rootView.layout(0, 0, rootView.measuredWidth, rootView.measuredHeight) + + // This aspect scales the view to fit in the surface and centers it + val scale: Float = + (width / rootView.measuredWidth.toFloat()).coerceAtMost( + height / rootView.measuredHeight.toFloat() + ) + + rootView.scaleX = scale + rootView.scaleY = scale + rootView.pivotX = 0f + rootView.pivotY = 0f + rootView.translationX = (width - scale * rootView.width) / 2 + rootView.translationY = (height - scale * rootView.height) / 2 + + host.setView(rootView, rootView.measuredWidth, rootView.measuredHeight) + } + } + + fun onSlotSelected(slotId: String) { + bottomAreaViewModel.onPreviewSlotSelected(slotId = slotId) + } + + fun destroy() { + isDestroyed = true + disposables.forEach { it.dispose() } + } + + private fun setUpBottomArea(parentView: ViewGroup) { + val bottomAreaView = + LayoutInflater.from(context) + .inflate( + R.layout.keyguard_bottom_area, + parentView, + false, + ) as KeyguardBottomAreaView + bottomAreaView.init( + viewModel = bottomAreaViewModel, + ) + parentView.addView( + bottomAreaView, + FrameLayout.LayoutParams( + FrameLayout.LayoutParams.MATCH_PARENT, + FrameLayout.LayoutParams.WRAP_CONTENT, + Gravity.BOTTOM, + ), + ) + } + + private fun setUpClock(parentView: ViewGroup) { + val clockChangeListener = ClockRegistry.ClockChangeListener { onClockChanged(parentView) } + clockRegistry.registerClockChangeListener(clockChangeListener) + disposables.add( + DisposableHandle { clockRegistry.unregisterClockChangeListener(clockChangeListener) } + ) + + clockController.registerListeners(parentView) + disposables.add(DisposableHandle { clockController.unregisterListeners() }) + + val receiver = + object : BroadcastReceiver() { + override fun onReceive(context: Context?, intent: Intent?) { + clockController.clock?.events?.onTimeTick() + } + } + broadcastDispatcher.registerReceiver( + receiver, + IntentFilter().apply { + addAction(Intent.ACTION_TIME_TICK) + addAction(Intent.ACTION_TIME_CHANGED) + }, + ) + disposables.add(DisposableHandle { broadcastDispatcher.unregisterReceiver(receiver) }) + + onClockChanged(parentView) + } + + private fun onClockChanged(parentView: ViewGroup) { + clockController.clock = clockRegistry.createCurrentClock() + clockController.clock + ?.largeClock + ?.events + ?.onTargetRegionChanged(KeyguardClockSwitch.getLargeClockRegion(parentView)) + clockView?.let { parentView.removeView(it) } + clockView = clockController.clock?.largeClock?.view?.apply { parentView.addView(this) } + } + + companion object { + private const val KEY_HOST_TOKEN = "host_token" + private const val KEY_VIEW_WIDTH = "width" + private const val KEY_VIEW_HEIGHT = "height" + private const val KEY_DISPLAY_ID = "display_id" + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRendererFactory.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRendererFactory.kt new file mode 100644 index 000000000000..be1d3a18520a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRendererFactory.kt @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.android.systemui.keyguard.ui.preview + +import android.os.Bundle +import dagger.assisted.AssistedFactory + +@AssistedFactory +interface KeyguardPreviewRendererFactory { + fun create(bundle: Bundle): KeyguardPreviewRenderer +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardRemotePreviewManager.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardRemotePreviewManager.kt new file mode 100644 index 000000000000..50722d5c68f8 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardRemotePreviewManager.kt @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.android.systemui.keyguard.ui.preview + +import android.os.Bundle +import android.os.Handler +import android.os.IBinder +import android.os.Message +import android.os.Messenger +import android.util.ArrayMap +import android.util.Log +import androidx.annotation.VisibleForTesting +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.shared.quickaffordance.shared.model.KeyguardQuickAffordancePreviewConstants +import javax.inject.Inject +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.runBlocking + +@SysUISingleton +class KeyguardRemotePreviewManager +@Inject +constructor( + private val previewRendererFactory: KeyguardPreviewRendererFactory, + @Main private val mainDispatcher: CoroutineDispatcher, + @Background private val backgroundHandler: Handler, +) { + private val activePreviews: ArrayMap<IBinder, PreviewLifecycleObserver> = + ArrayMap<IBinder, PreviewLifecycleObserver>() + + fun preview(request: Bundle?): Bundle? { + if (request == null) { + return null + } + + var observer: PreviewLifecycleObserver? = null + return try { + val renderer = previewRendererFactory.create(request) + + // Destroy any previous renderer associated with this token. + activePreviews[renderer.hostToken]?.let { destroyObserver(it) } + observer = PreviewLifecycleObserver(renderer, mainDispatcher, ::destroyObserver) + activePreviews[renderer.hostToken] = observer + renderer.render() + renderer.hostToken?.linkToDeath(observer, 0) + val result = Bundle() + result.putParcelable( + KEY_PREVIEW_SURFACE_PACKAGE, + renderer.surfacePackage, + ) + val messenger = + Messenger( + Handler( + backgroundHandler.looper, + observer, + ) + ) + val msg = Message.obtain() + msg.replyTo = messenger + result.putParcelable(KEY_PREVIEW_CALLBACK, msg) + result + } catch (e: Exception) { + Log.e(TAG, "Unable to generate preview", e) + observer?.let { destroyObserver(it) } + null + } + } + + private fun destroyObserver(observer: PreviewLifecycleObserver) { + observer.onDestroy()?.let { hostToken -> + if (activePreviews[hostToken] === observer) { + activePreviews.remove(hostToken) + } + } + } + + private class PreviewLifecycleObserver( + private val renderer: KeyguardPreviewRenderer, + private val mainDispatcher: CoroutineDispatcher, + private val requestDestruction: (PreviewLifecycleObserver) -> Unit, + ) : Handler.Callback, IBinder.DeathRecipient { + + private var isDestroyed = false + + override fun handleMessage(message: Message): Boolean { + when (message.what) { + KeyguardQuickAffordancePreviewConstants.MESSAGE_ID_SLOT_SELECTED -> { + message.data + .getString( + KeyguardQuickAffordancePreviewConstants.KEY_SLOT_ID, + ) + ?.let { slotId -> renderer.onSlotSelected(slotId = slotId) } + } + else -> requestDestruction(this) + } + + return true + } + + override fun binderDied() { + requestDestruction(this) + } + + fun onDestroy(): IBinder? { + if (isDestroyed) { + return null + } + + isDestroyed = true + val hostToken = renderer.hostToken + hostToken?.unlinkToDeath(this, 0) + runBlocking(mainDispatcher) { renderer.destroy() } + return hostToken + } + } + + companion object { + private const val TAG = "KeyguardRemotePreviewManager" + @VisibleForTesting const val KEY_PREVIEW_SURFACE_PACKAGE = "surface_package" + @VisibleForTesting const val KEY_PREVIEW_CALLBACK = "callback" + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt index 227796f43e35..5d85680efcf4 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt @@ -24,13 +24,19 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardQuickAffordanceIn import com.android.systemui.keyguard.domain.model.KeyguardQuickAffordanceModel import com.android.systemui.keyguard.shared.quickaffordance.ActivationState import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancePosition +import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots import javax.inject.Inject +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map /** View-model for the keyguard bottom area view */ +@OptIn(ExperimentalCoroutinesApi::class) class KeyguardBottomAreaViewModel @Inject constructor( @@ -40,6 +46,20 @@ constructor( private val burnInHelperWrapper: BurnInHelperWrapper, ) { /** + * Whether this view-model instance is powering the preview experience that renders exclusively + * in the wallpaper picker application. This should _always_ be `false` for the real lock screen + * experience. + */ + private val isInPreviewMode = MutableStateFlow(false) + + /** + * ID of the slot that's currently selected in the preview that renders exclusively in the + * wallpaper picker application. This is ignored for the actual, real lock screen experience. + */ + private val selectedPreviewSlotId = + MutableStateFlow(KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START) + + /** * Whether quick affordances are "opaque enough" to be considered visible to and interactive by * the user. If they are not interactive, user input should not be allowed on them. * @@ -66,7 +86,14 @@ constructor( val isOverlayContainerVisible: Flow<Boolean> = keyguardInteractor.isDozing.map { !it }.distinctUntilChanged() /** An observable for the alpha level for the entire bottom area. */ - val alpha: Flow<Float> = bottomAreaInteractor.alpha.distinctUntilChanged() + val alpha: Flow<Float> = + isInPreviewMode.flatMapLatest { isInPreviewMode -> + if (isInPreviewMode) { + flowOf(1f) + } else { + bottomAreaInteractor.alpha.distinctUntilChanged() + } + } /** An observable for whether the indication area should be padded. */ val isIndicationAreaPadded: Flow<Boolean> = combine(startButton, endButton) { startButtonModel, endButtonModel -> @@ -94,27 +121,61 @@ constructor( * Returns whether the keyguard bottom area should be constrained to the top of the lock icon */ fun shouldConstrainToTopOfLockIcon(): Boolean = - bottomAreaInteractor.shouldConstrainToTopOfLockIcon() + bottomAreaInteractor.shouldConstrainToTopOfLockIcon() + + /** + * Puts this view-model in "preview mode", which means it's being used for UI that is rendering + * the lock screen preview in wallpaper picker / settings and not the real experience on the + * lock screen. + * + * @param initiallySelectedSlotId The ID of the initial slot to render as the selected one. + */ + fun enablePreviewMode(initiallySelectedSlotId: String?) { + isInPreviewMode.value = true + onPreviewSlotSelected( + initiallySelectedSlotId ?: KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START + ) + } + + /** + * Notifies that a slot with the given ID has been selected in the preview experience that is + * rendering in the wallpaper picker. This is ignored for the real lock screen experience. + * + * @see enablePreviewMode + */ + fun onPreviewSlotSelected(slotId: String) { + selectedPreviewSlotId.value = slotId + } private fun button( position: KeyguardQuickAffordancePosition ): Flow<KeyguardQuickAffordanceViewModel> { - return combine( - quickAffordanceInteractor.quickAffordance(position), - bottomAreaInteractor.animateDozingTransitions.distinctUntilChanged(), - areQuickAffordancesFullyOpaque, - ) { model, animateReveal, isFullyOpaque -> - model.toViewModel( - animateReveal = animateReveal, - isClickable = isFullyOpaque, - ) - } - .distinctUntilChanged() + return isInPreviewMode.flatMapLatest { isInPreviewMode -> + combine( + if (isInPreviewMode) { + quickAffordanceInteractor.quickAffordanceAlwaysVisible(position = position) + } else { + quickAffordanceInteractor.quickAffordance(position = position) + }, + bottomAreaInteractor.animateDozingTransitions.distinctUntilChanged(), + areQuickAffordancesFullyOpaque, + selectedPreviewSlotId, + ) { model, animateReveal, isFullyOpaque, selectedPreviewSlotId -> + model.toViewModel( + animateReveal = !isInPreviewMode && animateReveal, + isClickable = isFullyOpaque && !isInPreviewMode, + isSelected = + (isInPreviewMode && selectedPreviewSlotId == position.toSlotId()), + ) + } + .distinctUntilChanged() + } } private fun KeyguardQuickAffordanceModel.toViewModel( animateReveal: Boolean, isClickable: Boolean, + isSelected: Boolean, ): KeyguardQuickAffordanceViewModel { return when (this) { is KeyguardQuickAffordanceModel.Visible -> @@ -131,6 +192,8 @@ constructor( }, isClickable = isClickable, isActivated = activationState is ActivationState.Active, + isSelected = isSelected, + useLongPress = quickAffordanceInteractor.useLongPress, ) is KeyguardQuickAffordanceModel.Hidden -> KeyguardQuickAffordanceViewModel() } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordanceViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordanceViewModel.kt index 44f48f97b62e..cf3a6daa40bb 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordanceViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordanceViewModel.kt @@ -29,6 +29,8 @@ data class KeyguardQuickAffordanceViewModel( val onClicked: (OnClickedParameters) -> Unit = {}, val isClickable: Boolean = false, val isActivated: Boolean = false, + val isSelected: Boolean = false, + val useLongPress: Boolean = false, ) { data class OnClickedParameters( val configKey: String, diff --git a/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java b/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java index 3e5d337bff9d..bb833df1ff69 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java +++ b/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java @@ -30,9 +30,11 @@ import com.android.systemui.media.nearby.NearbyMediaDevicesManager; import com.android.systemui.media.taptotransfer.MediaTttCommandLineHelper; import com.android.systemui.media.taptotransfer.MediaTttFlags; import com.android.systemui.media.taptotransfer.common.MediaTttLogger; +import com.android.systemui.media.taptotransfer.receiver.ChipReceiverInfo; import com.android.systemui.media.taptotransfer.receiver.MediaTttReceiverLogger; import com.android.systemui.media.taptotransfer.sender.MediaTttSenderLogger; import com.android.systemui.plugins.log.LogBuffer; +import com.android.systemui.temporarydisplay.chipbar.ChipbarInfo; import java.util.Optional; @@ -95,19 +97,19 @@ public interface MediaModule { @Provides @SysUISingleton @MediaTttSenderLogger - static MediaTttLogger providesMediaTttSenderLogger( + static MediaTttLogger<ChipbarInfo> providesMediaTttSenderLogger( @MediaTttSenderLogBuffer LogBuffer buffer ) { - return new MediaTttLogger("Sender", buffer); + return new MediaTttLogger<>("Sender", buffer); } @Provides @SysUISingleton @MediaTttReceiverLogger - static MediaTttLogger providesMediaTttReceiverLogger( + static MediaTttLogger<ChipReceiverInfo> providesMediaTttReceiverLogger( @MediaTttReceiverLogBuffer LogBuffer buffer ) { - return new MediaTttLogger("Receiver", buffer); + return new MediaTttLogger<>("Receiver", buffer); } /** */ diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttLogger.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttLogger.kt index b55bedda2dc1..8aef9385fe3e 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttLogger.kt @@ -18,17 +18,21 @@ package com.android.systemui.media.taptotransfer.common import com.android.systemui.plugins.log.LogBuffer import com.android.systemui.plugins.log.LogLevel +import com.android.systemui.temporarydisplay.TemporaryViewInfo import com.android.systemui.temporarydisplay.TemporaryViewLogger /** * A logger for media tap-to-transfer events. * * @param deviceTypeTag the type of device triggering the logs -- "Sender" or "Receiver". + * + * TODO(b/245610654): We should de-couple the sender and receiver loggers, since they're vastly + * different experiences. */ -class MediaTttLogger( +class MediaTttLogger<T : TemporaryViewInfo>( deviceTypeTag: String, buffer: LogBuffer -) : TemporaryViewLogger(buffer, BASE_TAG + deviceTypeTag) { +) : TemporaryViewLogger<T>(buffer, BASE_TAG + deviceTypeTag) { /** Logs a change in the chip state for the given [mediaRouteId]. */ fun logStateChange(stateName: String, mediaRouteId: String, packageName: String?) { buffer.log( diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttUtils.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttUtils.kt index 009595a6da8b..066c1853818f 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttUtils.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttUtils.kt @@ -25,6 +25,7 @@ import com.android.systemui.R import com.android.systemui.common.shared.model.ContentDescription import com.android.systemui.common.shared.model.Icon import com.android.systemui.common.shared.model.TintedIcon +import com.android.systemui.temporarydisplay.TemporaryViewInfo /** Utility methods for media tap-to-transfer. */ class MediaTttUtils { @@ -47,7 +48,7 @@ class MediaTttUtils { fun getIconInfoFromPackageName( context: Context, appPackageName: String?, - logger: MediaTttLogger + logger: MediaTttLogger<out TemporaryViewInfo> ): IconInfo { if (appPackageName != null) { val packageManager = context.packageManager diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ChipStateReceiver.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ChipStateReceiver.kt index 40ea1e6e87df..11348adb582c 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ChipStateReceiver.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ChipStateReceiver.kt @@ -35,6 +35,14 @@ enum class ChipStateReceiver( FAR_FROM_SENDER( StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_FAR_FROM_SENDER, MediaTttReceiverUiEvents.MEDIA_TTT_RECEIVER_FAR_FROM_SENDER + ), + TRANSFER_TO_RECEIVER_SUCCEEDED( + StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED, + MediaTttReceiverUiEvents.MEDIA_TTT_RECEIVER_TRANSFER_TO_RECEIVER_SUCCEEDED, + ), + TRANSFER_TO_RECEIVER_FAILED( + StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_TRANSFER_TO_RECEIVER_FAILED, + MediaTttReceiverUiEvents.MEDIA_TTT_RECEIVER_TRANSFER_TO_RECEIVER_FAILED, ); companion object { diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt index 1c3a53cbf815..7b9d0b4205af 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt @@ -45,8 +45,10 @@ import com.android.systemui.statusbar.CommandQueue import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.temporarydisplay.TemporaryViewDisplayController import com.android.systemui.temporarydisplay.TemporaryViewInfo +import com.android.systemui.temporarydisplay.ViewPriority import com.android.systemui.util.animation.AnimationUtil.Companion.frames import com.android.systemui.util.concurrency.DelayableExecutor +import com.android.systemui.util.time.SystemClock import com.android.systemui.util.view.ViewUtil import com.android.systemui.util.wakelock.WakeLock import javax.inject.Inject @@ -62,7 +64,7 @@ import javax.inject.Inject open class MediaTttChipControllerReceiver @Inject constructor( private val commandQueue: CommandQueue, context: Context, - @MediaTttReceiverLogger logger: MediaTttLogger, + @MediaTttReceiverLogger logger: MediaTttLogger<ChipReceiverInfo>, windowManager: WindowManager, mainExecutor: DelayableExecutor, accessibilityManager: AccessibilityManager, @@ -73,7 +75,8 @@ open class MediaTttChipControllerReceiver @Inject constructor( private val uiEventLogger: MediaTttReceiverUiEventLogger, private val viewUtil: ViewUtil, wakeLockBuilder: WakeLock.Builder, -) : TemporaryViewDisplayController<ChipReceiverInfo, MediaTttLogger>( + systemClock: SystemClock, +) : TemporaryViewDisplayController<ChipReceiverInfo, MediaTttLogger<ChipReceiverInfo>>( context, logger, windowManager, @@ -83,6 +86,7 @@ open class MediaTttChipControllerReceiver @Inject constructor( powerManager, R.layout.media_ttt_chip_receiver, wakeLockBuilder, + systemClock, ) { @SuppressLint("WrongConstant") // We're allowed to use LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS override val windowLayoutParams = commonWindowLayoutParams.apply { @@ -123,8 +127,8 @@ open class MediaTttChipControllerReceiver @Inject constructor( } uiEventLogger.logReceiverStateChange(chipState) - if (chipState == ChipStateReceiver.FAR_FROM_SENDER) { - removeView(routeInfo.id, removalReason = ChipStateReceiver.FAR_FROM_SENDER.name) + if (chipState != ChipStateReceiver.CLOSE_TO_SENDER) { + removeView(routeInfo.id, removalReason = chipState.name) return } if (appIcon == null) { @@ -290,4 +294,5 @@ data class ChipReceiverInfo( override val windowTitle: String = MediaTttUtils.WINDOW_TITLE_RECEIVER, override val wakeReason: String = MediaTttUtils.WAKE_REASON_RECEIVER, override val id: String, + override val priority: ViewPriority = ViewPriority.NORMAL, ) : TemporaryViewInfo() diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverUiEventLogger.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverUiEventLogger.kt index 39a276329a9b..6e515f27c25e 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverUiEventLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverUiEventLogger.kt @@ -34,7 +34,11 @@ enum class MediaTttReceiverUiEvents(val metricId: Int) : UiEventLogger.UiEventEn @UiEvent(doc = "See android.app.StatusBarManager.MEDIA_TRANSFER_RECEIVER_* docs") MEDIA_TTT_RECEIVER_CLOSE_TO_SENDER(982), @UiEvent(doc = "See android.app.StatusBarManager.MEDIA_TRANSFER_RECEIVER_* docs") - MEDIA_TTT_RECEIVER_FAR_FROM_SENDER(983); + MEDIA_TTT_RECEIVER_FAR_FROM_SENDER(983), + @UiEvent(doc = "See android.app.StatusBarManager.MEDIA_TRANSFER_RECEIVER_* docs") + MEDIA_TTT_RECEIVER_TRANSFER_TO_RECEIVER_SUCCEEDED(1263), + @UiEvent(doc = "See android.app.StatusBarManager.MEDIA_TRANSFER_RECEIVER_* docs") + MEDIA_TTT_RECEIVER_TRANSFER_TO_RECEIVER_FAILED(1264); override fun getId() = metricId } diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinator.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinator.kt index ec1984d78cf9..9f44d984124f 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinator.kt @@ -30,6 +30,7 @@ import com.android.systemui.media.taptotransfer.MediaTttFlags import com.android.systemui.media.taptotransfer.common.MediaTttLogger import com.android.systemui.media.taptotransfer.common.MediaTttUtils import com.android.systemui.statusbar.CommandQueue +import com.android.systemui.temporarydisplay.ViewPriority import com.android.systemui.temporarydisplay.chipbar.ChipbarCoordinator import com.android.systemui.temporarydisplay.chipbar.ChipbarEndItem import com.android.systemui.temporarydisplay.chipbar.ChipbarInfo @@ -46,7 +47,7 @@ constructor( private val chipbarCoordinator: ChipbarCoordinator, private val commandQueue: CommandQueue, private val context: Context, - @MediaTttSenderLogger private val logger: MediaTttLogger, + @MediaTttSenderLogger private val logger: MediaTttLogger<ChipbarInfo>, private val mediaTttFlags: MediaTttFlags, private val uiEventLogger: MediaTttSenderUiEventLogger, ) : CoreStartable { @@ -146,7 +147,7 @@ constructor( routeInfo: MediaRoute2Info, undoCallback: IUndoMediaTransferCallback?, context: Context, - logger: MediaTttLogger, + logger: MediaTttLogger<ChipbarInfo>, ): ChipbarInfo { val packageName = routeInfo.clientPackageName val otherDeviceName = routeInfo.name.toString() @@ -180,6 +181,7 @@ constructor( wakeReason = MediaTttUtils.WAKE_REASON_SENDER, timeoutMs = chipStateSender.timeout, id = routeInfo.id, + priority = ViewPriority.NORMAL, ) } diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java index d03ac3b419f6..13c5b48906c5 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java @@ -635,8 +635,9 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack } private void updateMLModelState() { - boolean newState = mIsEnabled && DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI, - SystemUiDeviceConfigFlags.USE_BACK_GESTURE_ML_MODEL, false); + boolean newState = + mIsGesturalModeEnabled && DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI, + SystemUiDeviceConfigFlags.USE_BACK_GESTURE_ML_MODEL, false); if (newState == mUseMLModel) { return; @@ -766,7 +767,7 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack // ML model boolean withinMinRange = x < mMLEnableWidth + mLeftInset || x >= (mDisplaySize.x - mMLEnableWidth - mRightInset); - if (!withinMinRange && mUseMLModel + if (!withinMinRange && mUseMLModel && !mMLModelIsLoading && (results = getBackGesturePredictionsCategory(x, y, app)) != -1) { withinRange = (results == 1); } diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java index 6ad0b9acb990..6d6427acec4c 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java @@ -1328,7 +1328,9 @@ public final class NotificationPanelViewController implements Dumpable { mKeyguardBottomArea.init( mKeyguardBottomAreaViewModel, mFalsingManager, - mLockIconViewController + mLockIconViewController, + stringResourceId -> + mKeyguardIndicationController.showTransientIndication(stringResourceId) ); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/LaunchAnimationParameters.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/LaunchAnimationParameters.kt index 42edb309d577..c22dbf615190 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/LaunchAnimationParameters.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/LaunchAnimationParameters.kt @@ -27,8 +27,10 @@ class LaunchAnimationParameters( /** * The top position of the notification at the start of the animation. This is needed in order * to keep the notification at its place when launching a notification that is clipped rounded. + * This value is in absolute screen coordinates. */ - var startNotificationTop = 0f + var startNotificationTop = 0 + var notificationParentTop = 0 var startClipTopAmount = 0 var parentStartClipTopAmount = 0 var progress = 0f diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt index 0d35fdce953e..798bbe8aff7a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt @@ -92,11 +92,12 @@ class NotificationLaunchAnimatorController( ) params.startTranslationZ = notification.translationZ - params.startNotificationTop = notification.translationY + params.startNotificationTop = location[1] + params.notificationParentTop = notificationListContainer + .getViewParentForNotification(notificationEntry).locationOnScreen[1] params.startRoundedTopClipping = roundedTopClipping params.startClipTopAmount = notification.clipTopAmount if (notification.isChildInGroup) { - params.startNotificationTop += notification.notificationParent.translationY val locationOnScreen = notification.notificationParent.locationOnScreen[1] val parentRoundedClip = (clipStartLocation - locationOnScreen).coerceAtLeast(0) params.parentStartRoundedTopClipping = parentRoundedClip diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java index c7c1634ea105..a487af1998fc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java @@ -2223,6 +2223,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView if (mNotificationParent != null) { mNotificationParent.setClipTopAmount(0); } + setTranslationX(0); return; } @@ -2241,6 +2242,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView setTranslationZ(translationZ); float extraWidthForClipping = params.getWidth() - getWidth(); setExtraWidthForClipping(extraWidthForClipping); + int top; if (params.getStartRoundedTopClipping() > 0) { // If we were clipping initially, let's interpolate from the start position to the @@ -2248,20 +2250,22 @@ public class ExpandableNotificationRow extends ActivatableNotificationView float expandProgress = Interpolators.FAST_OUT_SLOW_IN.getInterpolation( params.getProgress(0, NotificationLaunchAnimatorController.ANIMATION_DURATION_TOP_ROUNDING)); - float startTop = params.getStartNotificationTop(); - top = (int) Math.min(MathUtils.lerp(startTop, - params.getTop(), expandProgress), + int startTop = params.getStartNotificationTop(); + top = (int) Math.min(MathUtils.lerp(startTop, params.getTop(), expandProgress), startTop); } else { top = params.getTop(); } int actualHeight = params.getBottom() - top; setActualHeight(actualHeight); + + int notificationStackTop = params.getNotificationParentTop(); + top -= notificationStackTop; int startClipTopAmount = params.getStartClipTopAmount(); int clipTopAmount = (int) MathUtils.lerp(startClipTopAmount, 0, params.getProgress()); if (mNotificationParent != null) { - float parentY = mNotificationParent.getTranslationY(); - top -= parentY; + float parentTranslationY = mNotificationParent.getTranslationY(); + top -= parentTranslationY; mNotificationParent.setTranslationZ(translationZ); // When the expanding notification is below its parent, the parent must be clipped @@ -2270,15 +2274,14 @@ public class ExpandableNotificationRow extends ActivatableNotificationView // pixels to show the expanding notification, while still taking the decreasing // notification clipTopAmount into consideration, so 'top + clipTopAmount'. int parentStartClipTopAmount = params.getParentStartClipTopAmount(); - int parentClipTopAmount = Math.min(parentStartClipTopAmount, - top + clipTopAmount); + int parentClipTopAmount = Math.min(parentStartClipTopAmount, top + clipTopAmount); mNotificationParent.setClipTopAmount(parentClipTopAmount); mNotificationParent.setExtraWidthForClipping(extraWidthForClipping); - float clipBottom = Math.max(params.getBottom(), - parentY + mNotificationParent.getActualHeight() + float clipBottom = Math.max(params.getBottom() - notificationStackTop, + parentTranslationY + mNotificationParent.getActualHeight() - mNotificationParent.getClipBottomAmount()); - float clipTop = Math.min(params.getTop(), parentY); + float clipTop = Math.min(params.getTop() - notificationStackTop, parentTranslationY); int minimumHeightForClipping = (int) (clipBottom - clipTop); mNotificationParent.setMinimumHeightForClipping(minimumHeightForClipping); } else if (startClipTopAmount != 0) { @@ -2286,6 +2289,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } setTranslationY(top); + float absoluteCenterX = getLocationOnScreen()[0] + getWidth() / 2f - getTranslationX(); + setTranslationX(params.getCenterX() - absoluteCenterX); + final float maxRadius = getMaxRadius(); mTopRoundnessDuringLaunchAnimation = params.getTopCornerRadius() / maxRadius; mBottomRoundnessDuringLaunchAnimation = params.getBottomCornerRadius() / maxRadius; 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 21e2bd877bae..d22bfe8b9e3c 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 @@ -5772,14 +5772,20 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable || mExpandingNotificationRow == null) { return; } - int left = Math.min(mLaunchAnimationParams.getLeft(), mRoundedRectClippingLeft); - int right = Math.max(mLaunchAnimationParams.getRight(), mRoundedRectClippingRight); - int bottom = Math.max(mLaunchAnimationParams.getBottom(), mRoundedRectClippingBottom); + int[] absoluteCoords = new int[2]; + getLocationOnScreen(absoluteCoords); + + int left = Math.min(mLaunchAnimationParams.getLeft() - absoluteCoords[0], + mRoundedRectClippingLeft); + int right = Math.max(mLaunchAnimationParams.getRight() - absoluteCoords[0], + mRoundedRectClippingRight); + int bottom = Math.max(mLaunchAnimationParams.getBottom() - absoluteCoords[1], + mRoundedRectClippingBottom); float expandProgress = Interpolators.FAST_OUT_SLOW_IN.getInterpolation( mLaunchAnimationParams.getProgress(0, NotificationLaunchAnimatorController.ANIMATION_DURATION_TOP_ROUNDING)); int top = (int) Math.min(MathUtils.lerp(mRoundedRectClippingTop, - mLaunchAnimationParams.getTop(), expandProgress), + mLaunchAnimationParams.getTop() - absoluteCoords[1], expandProgress), mRoundedRectClippingTop); float topRadius = mLaunchAnimationParams.getTopCornerRadius(); float bottomRadius = mLaunchAnimationParams.getBottomCornerRadius(); 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 aff7b4c6c515..b6cf9482f00d 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 @@ -871,8 +871,7 @@ public class StackScrollAlgorithm { } for (int i = childCount - 1; i >= 0; i--) { - childrenOnTop = updateChildZValue(i, childrenOnTop, - algorithmState, ambientState, i == topHunIndex); + updateChildZValue(i, algorithmState, ambientState, i == topHunIndex); } } @@ -882,15 +881,11 @@ public class StackScrollAlgorithm { * * @param isTopHun Whether the child is a top HUN. A top HUN means a HUN that shows on the * vertically top of screen. Top HUNs should have drop shadows - * @param childrenOnTop It is greater than 0 when there's an existing HUN that is elevated - * @return childrenOnTop The decimal part represents the fraction of the elevated HUN's height - * that overlaps with QQS Panel. The integer part represents the count of - * previous HUNs whose Z positions are greater than 0. */ - protected float updateChildZValue(int i, float childrenOnTop, - StackScrollAlgorithmState algorithmState, - AmbientState ambientState, - boolean isTopHun) { + protected void updateChildZValue(int i, + StackScrollAlgorithmState algorithmState, + AmbientState ambientState, + boolean isTopHun) { ExpandableView child = algorithmState.visibleChildren.get(i); ExpandableViewState childViewState = child.getViewState(); float baseZ = ambientState.getBaseZHeight(); @@ -904,22 +899,16 @@ public class StackScrollAlgorithm { // Handles HUN shadow when Shade is opened, and AmbientState.mScrollY > 0 // Calculate the HUN's z-value based on its overlapping fraction with QQS Panel. // When scrolling down shade to make HUN back to in-position in Notification Panel, - // The over-lapping fraction goes to 0, and shadows hides gradually. - if (childrenOnTop != 0.0f) { - // To elevate the later HUN over previous HUN - childrenOnTop++; - } else { - float overlap = ambientState.getTopPadding() - + ambientState.getStackTranslation() - childViewState.getYTranslation(); - // To prevent over-shadow during HUN entry - childrenOnTop += Math.min( - 1.0f, - overlap / childViewState.height - ); - MathUtils.saturate(childrenOnTop); + // the overlapFraction goes to 0, and the pinned HUN's shadows hides gradually. + float overlap = ambientState.getTopPadding() + + ambientState.getStackTranslation() - childViewState.getYTranslation(); + + if (childViewState.height > 0) { // To avoid 0/0 problems + // To prevent over-shadow + float overlapFraction = MathUtils.saturate(overlap / childViewState.height); + childViewState.setZTranslation(baseZ + + overlapFraction * mPinnedZTranslationExtra); } - childViewState.setZTranslation(baseZ - + childrenOnTop * mPinnedZTranslationExtra); } else if (isTopHun) { // In case this is a new view that has never been measured before, we don't want to // elevate if we are currently expanded more than the notification @@ -947,15 +936,14 @@ public class StackScrollAlgorithm { } // Handles HUN shadow when shade is closed. - // While HUN is showing and Shade is closed: headerVisibleAmount stays 0, shadow stays. + // While shade is closed, and during HUN's entry: headerVisibleAmount stays 0, shadow stays. + // While shade is closed, and HUN is showing: headerVisibleAmount stays 0, shadow stays. // During HUN-to-Shade (eg. dragging down HUN to open Shade): headerVisibleAmount goes // gradually from 0 to 1, shadow hides gradually. // Header visibility is a deprecated concept, we are using headerVisibleAmount only because // this value nicely goes from 0 to 1 during the HUN-to-Shade process. - childViewState.setZTranslation(childViewState.getZTranslation() + (1.0f - child.getHeaderVisibleAmount()) * mPinnedZTranslationExtra); - return childrenOnTop; } public void setIsExpanded(boolean isExpanded) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java index 31cdb0549d45..005cd1bff90c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.phone; +import static android.app.StatusBarManager.DISABLE_HOME; import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN; import static android.app.StatusBarManager.WINDOW_STATE_SHOWING; import static android.app.StatusBarManager.WindowVisibleState; @@ -70,6 +71,7 @@ import android.graphics.Point; import android.hardware.devicestate.DeviceStateManager; import android.metrics.LogMaker; import android.net.Uri; +import android.os.Binder; import android.os.Bundle; import android.os.Handler; import android.os.Looper; @@ -1047,8 +1049,21 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { // set the initial view visibility int disabledFlags1 = result.mDisabledFlags1; int disabledFlags2 = result.mDisabledFlags2; - mInitController.addPostInitTask( - () -> setUpDisableFlags(disabledFlags1, disabledFlags2)); + mInitController.addPostInitTask(() -> { + setUpDisableFlags(disabledFlags1, disabledFlags2); + try { + // NOTE(b/262059863): Force-update the disable flags after applying the flags + // returned from registerStatusBar(). The result's disabled flags may be stale + // if StatusBarManager's disabled flags are updated between registering the bar and + // this handling this post-init task. We force an update in this case, and use a new + // token to not conflict with any other disabled flags already requested by SysUI + Binder token = new Binder(); + mBarService.disable(DISABLE_HOME, token, mContext.getPackageName()); + mBarService.disable(0, token, mContext.getPackageName()); + } catch (RemoteException ex) { + ex.rethrowFromSystemServer(); + } + }); mFalsingManager.addFalsingBeliefListener(mFalsingBeliefListener); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.kt index 78b28d203629..2ce116394236 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.kt @@ -23,7 +23,7 @@ import android.view.ViewGroup import android.view.ViewPropertyAnimator import android.view.WindowInsets import android.widget.FrameLayout -import com.android.keyguard.KeyguardUpdateMonitor +import androidx.annotation.StringRes import com.android.keyguard.LockIconViewController import com.android.systemui.R import com.android.systemui.keyguard.ui.binder.KeyguardBottomAreaViewBinder @@ -51,21 +51,29 @@ constructor( defStyleRes, ) { + interface MessageDisplayer { + fun display(@StringRes stringResourceId: Int) + } + private var ambientIndicationArea: View? = null private lateinit var binding: KeyguardBottomAreaViewBinder.Binding - private lateinit var lockIconViewController: LockIconViewController + private var lockIconViewController: LockIconViewController? = null /** Initializes the view. */ fun init( viewModel: KeyguardBottomAreaViewModel, - falsingManager: FalsingManager, - lockIconViewController: LockIconViewController, + falsingManager: FalsingManager? = null, + lockIconViewController: LockIconViewController? = null, + messageDisplayer: MessageDisplayer? = null, ) { - binding = bind( + binding = + bind( this, viewModel, falsingManager, - ) + ) { + messageDisplayer?.display(it) + } this.lockIconViewController = lockIconViewController } @@ -129,21 +137,21 @@ constructor( findViewById<View>(R.id.ambient_indication_container)?.let { val (ambientLeft, ambientTop) = it.locationOnScreen if (binding.shouldConstrainToTopOfLockIcon()) { - //make top of ambient indication view the bottom of the lock icon + // make top of ambient indication view the bottom of the lock icon it.layout( - ambientLeft, - lockIconViewController.bottom.toInt(), - right - ambientLeft, - ambientTop + it.measuredHeight + ambientLeft, + lockIconViewController?.bottom?.toInt() ?: 0, + right - ambientLeft, + ambientTop + it.measuredHeight ) } else { - //make bottom of ambient indication view the top of the lock icon - val lockLocationTop = lockIconViewController.top + // make bottom of ambient indication view the top of the lock icon + val lockLocationTop = lockIconViewController?.top ?: 0 it.layout( - ambientLeft, - lockLocationTop.toInt() - it.measuredHeight, - right - ambientLeft, - lockLocationTop.toInt() + ambientLeft, + lockLocationTop.toInt() - it.measuredHeight, + right - ambientLeft, + lockLocationTop.toInt() ) } } diff --git a/packages/SystemUI/src/com/android/systemui/stylus/OWNERS b/packages/SystemUI/src/com/android/systemui/stylus/OWNERS new file mode 100644 index 000000000000..7ccb316dbca5 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/stylus/OWNERS @@ -0,0 +1,8 @@ +# Bug component: 1254381 +azappone@google.com +achalke@google.com +juliacr@google.com +madym@google.com +mgalhardo@google.com +petrcermak@google.com +vanjan@google.com
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerStartable.kt b/packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerStartable.kt new file mode 100644 index 000000000000..11233dda165c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerStartable.kt @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.stylus + +import android.hardware.BatteryState +import android.hardware.input.InputManager +import android.util.Log +import android.view.InputDevice +import com.android.systemui.CoreStartable +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.flags.FeatureFlags +import com.android.systemui.flags.Flags +import java.util.concurrent.Executor +import javax.inject.Inject + +/** + * A [CoreStartable] that listens to USI stylus battery events, to manage the [StylusUsiPowerUI] + * notification controller. + */ +@SysUISingleton +class StylusUsiPowerStartable +@Inject +constructor( + private val stylusManager: StylusManager, + private val inputManager: InputManager, + private val stylusUsiPowerUi: StylusUsiPowerUI, + private val featureFlags: FeatureFlags, + @Background private val executor: Executor, +) : CoreStartable, StylusManager.StylusCallback, InputManager.InputDeviceBatteryListener { + + override fun onStylusAdded(deviceId: Int) { + val device = inputManager.getInputDevice(deviceId) ?: return + + if (!device.isExternal) { + registerBatteryListener(deviceId) + } + } + + override fun onStylusBluetoothConnected(deviceId: Int, btAddress: String) { + stylusUsiPowerUi.refresh() + } + + override fun onStylusBluetoothDisconnected(deviceId: Int, btAddress: String) { + stylusUsiPowerUi.refresh() + } + + override fun onStylusRemoved(deviceId: Int) { + val device = inputManager.getInputDevice(deviceId) ?: return + + if (!device.isExternal) { + unregisterBatteryListener(deviceId) + } + } + + override fun onBatteryStateChanged( + deviceId: Int, + eventTimeMillis: Long, + batteryState: BatteryState + ) { + if (batteryState.isPresent) { + stylusUsiPowerUi.updateBatteryState(batteryState) + } + } + + private fun registerBatteryListener(deviceId: Int) { + try { + inputManager.addInputDeviceBatteryListener(deviceId, executor, this) + } catch (e: SecurityException) { + Log.e(TAG, "$e: Failed to register battery listener for $deviceId.") + } + } + + private fun unregisterBatteryListener(deviceId: Int) { + try { + inputManager.removeInputDeviceBatteryListener(deviceId, this) + } catch (e: SecurityException) { + Log.e(TAG, "$e: Failed to unregister battery listener for $deviceId.") + } + } + + override fun start() { + if (!featureFlags.isEnabled(Flags.ENABLE_USI_BATTERY_NOTIFICATIONS)) return + addBatteryListenerForInternalStyluses() + + stylusManager.registerCallback(this) + stylusManager.startListener() + } + + private fun addBatteryListenerForInternalStyluses() { + // For most devices, an active stylus is represented by an internal InputDevice. + // This InputDevice will be present in InputManager before CoreStartables run, + // and will not be removed. In many cases, it reports the battery level of the stylus. + inputManager.inputDeviceIds + .asSequence() + .mapNotNull { inputManager.getInputDevice(it) } + .filter { it.supportsSource(InputDevice.SOURCE_STYLUS) } + .forEach { onStylusAdded(it.id) } + } + + companion object { + private val TAG = StylusUsiPowerStartable::class.simpleName.orEmpty() + } +} diff --git a/packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerUI.kt b/packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerUI.kt new file mode 100644 index 000000000000..70a5b366263e --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerUI.kt @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.stylus + +import android.Manifest +import android.app.PendingIntent +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.hardware.BatteryState +import android.hardware.input.InputManager +import android.os.Handler +import android.os.UserHandle +import android.view.InputDevice +import androidx.core.app.NotificationCompat +import androidx.core.app.NotificationManagerCompat +import com.android.systemui.R +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.util.NotificationChannels +import java.text.NumberFormat +import javax.inject.Inject + +/** + * UI controller for the notification that shows when a USI stylus battery is low. The + * [StylusUsiPowerStartable], which listens to battery events, uses this controller. + */ +@SysUISingleton +class StylusUsiPowerUI +@Inject +constructor( + private val context: Context, + private val notificationManager: NotificationManagerCompat, + private val inputManager: InputManager, + @Background private val handler: Handler, +) { + + // These values must only be accessed on the handler. + private var batteryCapacity = 1.0f + private var suppressed = false + + fun init() { + val filter = + IntentFilter().also { + it.addAction(ACTION_DISMISSED_LOW_BATTERY) + it.addAction(ACTION_CLICKED_LOW_BATTERY) + } + + context.registerReceiverAsUser( + receiver, + UserHandle.ALL, + filter, + Manifest.permission.DEVICE_POWER, + handler, + Context.RECEIVER_NOT_EXPORTED, + ) + } + + fun refresh() { + handler.post refreshNotification@{ + if (!suppressed && !hasConnectedBluetoothStylus() && isBatteryBelowThreshold()) { + showOrUpdateNotification() + return@refreshNotification + } + + if (!isBatteryBelowThreshold()) { + // Reset suppression when stylus battery is recharged, so that the next time + // it reaches a low battery, the notification will show again. + suppressed = false + } + hideNotification() + } + } + + fun updateBatteryState(batteryState: BatteryState) { + handler.post updateBattery@{ + if (batteryState.capacity == batteryCapacity) return@updateBattery + + batteryCapacity = batteryState.capacity + refresh() + } + } + + /** + * Suppression happens when the notification is dismissed by the user. This is to prevent + * further battery events with capacities below the threshold from reopening the suppressed + * notification. + * + * Suppression can only be removed when the battery has been recharged - thus restarting the + * notification cycle (i.e. next low battery event, notification should show). + */ + fun updateSuppression(suppress: Boolean) { + handler.post updateSuppressed@{ + if (suppressed == suppress) return@updateSuppressed + + suppressed = suppress + refresh() + } + } + + private fun hideNotification() { + notificationManager.cancel(USI_NOTIFICATION_ID) + } + + private fun showOrUpdateNotification() { + val notification = + NotificationCompat.Builder(context, NotificationChannels.BATTERY) + .setSmallIcon(R.drawable.ic_power_low) + .setDeleteIntent(getPendingBroadcast(ACTION_DISMISSED_LOW_BATTERY)) + .setContentIntent(getPendingBroadcast(ACTION_CLICKED_LOW_BATTERY)) + .setContentTitle(context.getString(R.string.stylus_battery_low)) + .setContentText( + context.getString( + R.string.battery_low_percent_format, + NumberFormat.getPercentInstance().format(batteryCapacity) + ) + ) + .setPriority(NotificationCompat.PRIORITY_DEFAULT) + .setLocalOnly(true) + .setAutoCancel(true) + .build() + + notificationManager.notify(USI_NOTIFICATION_ID, notification) + } + + private fun isBatteryBelowThreshold(): Boolean { + return batteryCapacity <= LOW_BATTERY_THRESHOLD + } + + private fun hasConnectedBluetoothStylus(): Boolean { + // TODO(b/257936830): get bt address once input api available + return inputManager.inputDeviceIds.any { deviceId -> + inputManager.getInputDevice(deviceId).supportsSource(InputDevice.SOURCE_STYLUS) + } + } + + private fun getPendingBroadcast(action: String): PendingIntent? { + return PendingIntent.getBroadcastAsUser( + context, + 0, + Intent(action), + PendingIntent.FLAG_IMMUTABLE, + UserHandle.CURRENT + ) + } + + private val receiver: BroadcastReceiver = + object : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + when (intent.action) { + ACTION_DISMISSED_LOW_BATTERY -> updateSuppression(true) + ACTION_CLICKED_LOW_BATTERY -> { + updateSuppression(true) + // TODO(b/261584943): open USI device details page + } + } + } + } + + companion object { + // Low battery threshold matches CrOS, see: + // https://source.chromium.org/chromium/chromium/src/+/main:ash/system/power/peripheral_battery_notifier.cc;l=41 + private const val LOW_BATTERY_THRESHOLD = 0.16f + + private val USI_NOTIFICATION_ID = R.string.stylus_battery_low + + private const val ACTION_DISMISSED_LOW_BATTERY = "StylusUsiPowerUI.dismiss" + private const val ACTION_CLICKED_LOW_BATTERY = "StylusUsiPowerUI.click" + } +} diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt index ea4020861a09..db7315f311ac 100644 --- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt +++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt @@ -34,6 +34,7 @@ import com.android.systemui.CoreStartable import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.util.concurrency.DelayableExecutor +import com.android.systemui.util.time.SystemClock import com.android.systemui.util.wakelock.WakeLock /** @@ -44,8 +45,24 @@ import com.android.systemui.util.wakelock.WakeLock * * The generic type T is expected to contain all the information necessary for the subclasses to * display the view in a certain state, since they receive <T> in [updateView]. + * + * Some information about display ordering: + * + * [ViewPriority] defines different priorities for the incoming views. The incoming view will be + * displayed so long as its priority is equal to or greater than the currently displayed view. + * (Concretely, this means that a [ViewPriority.NORMAL] won't be displayed if a + * [ViewPriority.CRITICAL] is currently displayed. But otherwise, the incoming view will get + * displayed and kick out the old view). + * + * Once the currently displayed view times out, we *may* display a previously requested view if it + * still has enough time left before its own timeout. The same priority ordering applies. + * + * Note: [TemporaryViewInfo.id] is the identifier that we use to determine if a call to + * [displayView] will just update the current view with new information, or display a completely new + * view. This means that you *cannot* change the [TemporaryViewInfo.priority] or + * [TemporaryViewInfo.windowTitle] while using the same ID. */ -abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : TemporaryViewLogger>( +abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : TemporaryViewLogger<T>>( internal val context: Context, internal val logger: U, internal val windowManager: WindowManager, @@ -55,6 +72,7 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora private val powerManager: PowerManager, @LayoutRes private val viewLayoutRes: Int, private val wakeLockBuilder: WakeLock.Builder, + private val systemClock: SystemClock, ) : CoreStartable { /** * Window layout params that will be used as a starting point for the [windowLayoutParams] of @@ -78,27 +96,18 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora */ internal abstract val windowLayoutParams: WindowManager.LayoutParams - /** A container for all the display-related objects. Null if the view is not being displayed. */ - private var displayInfo: DisplayInfo? = null - - /** A [Runnable] that, when run, will cancel the pending timeout of the view. */ - private var cancelViewTimeout: Runnable? = null - /** - * A wakelock that is acquired when view is displayed and screen off, - * then released when view is removed. + * A list of the currently active views, ordered from highest priority in the beginning to + * lowest priority at the end. + * + * Whenever the current view disappears, the next-priority view will be displayed if it's still + * valid. */ - private var wakeLock: WakeLock? = null - - /** A string that keeps track of wakelock reason once it is acquired till it gets released */ - private var wakeReasonAcquired: String? = null + internal val activeViews: MutableList<DisplayInfo> = mutableListOf() - /** - * A stack of pairs of device id and temporary view info. This is used when there may be - * multiple devices in range, and we want to always display the chip for the most recently - * active device. - */ - internal val activeViews: ArrayDeque<Pair<String, T>> = ArrayDeque() + private fun getCurrentDisplayInfo(): DisplayInfo? { + return activeViews.getOrNull(0) + } /** * Displays the view with the provided [newInfo]. @@ -107,94 +116,139 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora * display the correct information in the view. * @param onViewTimeout a runnable that runs after the view timeout. */ + @Synchronized fun displayView(newInfo: T, onViewTimeout: Runnable? = null) { - val currentDisplayInfo = displayInfo - - // Update our list of active devices by removing it if necessary, then adding back at the - // front of the list - val id = newInfo.id - val position = findAndRemoveFromActiveViewsList(id) - activeViews.addFirst(Pair(id, newInfo)) - - if (currentDisplayInfo != null && - currentDisplayInfo.info.windowTitle == newInfo.windowTitle) { - // We're already displaying information in the correctly-titled window, so we just need - // to update the view. - currentDisplayInfo.info = newInfo - updateView(currentDisplayInfo.info, currentDisplayInfo.view) - } else { - if (currentDisplayInfo != null) { - // We're already displaying information but that information is under a different - // window title. So, we need to remove the old window with the old title and add a - // new window with the new title. - removeView( - id, - removalReason = "New info has new window title: ${newInfo.windowTitle}" - ) - } - - // At this point, we're guaranteed to no longer be displaying a view. - // So, set up all our callbacks and inflate the view. - configurationController.addCallback(displayScaleListener) - - wakeLock = if (!powerManager.isScreenOn) { - // If the screen is off, fully wake it so the user can see the view. - wakeLockBuilder - .setTag(newInfo.windowTitle) - .setLevelsAndFlags( - PowerManager.FULL_WAKE_LOCK or - PowerManager.ACQUIRE_CAUSES_WAKEUP - ) - .build() - } else { - // Per b/239426653, we want the view to show over the dream state. - // If the screen is on, using screen bright level will leave screen on the dream - // state but ensure the screen will not go off before wake lock is released. - wakeLockBuilder - .setTag(newInfo.windowTitle) - .setLevelsAndFlags(PowerManager.SCREEN_BRIGHT_WAKE_LOCK) - .build() - } - wakeLock?.acquire(newInfo.wakeReason) - wakeReasonAcquired = newInfo.wakeReason - logger.logViewAddition(id, newInfo.windowTitle) - inflateAndUpdateView(newInfo) - } - - // Cancel and re-set the view timeout each time we get a new state. val timeout = accessibilityManager.getRecommendedTimeoutMillis( newInfo.timeoutMs, // Not all views have controls so FLAG_CONTENT_CONTROLS might be superfluous, but // include it just to be safe. FLAG_CONTENT_ICONS or FLAG_CONTENT_TEXT or FLAG_CONTENT_CONTROLS - ) + ) + val timeExpirationMillis = systemClock.currentTimeMillis() + timeout + + val currentDisplayInfo = getCurrentDisplayInfo() + + // We're current displaying a chipbar with the same ID, we just need to update its info + if (currentDisplayInfo != null && currentDisplayInfo.info.id == newInfo.id) { + val view = checkNotNull(currentDisplayInfo.view) { + "First item in activeViews list must have a valid view" + } + logger.logViewUpdate(newInfo) + currentDisplayInfo.info = newInfo + currentDisplayInfo.timeExpirationMillis = timeExpirationMillis + updateTimeout(currentDisplayInfo, timeout, onViewTimeout) + updateView(newInfo, view) + return + } + + val newDisplayInfo = DisplayInfo( + info = newInfo, + onViewTimeout = onViewTimeout, + timeExpirationMillis = timeExpirationMillis, + // Null values will be updated to non-null if/when this view actually gets displayed + view = null, + wakeLock = null, + cancelViewTimeout = null, + ) + + // We're not displaying anything, so just render this new info + if (currentDisplayInfo == null) { + addCallbacks() + activeViews.add(newDisplayInfo) + showNewView(newDisplayInfo, timeout) + return + } + + // The currently displayed info takes higher priority than the new one. + // So, just store the new one in case the current one disappears. + if (currentDisplayInfo.info.priority > newInfo.priority) { + logger.logViewAdditionDelayed(newInfo) + // Remove any old information for this id (if it exists) and re-add it to the list in + // the right priority spot + removeFromActivesIfNeeded(newInfo.id) + var insertIndex = 0 + while (insertIndex < activeViews.size && + activeViews[insertIndex].info.priority > newInfo.priority) { + insertIndex++ + } + activeViews.add(insertIndex, newDisplayInfo) + return + } + + // Else: The newInfo should be displayed and the currentInfo should be hidden + hideView(currentDisplayInfo) + // Remove any old information for this id (if it exists) and put this info at the beginning + removeFromActivesIfNeeded(newDisplayInfo.info.id) + activeViews.add(0, newDisplayInfo) + showNewView(newDisplayInfo, timeout) + } + + private fun showNewView(newDisplayInfo: DisplayInfo, timeout: Int) { + logger.logViewAddition(newDisplayInfo.info) + createAndAcquireWakeLock(newDisplayInfo) + updateTimeout(newDisplayInfo, timeout, newDisplayInfo.onViewTimeout) + inflateAndUpdateView(newDisplayInfo) + } - // Only cancel timeout of the most recent view displayed, as it will be reset. - if (position == 0) { - cancelViewTimeout?.run() + private fun createAndAcquireWakeLock(displayInfo: DisplayInfo) { + // TODO(b/262009503): Migrate off of isScrenOn, since it's deprecated. + val newWakeLock = if (!powerManager.isScreenOn) { + // If the screen is off, fully wake it so the user can see the view. + wakeLockBuilder + .setTag(displayInfo.info.windowTitle) + .setLevelsAndFlags( + PowerManager.FULL_WAKE_LOCK or + PowerManager.ACQUIRE_CAUSES_WAKEUP + ) + .build() + } else { + // Per b/239426653, we want the view to show over the dream state. + // If the screen is on, using screen bright level will leave screen on the dream + // state but ensure the screen will not go off before wake lock is released. + wakeLockBuilder + .setTag(displayInfo.info.windowTitle) + .setLevelsAndFlags(PowerManager.SCREEN_BRIGHT_WAKE_LOCK) + .build() } - cancelViewTimeout = mainExecutor.executeDelayed( + displayInfo.wakeLock = newWakeLock + newWakeLock.acquire(displayInfo.info.wakeReason) + } + + /** + * Creates a runnable that will remove [displayInfo] in [timeout] ms from now. + * + * @param onViewTimeout an optional runnable that will be run if the view times out. + * @return a runnable that, when run, will *cancel* the view's timeout. + */ + private fun updateTimeout(displayInfo: DisplayInfo, timeout: Int, onViewTimeout: Runnable?) { + val cancelViewTimeout = mainExecutor.executeDelayed( { - removeView(id, REMOVAL_REASON_TIMEOUT) + removeView(displayInfo.info.id, REMOVAL_REASON_TIMEOUT) onViewTimeout?.run() }, timeout.toLong() ) + + displayInfo.onViewTimeout = onViewTimeout + // Cancel old view timeout and re-set it. + displayInfo.cancelViewTimeout?.run() + displayInfo.cancelViewTimeout = cancelViewTimeout } - /** Inflates a new view, updates it with [newInfo], and adds the view to the window. */ - private fun inflateAndUpdateView(newInfo: T) { + /** Inflates a new view, updates it with [DisplayInfo.info], and adds the view to the window. */ + private fun inflateAndUpdateView(displayInfo: DisplayInfo) { + val newInfo = displayInfo.info val newView = LayoutInflater .from(context) .inflate(viewLayoutRes, null) as ViewGroup - val newViewController = TouchableRegionViewController(newView, this::getTouchableRegion) - newViewController.init() + displayInfo.view = newView // We don't need to hold on to the view controller since we never set anything additional // on it -- it will be automatically cleaned up when the view is detached. - val newDisplayInfo = DisplayInfo(newView, newInfo) - displayInfo = newDisplayInfo - updateView(newDisplayInfo.info, newDisplayInfo.view) + val newViewController = TouchableRegionViewController(newView, this::getTouchableRegion) + newViewController.init() + + updateView(newInfo, newView) val paramsWithTitle = WindowManager.LayoutParams().also { it.copyFrom(windowLayoutParams) @@ -206,11 +260,15 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora } /** Removes then re-inflates the view. */ + @Synchronized private fun reinflateView() { - val currentViewInfo = displayInfo ?: return + val currentDisplayInfo = getCurrentDisplayInfo() ?: return - windowManager.removeView(currentViewInfo.view) - inflateAndUpdateView(currentViewInfo.info) + val view = checkNotNull(currentDisplayInfo.view) { + "First item in activeViews list must have a valid view" + } + windowManager.removeView(view) + inflateAndUpdateView(currentDisplayInfo) } private val displayScaleListener = object : ConfigurationController.ConfigurationListener { @@ -219,68 +277,109 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora } } + private fun addCallbacks() { + configurationController.addCallback(displayScaleListener) + } + + private fun removeCallbacks() { + configurationController.removeCallback(displayScaleListener) + } + /** - * Hides the view given its [id]. + * Completely removes the view for the given [id], both visually and from our internal store. * * @param id the id of the device responsible of displaying the temp view. * @param removalReason a short string describing why the view was removed (timeout, state * change, etc.) */ + @Synchronized fun removeView(id: String, removalReason: String) { - val currentDisplayInfo = displayInfo ?: return + logger.logViewRemoval(id, removalReason) - val removalPosition = findAndRemoveFromActiveViewsList(id) - if (removalPosition == null) { - logger.logViewRemovalIgnored(id, "view not found in the list") + val displayInfo = activeViews.firstOrNull { it.info.id == id } + if (displayInfo == null) { + logger.logViewRemovalIgnored(id, "View not found in list") return } - if (removalPosition != 0) { - logger.logViewRemovalIgnored(id, "most recent view is being displayed.") + + val currentlyDisplayedView = activeViews[0] + // Remove immediately (instead as part of the animation end runnable) so that if a new view + // event comes in while this view is animating out, we still display the new view + // appropriately. + activeViews.remove(displayInfo) + + // No need to time the view out since it's already gone + displayInfo.cancelViewTimeout?.run() + + if (displayInfo.view == null) { + logger.logViewRemovalIgnored(id, "No view to remove") return } - logger.logViewRemoval(id, removalReason) - val newViewToDisplay = if (activeViews.isEmpty()) { - null - } else { - activeViews[0].second + if (currentlyDisplayedView.info.id != id) { + logger.logViewRemovalIgnored(id, "View isn't the currently displayed view") + return } - val currentView = currentDisplayInfo.view - animateViewOut(currentView) { - windowManager.removeView(currentView) - wakeLock?.release(wakeReasonAcquired) - } + removeViewFromWindow(displayInfo) - configurationController.removeCallback(displayScaleListener) - // Re-set to null immediately (instead as part of the animation end runnable) so - // that if a new view event comes in while this view is animating out, we still display - // the new view appropriately. - displayInfo = null - // No need to time the view out since it's already gone - cancelViewTimeout?.run() + // Prune anything that's already timed out before determining if we should re-display a + // different chipbar. + removeTimedOutViews() + val newViewToDisplay = getCurrentDisplayInfo() if (newViewToDisplay != null) { - mainExecutor.executeDelayed({ displayView(newViewToDisplay)}, DISPLAY_VIEW_DELAY) + val timeout = newViewToDisplay.timeExpirationMillis - systemClock.currentTimeMillis() + // TODO(b/258019006): We may want to have a delay before showing the new view so + // that the UI translation looks a bit smoother. But, we expect this to happen + // rarely so it may not be worth the extra complexity. + showNewView(newViewToDisplay, timeout.toInt()) + } else { + removeCallbacks() } } /** - * Finds and removes the active view with the given [id] from the stack, or null if there is no - * active view with that ID - * - * @param id that temporary view belonged to. - * - * @return index of the view in the stack , otherwise null. + * Hides the view from the window, but keeps [displayInfo] around in [activeViews] in case it + * should be re-displayed later. */ - private fun findAndRemoveFromActiveViewsList(id: String): Int? { - for (i in 0 until activeViews.size) { - if (activeViews[i].first == id) { - activeViews.removeAt(i) - return i - } + private fun hideView(displayInfo: DisplayInfo) { + logger.logViewHidden(displayInfo.info) + removeViewFromWindow(displayInfo) + } + + private fun removeViewFromWindow(displayInfo: DisplayInfo) { + val view = displayInfo.view + if (view == null) { + logger.logViewRemovalIgnored(displayInfo.info.id, "View is null") + return + } + displayInfo.view = null // Need other places?? + animateViewOut(view) { + windowManager.removeView(view) + displayInfo.wakeLock?.release(displayInfo.info.wakeReason) + } + } + + @Synchronized + private fun removeTimedOutViews() { + val invalidViews = activeViews + .filter { it.timeExpirationMillis < + systemClock.currentTimeMillis() + MIN_REQUIRED_TIME_FOR_REDISPLAY } + + invalidViews.forEach { + activeViews.remove(it) + logger.logViewExpiration(it.info) + } + } + + @Synchronized + private fun removeFromActivesIfNeeded(id: String) { + val toRemove = activeViews.find { it.info.id == id } + toRemove?.let { + it.cancelViewTimeout?.run() + activeViews.remove(it) } - return null } /** @@ -311,17 +410,47 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora } /** A container for all the display-related state objects. */ - private inner class DisplayInfo( - /** The view currently being displayed. */ - val view: ViewGroup, - - /** The info currently being displayed. */ + inner class DisplayInfo( + /** + * The view currently being displayed. + * + * Null if this info isn't currently being displayed. + */ + var view: ViewGroup?, + + /** The info that should be displayed if/when this is the highest priority view. */ var info: T, + + /** + * The system time at which this display info should expire and never be displayed again. + */ + var timeExpirationMillis: Long, + + /** + * The wake lock currently held by this view. Must be released when the view disappears. + * + * Null if this info isn't currently being displayed. + */ + var wakeLock: WakeLock?, + + /** + * See [displayView]. + */ + var onViewTimeout: Runnable?, + + /** + * A runnable that, when run, will cancel this view's timeout. + * + * Null if this info isn't currently being displayed. + */ + var cancelViewTimeout: Runnable?, ) + + // TODO(b/258019006): Add a dump method that dumps the currently active views. } private const val REMOVAL_REASON_TIMEOUT = "TIMEOUT" -const val DISPLAY_VIEW_DELAY = 50L +private const val MIN_REQUIRED_TIME_FOR_REDISPLAY = 1000 private data class IconInfo( val iconName: String, diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewInfo.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewInfo.kt index df8396051dda..5596cf68b4bc 100644 --- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewInfo.kt +++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewInfo.kt @@ -42,6 +42,20 @@ abstract class TemporaryViewInfo { * The id of the temporary view. */ abstract val id: String + + /** The priority for this view. */ + abstract val priority: ViewPriority } const val DEFAULT_TIMEOUT_MILLIS = 10000 + +/** + * The priority of the view being displayed. + * + * Must be ordered from lowest priority to highest priority. (CRITICAL is currently the highest + * priority.) + */ +enum class ViewPriority { + NORMAL, + CRITICAL, +} diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewLogger.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewLogger.kt index 133a384e7e17..ec6965a83b5a 100644 --- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewLogger.kt @@ -20,20 +20,79 @@ import com.android.systemui.plugins.log.LogBuffer import com.android.systemui.plugins.log.LogLevel /** A logger for temporary view changes -- see [TemporaryViewDisplayController]. */ -open class TemporaryViewLogger( +open class TemporaryViewLogger<T : TemporaryViewInfo>( internal val buffer: LogBuffer, internal val tag: String, ) { - /** Logs that we added the view with the given [id] in a window titled [windowTitle]. */ - fun logViewAddition(id: String, windowTitle: String) { + fun logViewExpiration(info: T) { buffer.log( tag, LogLevel.DEBUG, { - str1 = windowTitle - str2 = id + str1 = info.id + str2 = info.windowTitle + str3 = info.priority.name + }, + { "View timeout has already expired; removing. id=$str1 window=$str2 priority=$str3" } + ) + } + + fun logViewUpdate(info: T) { + buffer.log( + tag, + LogLevel.DEBUG, + { + str1 = info.id + str2 = info.windowTitle + str3 = info.priority.name }, - { "View added. window=$str1 id=$str2" } + { "Existing view updated with new data. id=$str1 window=$str2 priority=$str3" } + ) + } + + fun logViewAdditionDelayed(info: T) { + buffer.log( + tag, + LogLevel.DEBUG, + { + str1 = info.id + str2 = info.windowTitle + str3 = info.priority.name + }, + { + "New view can't be displayed because higher priority view is currently " + + "displayed. New view id=$str1 window=$str2 priority=$str3" + } + ) + } + + /** Logs that we added the view with the given information. */ + fun logViewAddition(info: T) { + buffer.log( + tag, + LogLevel.DEBUG, + { + str1 = info.id + str2 = info.windowTitle + str3 = info.priority.name + }, + { "View added. id=$str1 window=$str2 priority=$str3" } + ) + } + + fun logViewHidden(info: T) { + buffer.log( + tag, + LogLevel.DEBUG, + { + str1 = info.id + str2 = info.windowTitle + str3 = info.priority.name + }, + { + "View hidden in favor of newer view. " + + "Hidden view id=$str1 window=$str2 priority=$str3" + } ) } diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt index 4d91e35856dc..14ba63a2738f 100644 --- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt @@ -43,6 +43,7 @@ import com.android.systemui.statusbar.VibratorHelper import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.temporarydisplay.TemporaryViewDisplayController import com.android.systemui.util.concurrency.DelayableExecutor +import com.android.systemui.util.time.SystemClock import com.android.systemui.util.view.ViewUtil import com.android.systemui.util.wakelock.WakeLock import javax.inject.Inject @@ -77,6 +78,7 @@ open class ChipbarCoordinator @Inject constructor( private val viewUtil: ViewUtil, private val vibratorHelper: VibratorHelper, wakeLockBuilder: WakeLock.Builder, + systemClock: SystemClock, ) : TemporaryViewDisplayController<ChipbarInfo, ChipbarLogger>( context, logger, @@ -87,6 +89,7 @@ open class ChipbarCoordinator @Inject constructor( powerManager, R.layout.chipbar, wakeLockBuilder, + systemClock, ) { private lateinit var parent: ChipbarRootView diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarInfo.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarInfo.kt index a3eef8032b3b..dd4bd26e3bcd 100644 --- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarInfo.kt +++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarInfo.kt @@ -22,6 +22,7 @@ import androidx.annotation.AttrRes import com.android.systemui.common.shared.model.Text import com.android.systemui.common.shared.model.TintedIcon import com.android.systemui.temporarydisplay.TemporaryViewInfo +import com.android.systemui.temporarydisplay.ViewPriority /** * A container for all the state needed to display a chipbar via [ChipbarCoordinator]. @@ -42,6 +43,7 @@ data class ChipbarInfo( override val wakeReason: String, override val timeoutMs: Int, override val id: String, + override val priority: ViewPriority, ) : TemporaryViewInfo() { companion object { @AttrRes const val DEFAULT_ICON_TINT_ATTR = android.R.attr.textColorPrimary diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarLogger.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarLogger.kt index e477cd68673a..fcfbe0aeedf6 100644 --- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarLogger.kt @@ -29,7 +29,7 @@ class ChipbarLogger @Inject constructor( @ChipbarLog buffer: LogBuffer, -) : TemporaryViewLogger(buffer, "ChipbarLog") { +) : TemporaryViewLogger<ChipbarInfo>(buffer, "ChipbarLog") { /** * Logs that the chipbar was updated to display in a window named [windowTitle], with [text] and * [endItemDesc]. diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt index 99406ed44606..8e689cf8f17e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt @@ -23,11 +23,11 @@ import org.mockito.MockitoAnnotations class DreamOverlayAnimationsControllerTest : SysuiTestCase() { companion object { + private const val DREAM_BLUR_RADIUS = 50 private const val DREAM_IN_BLUR_ANIMATION_DURATION = 1L - private const val DREAM_IN_BLUR_ANIMATION_DELAY = 2L private const val DREAM_IN_COMPLICATIONS_ANIMATION_DURATION = 3L - private const val DREAM_IN_TOP_COMPLICATIONS_ANIMATION_DELAY = 4L - private const val DREAM_IN_BOTTOM_COMPLICATIONS_ANIMATION_DELAY = 5L + private const val DREAM_IN_TRANSLATION_Y_DISTANCE = 6 + private const val DREAM_IN_TRANSLATION_Y_DURATION = 7L private const val DREAM_OUT_TRANSLATION_Y_DISTANCE = 6 private const val DREAM_OUT_TRANSLATION_Y_DURATION = 7L private const val DREAM_OUT_TRANSLATION_Y_DELAY_BOTTOM = 8L @@ -54,11 +54,11 @@ class DreamOverlayAnimationsControllerTest : SysuiTestCase() { hostViewController, statusBarViewController, stateController, + DREAM_BLUR_RADIUS, DREAM_IN_BLUR_ANIMATION_DURATION, - DREAM_IN_BLUR_ANIMATION_DELAY, DREAM_IN_COMPLICATIONS_ANIMATION_DURATION, - DREAM_IN_TOP_COMPLICATIONS_ANIMATION_DELAY, - DREAM_IN_BOTTOM_COMPLICATIONS_ANIMATION_DELAY, + DREAM_IN_TRANSLATION_Y_DISTANCE, + DREAM_IN_TRANSLATION_Y_DURATION, DREAM_OUT_TRANSLATION_Y_DISTANCE, DREAM_OUT_TRANSLATION_Y_DURATION, DREAM_OUT_TRANSLATION_Y_DELAY_BOTTOM, diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationLayoutParamsTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationLayoutParamsTest.java index fdb4cc4480da..e414942afb56 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationLayoutParamsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationLayoutParamsTest.java @@ -17,6 +17,10 @@ package com.android.systemui.dreams.complication; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + import android.testing.AndroidTestingRunner; import androidx.test.filters.SmallTest; @@ -29,6 +33,7 @@ import org.junit.runner.RunWith; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; +import java.util.function.Consumer; @SmallTest @RunWith(AndroidTestingRunner.class) @@ -197,4 +202,19 @@ public class ComplicationLayoutParamsTest extends SysuiTestCase { assertThat(paramsWithConstraint.constraintSpecified()).isTrue(); assertThat(paramsWithConstraint.getConstraint()).isEqualTo(constraint); } + + @Test + public void testIteratePositions() { + final int positions = ComplicationLayoutParams.POSITION_TOP + | ComplicationLayoutParams.POSITION_START + | ComplicationLayoutParams.POSITION_END; + final Consumer<Integer> consumer = mock(Consumer.class); + + ComplicationLayoutParams.iteratePositions(consumer, positions); + + verify(consumer).accept(ComplicationLayoutParams.POSITION_TOP); + verify(consumer).accept(ComplicationLayoutParams.POSITION_START); + verify(consumer).accept(ComplicationLayoutParams.POSITION_END); + verify(consumer, never()).accept(ComplicationLayoutParams.POSITION_BOTTOM); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardQuickAffordanceProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardQuickAffordanceProviderTest.kt index cef452b8ec22..09c8e6ac1268 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardQuickAffordanceProviderTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardQuickAffordanceProviderTest.kt @@ -20,7 +20,13 @@ package com.android.systemui.keyguard import android.content.ContentValues import android.content.pm.PackageManager import android.content.pm.ProviderInfo +import android.os.Bundle +import android.os.Handler +import android.os.IBinder import android.os.UserHandle +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper +import android.view.SurfaceControlViewHost import androidx.test.filters.SmallTest import com.android.internal.widget.LockPatternUtils import com.android.systemui.SystemUIAppComponentFactoryBase @@ -36,6 +42,9 @@ import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardQuickAffordanceInteractor +import com.android.systemui.keyguard.ui.preview.KeyguardPreviewRenderer +import com.android.systemui.keyguard.ui.preview.KeyguardPreviewRendererFactory +import com.android.systemui.keyguard.ui.preview.KeyguardRemotePreviewManager import com.android.systemui.plugins.ActivityStarter import com.android.systemui.settings.UserFileManager import com.android.systemui.settings.UserTracker @@ -43,40 +52,53 @@ import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordance import com.android.systemui.shared.quickaffordance.data.content.KeyguardQuickAffordanceProviderContract as Contract import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.FakeSharedPreferences +import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import com.android.systemui.util.settings.FakeSettings import com.google.common.truth.Truth.assertThat -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.junit.runners.JUnit4 import org.mockito.ArgumentMatchers.anyInt import org.mockito.ArgumentMatchers.anyString import org.mockito.Mock import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations +@OptIn(ExperimentalCoroutinesApi::class) @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidTestingRunner::class) +@TestableLooper.RunWithLooper(setAsMainLooper = true) class KeyguardQuickAffordanceProviderTest : SysuiTestCase() { @Mock private lateinit var lockPatternUtils: LockPatternUtils @Mock private lateinit var keyguardStateController: KeyguardStateController @Mock private lateinit var userTracker: UserTracker @Mock private lateinit var activityStarter: ActivityStarter + @Mock private lateinit var previewRendererFactory: KeyguardPreviewRendererFactory + @Mock private lateinit var previewRenderer: KeyguardPreviewRenderer + @Mock private lateinit var backgroundHandler: Handler + @Mock private lateinit var previewSurfacePackage: SurfaceControlViewHost.SurfacePackage private lateinit var underTest: KeyguardQuickAffordanceProvider + private lateinit var testScope: TestScope + @Before fun setUp() { MockitoAnnotations.initMocks(this) + whenever(previewRenderer.surfacePackage).thenReturn(previewSurfacePackage) + whenever(previewRendererFactory.create(any())).thenReturn(previewRenderer) + whenever(backgroundHandler.looper).thenReturn(TestableLooper.get(this).looper) underTest = KeyguardQuickAffordanceProvider() - val scope = CoroutineScope(IMMEDIATE) + val testDispatcher = StandardTestDispatcher() + testScope = TestScope(testDispatcher) val localUserSelectionManager = KeyguardQuickAffordanceLocalUserSelectionManager( context = context, @@ -96,7 +118,7 @@ class KeyguardQuickAffordanceProviderTest : SysuiTestCase() { ) val remoteUserSelectionManager = KeyguardQuickAffordanceRemoteUserSelectionManager( - scope = scope, + scope = testScope.backgroundScope, userTracker = userTracker, clientFactory = FakeKeyguardQuickAffordanceProviderClientFactory(userTracker), userHandle = UserHandle.SYSTEM, @@ -104,7 +126,7 @@ class KeyguardQuickAffordanceProviderTest : SysuiTestCase() { val quickAffordanceRepository = KeyguardQuickAffordanceRepository( appContext = context, - scope = scope, + scope = testScope.backgroundScope, localUserSelectionManager = localUserSelectionManager, remoteUserSelectionManager = remoteUserSelectionManager, userTracker = userTracker, @@ -123,8 +145,8 @@ class KeyguardQuickAffordanceProviderTest : SysuiTestCase() { ), legacySettingSyncer = KeyguardQuickAffordanceLegacySettingSyncer( - scope = scope, - backgroundDispatcher = IMMEDIATE, + scope = testScope.backgroundScope, + backgroundDispatcher = testDispatcher, secureSettings = FakeSettings(), selectionsManager = localUserSelectionManager, ), @@ -148,6 +170,12 @@ class KeyguardQuickAffordanceProviderTest : SysuiTestCase() { }, repository = { quickAffordanceRepository }, ) + underTest.previewManager = + KeyguardRemotePreviewManager( + previewRendererFactory = previewRendererFactory, + mainDispatcher = testDispatcher, + backgroundHandler = backgroundHandler, + ) underTest.attachInfoForTesting( context, @@ -190,7 +218,7 @@ class KeyguardQuickAffordanceProviderTest : SysuiTestCase() { @Test fun `insert and query selection`() = - runBlocking(IMMEDIATE) { + testScope.runTest { val slotId = KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START val affordanceId = AFFORDANCE_2 val affordanceName = AFFORDANCE_2_NAME @@ -214,7 +242,7 @@ class KeyguardQuickAffordanceProviderTest : SysuiTestCase() { @Test fun `query slots`() = - runBlocking(IMMEDIATE) { + testScope.runTest { assertThat(querySlots()) .isEqualTo( listOf( @@ -232,7 +260,7 @@ class KeyguardQuickAffordanceProviderTest : SysuiTestCase() { @Test fun `query affordances`() = - runBlocking(IMMEDIATE) { + testScope.runTest { assertThat(queryAffordances()) .isEqualTo( listOf( @@ -252,7 +280,7 @@ class KeyguardQuickAffordanceProviderTest : SysuiTestCase() { @Test fun `delete and query selection`() = - runBlocking(IMMEDIATE) { + testScope.runTest { insertSelection( slotId = KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START, affordanceId = AFFORDANCE_1, @@ -286,7 +314,7 @@ class KeyguardQuickAffordanceProviderTest : SysuiTestCase() { @Test fun `delete all selections in a slot`() = - runBlocking(IMMEDIATE) { + testScope.runTest { insertSelection( slotId = KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START, affordanceId = AFFORDANCE_1, @@ -316,6 +344,23 @@ class KeyguardQuickAffordanceProviderTest : SysuiTestCase() { ) } + @Test + fun preview() = + testScope.runTest { + val hostToken: IBinder = mock() + whenever(previewRenderer.hostToken).thenReturn(hostToken) + val extras = Bundle() + + val result = underTest.call("whatever", "anything", extras) + + verify(previewRenderer).render() + verify(hostToken).linkToDeath(any(), anyInt()) + assertThat(result!!).isNotNull() + assertThat(result.get(KeyguardRemotePreviewManager.KEY_PREVIEW_SURFACE_PACKAGE)) + .isEqualTo(previewSurfacePackage) + assertThat(result.containsKey(KeyguardRemotePreviewManager.KEY_PREVIEW_CALLBACK)) + } + private fun insertSelection( slotId: String, affordanceId: String, @@ -451,7 +496,6 @@ class KeyguardQuickAffordanceProviderTest : SysuiTestCase() { ) companion object { - private val IMMEDIATE = Dispatchers.Main.immediate private const val AFFORDANCE_1 = "affordance_1" private const val AFFORDANCE_2 = "affordance_2" private const val AFFORDANCE_1_NAME = "affordance_1_name" diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt index 11fe905b1d1f..d97571bcd8ef 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt @@ -23,6 +23,7 @@ import com.android.internal.widget.LockPatternUtils import com.android.systemui.SysuiTestCase import com.android.systemui.common.shared.model.ContentDescription import com.android.systemui.common.shared.model.Icon +import com.android.systemui.coroutines.collectLastValue import com.android.systemui.flags.FakeFeatureFlags import com.android.systemui.flags.Flags import com.android.systemui.keyguard.data.quickaffordance.BuiltInKeyguardQuickAffordanceKeys @@ -49,14 +50,10 @@ import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import com.android.systemui.util.settings.FakeSettings import com.google.common.truth.Truth.assertThat -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.runBlocking -import kotlinx.coroutines.test.runBlockingTest -import kotlinx.coroutines.yield +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -78,6 +75,7 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { private lateinit var underTest: KeyguardQuickAffordanceInteractor + private lateinit var testScope: TestScope private lateinit var repository: FakeKeyguardRepository private lateinit var homeControls: FakeKeyguardQuickAffordanceConfig private lateinit var quickAccessWallet: FakeKeyguardQuickAffordanceConfig @@ -99,7 +97,8 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { ) qrCodeScanner = FakeKeyguardQuickAffordanceConfig(BuiltInKeyguardQuickAffordanceKeys.QR_CODE_SCANNER) - val scope = CoroutineScope(IMMEDIATE) + val testDispatcher = StandardTestDispatcher() + testScope = TestScope(testDispatcher) val localUserSelectionManager = KeyguardQuickAffordanceLocalUserSelectionManager( @@ -120,7 +119,7 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { ) val remoteUserSelectionManager = KeyguardQuickAffordanceRemoteUserSelectionManager( - scope = scope, + scope = testScope.backgroundScope, userTracker = userTracker, clientFactory = FakeKeyguardQuickAffordanceProviderClientFactory(userTracker), userHandle = UserHandle.SYSTEM, @@ -128,14 +127,14 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { val quickAffordanceRepository = KeyguardQuickAffordanceRepository( appContext = context, - scope = scope, + scope = testScope.backgroundScope, localUserSelectionManager = localUserSelectionManager, remoteUserSelectionManager = remoteUserSelectionManager, userTracker = userTracker, legacySettingSyncer = KeyguardQuickAffordanceLegacySettingSyncer( - scope = scope, - backgroundDispatcher = IMMEDIATE, + scope = testScope.backgroundScope, + backgroundDispatcher = testDispatcher, secureSettings = FakeSettings(), selectionsManager = localUserSelectionManager, ), @@ -175,88 +174,76 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { } @Test - fun `quickAffordance - bottom start affordance is visible`() = runBlockingTest { - val configKey = BuiltInKeyguardQuickAffordanceKeys.HOME_CONTROLS - homeControls.setState( - KeyguardQuickAffordanceConfig.LockScreenState.Visible( - icon = ICON, - activationState = ActivationState.Active, + fun `quickAffordance - bottom start affordance is visible`() = + testScope.runTest { + val configKey = BuiltInKeyguardQuickAffordanceKeys.HOME_CONTROLS + homeControls.setState( + KeyguardQuickAffordanceConfig.LockScreenState.Visible( + icon = ICON, + activationState = ActivationState.Active, + ) ) - ) - - var latest: KeyguardQuickAffordanceModel? = null - val job = - underTest - .quickAffordance(KeyguardQuickAffordancePosition.BOTTOM_START) - .onEach { latest = it } - .launchIn(this) - // The interactor has an onStart { emit(Hidden) } to cover for upstream configs that don't - // produce an initial value. We yield to give the coroutine time to emit the first real - // value from our config. - yield() - - assertThat(latest).isInstanceOf(KeyguardQuickAffordanceModel.Visible::class.java) - val visibleModel = latest as KeyguardQuickAffordanceModel.Visible - assertThat(visibleModel.configKey).isEqualTo(configKey) - assertThat(visibleModel.icon).isEqualTo(ICON) - assertThat(visibleModel.icon.contentDescription) - .isEqualTo(ContentDescription.Resource(res = CONTENT_DESCRIPTION_RESOURCE_ID)) - assertThat(visibleModel.activationState).isEqualTo(ActivationState.Active) - job.cancel() - } + + val collectedValue = + collectLastValue( + underTest.quickAffordance(KeyguardQuickAffordancePosition.BOTTOM_START) + ) + + assertThat(collectedValue()) + .isInstanceOf(KeyguardQuickAffordanceModel.Visible::class.java) + val visibleModel = collectedValue() as KeyguardQuickAffordanceModel.Visible + assertThat(visibleModel.configKey).isEqualTo(configKey) + assertThat(visibleModel.icon).isEqualTo(ICON) + assertThat(visibleModel.icon.contentDescription) + .isEqualTo(ContentDescription.Resource(res = CONTENT_DESCRIPTION_RESOURCE_ID)) + assertThat(visibleModel.activationState).isEqualTo(ActivationState.Active) + } @Test - fun `quickAffordance - bottom end affordance is visible`() = runBlockingTest { - val configKey = BuiltInKeyguardQuickAffordanceKeys.QUICK_ACCESS_WALLET - quickAccessWallet.setState( - KeyguardQuickAffordanceConfig.LockScreenState.Visible( - icon = ICON, + fun `quickAffordance - bottom end affordance is visible`() = + testScope.runTest { + val configKey = BuiltInKeyguardQuickAffordanceKeys.QUICK_ACCESS_WALLET + quickAccessWallet.setState( + KeyguardQuickAffordanceConfig.LockScreenState.Visible( + icon = ICON, + ) ) - ) - - var latest: KeyguardQuickAffordanceModel? = null - val job = - underTest - .quickAffordance(KeyguardQuickAffordancePosition.BOTTOM_END) - .onEach { latest = it } - .launchIn(this) - // The interactor has an onStart { emit(Hidden) } to cover for upstream configs that don't - // produce an initial value. We yield to give the coroutine time to emit the first real - // value from our config. - yield() - - assertThat(latest).isInstanceOf(KeyguardQuickAffordanceModel.Visible::class.java) - val visibleModel = latest as KeyguardQuickAffordanceModel.Visible - assertThat(visibleModel.configKey).isEqualTo(configKey) - assertThat(visibleModel.icon).isEqualTo(ICON) - assertThat(visibleModel.icon.contentDescription) - .isEqualTo(ContentDescription.Resource(res = CONTENT_DESCRIPTION_RESOURCE_ID)) - assertThat(visibleModel.activationState).isEqualTo(ActivationState.NotSupported) - job.cancel() - } + + val collectedValue = + collectLastValue( + underTest.quickAffordance(KeyguardQuickAffordancePosition.BOTTOM_END) + ) + + assertThat(collectedValue()) + .isInstanceOf(KeyguardQuickAffordanceModel.Visible::class.java) + val visibleModel = collectedValue() as KeyguardQuickAffordanceModel.Visible + assertThat(visibleModel.configKey).isEqualTo(configKey) + assertThat(visibleModel.icon).isEqualTo(ICON) + assertThat(visibleModel.icon.contentDescription) + .isEqualTo(ContentDescription.Resource(res = CONTENT_DESCRIPTION_RESOURCE_ID)) + assertThat(visibleModel.activationState).isEqualTo(ActivationState.NotSupported) + } @Test - fun `quickAffordance - bottom start affordance hidden while dozing`() = runBlockingTest { - repository.setDozing(true) - homeControls.setState( - KeyguardQuickAffordanceConfig.LockScreenState.Visible( - icon = ICON, + fun `quickAffordance - bottom start affordance hidden while dozing`() = + testScope.runTest { + repository.setDozing(true) + homeControls.setState( + KeyguardQuickAffordanceConfig.LockScreenState.Visible( + icon = ICON, + ) ) - ) - - var latest: KeyguardQuickAffordanceModel? = null - val job = - underTest - .quickAffordance(KeyguardQuickAffordancePosition.BOTTOM_START) - .onEach { latest = it } - .launchIn(this) - assertThat(latest).isEqualTo(KeyguardQuickAffordanceModel.Hidden) - job.cancel() - } + + val collectedValue = + collectLastValue( + underTest.quickAffordance(KeyguardQuickAffordancePosition.BOTTOM_START) + ) + assertThat(collectedValue()).isEqualTo(KeyguardQuickAffordanceModel.Hidden) + } @Test fun `quickAffordance - bottom start affordance hidden when lockscreen is not showing`() = - runBlockingTest { + testScope.runTest { repository.setKeyguardShowing(false) homeControls.setState( KeyguardQuickAffordanceConfig.LockScreenState.Visible( @@ -264,19 +251,45 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { ) ) - var latest: KeyguardQuickAffordanceModel? = null - val job = - underTest - .quickAffordance(KeyguardQuickAffordancePosition.BOTTOM_START) - .onEach { latest = it } - .launchIn(this) - assertThat(latest).isEqualTo(KeyguardQuickAffordanceModel.Hidden) - job.cancel() + val collectedValue = + collectLastValue( + underTest.quickAffordance(KeyguardQuickAffordancePosition.BOTTOM_START) + ) + assertThat(collectedValue()).isEqualTo(KeyguardQuickAffordanceModel.Hidden) + } + + @Test + fun `quickAffordanceAlwaysVisible - even when lock screen not showing and dozing`() = + testScope.runTest { + repository.setKeyguardShowing(false) + repository.setDozing(true) + val configKey = BuiltInKeyguardQuickAffordanceKeys.HOME_CONTROLS + homeControls.setState( + KeyguardQuickAffordanceConfig.LockScreenState.Visible( + icon = ICON, + activationState = ActivationState.Active, + ) + ) + + val collectedValue = + collectLastValue( + underTest.quickAffordanceAlwaysVisible( + KeyguardQuickAffordancePosition.BOTTOM_START + ) + ) + assertThat(collectedValue()) + .isInstanceOf(KeyguardQuickAffordanceModel.Visible::class.java) + val visibleModel = collectedValue() as KeyguardQuickAffordanceModel.Visible + assertThat(visibleModel.configKey).isEqualTo(configKey) + assertThat(visibleModel.icon).isEqualTo(ICON) + assertThat(visibleModel.icon.contentDescription) + .isEqualTo(ContentDescription.Resource(res = CONTENT_DESCRIPTION_RESOURCE_ID)) + assertThat(visibleModel.activationState).isEqualTo(ActivationState.Active) } @Test fun select() = - runBlocking(IMMEDIATE) { + testScope.runTest { featureFlags.set(Flags.CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES, true) homeControls.setState( KeyguardQuickAffordanceConfig.LockScreenState.Visible(icon = ICON) @@ -296,23 +309,18 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { ) ) - var startConfig: KeyguardQuickAffordanceModel? = null - val job1 = - underTest - .quickAffordance(KeyguardQuickAffordancePosition.BOTTOM_START) - .onEach { startConfig = it } - .launchIn(this) - var endConfig: KeyguardQuickAffordanceModel? = null - val job2 = - underTest - .quickAffordance(KeyguardQuickAffordancePosition.BOTTOM_END) - .onEach { endConfig = it } - .launchIn(this) + val startConfig = + collectLastValue( + underTest.quickAffordance(KeyguardQuickAffordancePosition.BOTTOM_START) + ) + val endConfig = + collectLastValue( + underTest.quickAffordance(KeyguardQuickAffordancePosition.BOTTOM_END) + ) underTest.select(KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START, homeControls.key) - yield() - yield() - assertThat(startConfig) + + assertThat(startConfig()) .isEqualTo( KeyguardQuickAffordanceModel.Visible( configKey = @@ -322,7 +330,7 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { activationState = ActivationState.NotSupported, ) ) - assertThat(endConfig) + assertThat(endConfig()) .isEqualTo( KeyguardQuickAffordanceModel.Hidden, ) @@ -345,9 +353,8 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START, quickAccessWallet.key ) - yield() - yield() - assertThat(startConfig) + + assertThat(startConfig()) .isEqualTo( KeyguardQuickAffordanceModel.Visible( configKey = @@ -357,7 +364,7 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { activationState = ActivationState.NotSupported, ) ) - assertThat(endConfig) + assertThat(endConfig()) .isEqualTo( KeyguardQuickAffordanceModel.Hidden, ) @@ -377,9 +384,8 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { ) underTest.select(KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END, qrCodeScanner.key) - yield() - yield() - assertThat(startConfig) + + assertThat(startConfig()) .isEqualTo( KeyguardQuickAffordanceModel.Visible( configKey = @@ -389,7 +395,7 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { activationState = ActivationState.NotSupported, ) ) - assertThat(endConfig) + assertThat(endConfig()) .isEqualTo( KeyguardQuickAffordanceModel.Visible( configKey = @@ -420,14 +426,11 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { ), ) ) - - job1.cancel() - job2.cancel() } @Test fun `unselect - one`() = - runBlocking(IMMEDIATE) { + testScope.runTest { featureFlags.set(Flags.CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES, true) homeControls.setState( KeyguardQuickAffordanceConfig.LockScreenState.Visible(icon = ICON) @@ -439,34 +442,23 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { KeyguardQuickAffordanceConfig.LockScreenState.Visible(icon = ICON) ) - var startConfig: KeyguardQuickAffordanceModel? = null - val job1 = - underTest - .quickAffordance(KeyguardQuickAffordancePosition.BOTTOM_START) - .onEach { startConfig = it } - .launchIn(this) - var endConfig: KeyguardQuickAffordanceModel? = null - val job2 = - underTest - .quickAffordance(KeyguardQuickAffordancePosition.BOTTOM_END) - .onEach { endConfig = it } - .launchIn(this) + val startConfig = + collectLastValue( + underTest.quickAffordance(KeyguardQuickAffordancePosition.BOTTOM_START) + ) + val endConfig = + collectLastValue( + underTest.quickAffordance(KeyguardQuickAffordancePosition.BOTTOM_END) + ) underTest.select(KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START, homeControls.key) - yield() - yield() underTest.select(KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END, quickAccessWallet.key) - yield() - yield() - underTest.unselect(KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START, homeControls.key) - yield() - yield() - assertThat(startConfig) + assertThat(startConfig()) .isEqualTo( KeyguardQuickAffordanceModel.Hidden, ) - assertThat(endConfig) + assertThat(endConfig()) .isEqualTo( KeyguardQuickAffordanceModel.Visible( configKey = @@ -495,14 +487,12 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END, quickAccessWallet.key ) - yield() - yield() - assertThat(startConfig) + assertThat(startConfig()) .isEqualTo( KeyguardQuickAffordanceModel.Hidden, ) - assertThat(endConfig) + assertThat(endConfig()) .isEqualTo( KeyguardQuickAffordanceModel.Hidden, ) @@ -513,14 +503,11 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END to emptyList(), ) ) - - job1.cancel() - job2.cancel() } @Test fun `unselect - all`() = - runBlocking(IMMEDIATE) { + testScope.runTest { featureFlags.set(Flags.CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES, true) homeControls.setState( KeyguardQuickAffordanceConfig.LockScreenState.Visible(icon = ICON) @@ -533,15 +520,8 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { ) underTest.select(KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START, homeControls.key) - yield() - yield() underTest.select(KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END, quickAccessWallet.key) - yield() - yield() - underTest.unselect(KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START, null) - yield() - yield() assertThat(underTest.getSelections()) .isEqualTo( @@ -562,8 +542,6 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END, null, ) - yield() - yield() assertThat(underTest.getSelections()) .isEqualTo( @@ -584,6 +562,5 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { ) } private const val CONTENT_DESCRIPTION_RESOURCE_ID = 1337 - private val IMMEDIATE = Dispatchers.Main.immediate } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt index 83a5d0e90c84..0abff88b5faf 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt @@ -23,6 +23,7 @@ import com.android.internal.widget.LockPatternUtils import com.android.systemui.SysuiTestCase import com.android.systemui.animation.Expandable import com.android.systemui.common.shared.model.Icon +import com.android.systemui.coroutines.collectLastValue import com.android.systemui.doze.util.BurnInHelperWrapper import com.android.systemui.flags.FakeFeatureFlags import com.android.systemui.flags.Flags @@ -44,20 +45,21 @@ import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAfforda import com.android.systemui.plugins.ActivityStarter import com.android.systemui.settings.UserFileManager import com.android.systemui.settings.UserTracker +import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.FakeSharedPreferences import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.mock +import com.android.systemui.util.mockito.whenever import com.android.systemui.util.settings.FakeSettings import com.google.common.truth.Truth.assertThat import kotlin.math.max import kotlin.math.min -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.test.runBlockingTest -import kotlinx.coroutines.yield +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -67,9 +69,9 @@ import org.mockito.ArgumentMatchers.anyString import org.mockito.Mock import org.mockito.Mockito import org.mockito.Mockito.verifyZeroInteractions -import org.mockito.Mockito.`when` as whenever import org.mockito.MockitoAnnotations +@OptIn(ExperimentalCoroutinesApi::class) @SmallTest @RunWith(JUnit4::class) class KeyguardBottomAreaViewModelTest : SysuiTestCase() { @@ -83,6 +85,7 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { private lateinit var underTest: KeyguardBottomAreaViewModel + private lateinit var testScope: TestScope private lateinit var repository: FakeKeyguardRepository private lateinit var registry: FakeKeyguardQuickAffordanceRegistry private lateinit var homeControlsQuickAffordanceConfig: FakeKeyguardQuickAffordanceConfig @@ -123,7 +126,8 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { whenever(userTracker.userHandle).thenReturn(mock()) whenever(lockPatternUtils.getStrongAuthForUser(anyInt())) .thenReturn(LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED) - val scope = CoroutineScope(IMMEDIATE) + val testDispatcher = StandardTestDispatcher() + testScope = TestScope(testDispatcher) val localUserSelectionManager = KeyguardQuickAffordanceLocalUserSelectionManager( context = context, @@ -143,7 +147,7 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { ) val remoteUserSelectionManager = KeyguardQuickAffordanceRemoteUserSelectionManager( - scope = scope, + scope = testScope.backgroundScope, userTracker = userTracker, clientFactory = FakeKeyguardQuickAffordanceProviderClientFactory(userTracker), userHandle = UserHandle.SYSTEM, @@ -151,14 +155,14 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { val quickAffordanceRepository = KeyguardQuickAffordanceRepository( appContext = context, - scope = scope, + scope = testScope.backgroundScope, localUserSelectionManager = localUserSelectionManager, remoteUserSelectionManager = remoteUserSelectionManager, userTracker = userTracker, legacySettingSyncer = KeyguardQuickAffordanceLegacySettingSyncer( - scope = scope, - backgroundDispatcher = IMMEDIATE, + scope = testScope.backgroundScope, + backgroundDispatcher = testDispatcher, secureSettings = FakeSettings(), selectionsManager = localUserSelectionManager, ), @@ -194,366 +198,394 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { } @Test - fun `startButton - present - visible model - starts activity on click`() = runBlockingTest { - repository.setKeyguardShowing(true) - var latest: KeyguardQuickAffordanceViewModel? = null - val job = underTest.startButton.onEach { latest = it }.launchIn(this) - - val testConfig = - TestConfig( - isVisible = true, - isClickable = true, - isActivated = true, - icon = mock(), - canShowWhileLocked = false, - intent = Intent("action"), - ) - val configKey = - setUpQuickAffordanceModel( - position = KeyguardQuickAffordancePosition.BOTTOM_START, + fun `startButton - present - visible model - starts activity on click`() = + testScope.runTest { + repository.setKeyguardShowing(true) + val latest = collectLastValue(underTest.startButton) + + val testConfig = + TestConfig( + isVisible = true, + isClickable = true, + isActivated = true, + icon = mock(), + canShowWhileLocked = false, + intent = Intent("action"), + ) + val configKey = + setUpQuickAffordanceModel( + position = KeyguardQuickAffordancePosition.BOTTOM_START, + testConfig = testConfig, + ) + + assertQuickAffordanceViewModel( + viewModel = latest(), testConfig = testConfig, + configKey = configKey, ) - - assertQuickAffordanceViewModel( - viewModel = latest, - testConfig = testConfig, - configKey = configKey, - ) - job.cancel() - } + } @Test - fun `endButton - present - visible model - do nothing on click`() = runBlockingTest { - repository.setKeyguardShowing(true) - var latest: KeyguardQuickAffordanceViewModel? = null - val job = underTest.endButton.onEach { latest = it }.launchIn(this) + fun `startButton - in preview mode - visible even when keyguard not showing`() = + testScope.runTest { + underTest.enablePreviewMode(KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START) + repository.setKeyguardShowing(false) + val latest = collectLastValue(underTest.startButton) + + val icon: Icon = mock() + val configKey = + setUpQuickAffordanceModel( + position = KeyguardQuickAffordancePosition.BOTTOM_START, + testConfig = + TestConfig( + isVisible = true, + isClickable = true, + isActivated = true, + icon = icon, + canShowWhileLocked = false, + intent = Intent("action"), + ), + ) - val config = - TestConfig( - isVisible = true, - isClickable = true, - icon = mock(), - canShowWhileLocked = false, - intent = null, // This will cause it to tell the system that the click was handled. + assertQuickAffordanceViewModel( + viewModel = latest(), + testConfig = + TestConfig( + isVisible = true, + isClickable = false, + isActivated = true, + icon = icon, + canShowWhileLocked = false, + intent = Intent("action"), + ), + configKey = configKey, ) - val configKey = - setUpQuickAffordanceModel( - position = KeyguardQuickAffordancePosition.BOTTOM_END, + assertThat(latest()?.isSelected).isTrue() + } + + @Test + fun `endButton - present - visible model - do nothing on click`() = + testScope.runTest { + repository.setKeyguardShowing(true) + val latest = collectLastValue(underTest.endButton) + + val config = + TestConfig( + isVisible = true, + isClickable = true, + icon = mock(), + canShowWhileLocked = false, + intent = + null, // This will cause it to tell the system that the click was handled. + ) + val configKey = + setUpQuickAffordanceModel( + position = KeyguardQuickAffordancePosition.BOTTOM_END, + testConfig = config, + ) + + assertQuickAffordanceViewModel( + viewModel = latest(), testConfig = config, + configKey = configKey, ) - - assertQuickAffordanceViewModel( - viewModel = latest, - testConfig = config, - configKey = configKey, - ) - job.cancel() - } + } @Test - fun `startButton - not present - model is hidden`() = runBlockingTest { - var latest: KeyguardQuickAffordanceViewModel? = null - val job = underTest.startButton.onEach { latest = it }.launchIn(this) + fun `startButton - not present - model is hidden`() = + testScope.runTest { + val latest = collectLastValue(underTest.startButton) - val config = - TestConfig( - isVisible = false, - ) - val configKey = - setUpQuickAffordanceModel( - position = KeyguardQuickAffordancePosition.BOTTOM_START, + val config = + TestConfig( + isVisible = false, + ) + val configKey = + setUpQuickAffordanceModel( + position = KeyguardQuickAffordancePosition.BOTTOM_START, + testConfig = config, + ) + + assertQuickAffordanceViewModel( + viewModel = latest(), testConfig = config, + configKey = configKey, ) - - assertQuickAffordanceViewModel( - viewModel = latest, - testConfig = config, - configKey = configKey, - ) - job.cancel() - } + } @Test - fun animateButtonReveal() = runBlockingTest { - repository.setKeyguardShowing(true) - val testConfig = - TestConfig( - isVisible = true, - isClickable = true, - icon = mock(), - canShowWhileLocked = false, - intent = Intent("action"), + fun animateButtonReveal() = + testScope.runTest { + repository.setKeyguardShowing(true) + val testConfig = + TestConfig( + isVisible = true, + isClickable = true, + icon = mock(), + canShowWhileLocked = false, + intent = Intent("action"), + ) + + setUpQuickAffordanceModel( + position = KeyguardQuickAffordancePosition.BOTTOM_START, + testConfig = testConfig, ) - setUpQuickAffordanceModel( - position = KeyguardQuickAffordancePosition.BOTTOM_START, - testConfig = testConfig, - ) + val value = collectLastValue(underTest.startButton.map { it.animateReveal }) - val values = mutableListOf<Boolean>() - val job = underTest.startButton.onEach { values.add(it.animateReveal) }.launchIn(this) + assertThat(value()).isFalse() + repository.setAnimateDozingTransitions(true) + assertThat(value()).isTrue() + repository.setAnimateDozingTransitions(false) + assertThat(value()).isFalse() + } - repository.setAnimateDozingTransitions(true) - yield() - repository.setAnimateDozingTransitions(false) - yield() + @Test + fun isOverlayContainerVisible() = + testScope.runTest { + val value = collectLastValue(underTest.isOverlayContainerVisible) + + assertThat(value()).isTrue() + repository.setDozing(true) + assertThat(value()).isFalse() + repository.setDozing(false) + assertThat(value()).isTrue() + } - // Note the extra false value in the beginning. This is to cover for the initial value - // inserted by the quick affordance interactor which it does to cover for config - // implementations that don't emit an initial value. - assertThat(values).isEqualTo(listOf(false, false, true, false)) - job.cancel() - } + @Test + fun alpha() = + testScope.runTest { + val value = collectLastValue(underTest.alpha) + + assertThat(value()).isEqualTo(1f) + repository.setBottomAreaAlpha(0.1f) + assertThat(value()).isEqualTo(0.1f) + repository.setBottomAreaAlpha(0.5f) + assertThat(value()).isEqualTo(0.5f) + repository.setBottomAreaAlpha(0.2f) + assertThat(value()).isEqualTo(0.2f) + repository.setBottomAreaAlpha(0f) + assertThat(value()).isEqualTo(0f) + } @Test - fun isOverlayContainerVisible() = runBlockingTest { - val values = mutableListOf<Boolean>() - val job = underTest.isOverlayContainerVisible.onEach(values::add).launchIn(this) + fun `alpha - in preview mode - does not change`() = + testScope.runTest { + underTest.enablePreviewMode(null) + val value = collectLastValue(underTest.alpha) + + assertThat(value()).isEqualTo(1f) + repository.setBottomAreaAlpha(0.1f) + assertThat(value()).isEqualTo(1f) + repository.setBottomAreaAlpha(0.5f) + assertThat(value()).isEqualTo(1f) + repository.setBottomAreaAlpha(0.2f) + assertThat(value()).isEqualTo(1f) + repository.setBottomAreaAlpha(0f) + assertThat(value()).isEqualTo(1f) + } - repository.setDozing(true) - repository.setDozing(false) + @Test + fun isIndicationAreaPadded() = + testScope.runTest { + repository.setKeyguardShowing(true) + val value = collectLastValue(underTest.isIndicationAreaPadded) - assertThat(values).isEqualTo(listOf(true, false, true)) - job.cancel() - } + assertThat(value()).isFalse() + setUpQuickAffordanceModel( + position = KeyguardQuickAffordancePosition.BOTTOM_START, + testConfig = + TestConfig( + isVisible = true, + isClickable = true, + icon = mock(), + canShowWhileLocked = true, + ) + ) + assertThat(value()).isTrue() + setUpQuickAffordanceModel( + position = KeyguardQuickAffordancePosition.BOTTOM_END, + testConfig = + TestConfig( + isVisible = true, + isClickable = true, + icon = mock(), + canShowWhileLocked = false, + ) + ) + assertThat(value()).isTrue() + setUpQuickAffordanceModel( + position = KeyguardQuickAffordancePosition.BOTTOM_START, + testConfig = + TestConfig( + isVisible = false, + ) + ) + assertThat(value()).isTrue() + setUpQuickAffordanceModel( + position = KeyguardQuickAffordancePosition.BOTTOM_END, + testConfig = + TestConfig( + isVisible = false, + ) + ) + assertThat(value()).isFalse() + } @Test - fun alpha() = runBlockingTest { - val values = mutableListOf<Float>() - val job = underTest.alpha.onEach(values::add).launchIn(this) - - repository.setBottomAreaAlpha(0.1f) - repository.setBottomAreaAlpha(0.5f) - repository.setBottomAreaAlpha(0.2f) - repository.setBottomAreaAlpha(0f) + fun indicationAreaTranslationX() = + testScope.runTest { + val value = collectLastValue(underTest.indicationAreaTranslationX) + + assertThat(value()).isEqualTo(0f) + repository.setClockPosition(100, 100) + assertThat(value()).isEqualTo(100f) + repository.setClockPosition(200, 100) + assertThat(value()).isEqualTo(200f) + repository.setClockPosition(200, 200) + assertThat(value()).isEqualTo(200f) + repository.setClockPosition(300, 100) + assertThat(value()).isEqualTo(300f) + } - assertThat(values).isEqualTo(listOf(1f, 0.1f, 0.5f, 0.2f, 0f)) - job.cancel() - } + @Test + fun indicationAreaTranslationY() = + testScope.runTest { + val value = + collectLastValue(underTest.indicationAreaTranslationY(DEFAULT_BURN_IN_OFFSET)) + + // Negative 0 - apparently there's a difference in floating point arithmetic - FML + assertThat(value()).isEqualTo(-0f) + val expected1 = setDozeAmountAndCalculateExpectedTranslationY(0.1f) + assertThat(value()).isEqualTo(expected1) + val expected2 = setDozeAmountAndCalculateExpectedTranslationY(0.2f) + assertThat(value()).isEqualTo(expected2) + val expected3 = setDozeAmountAndCalculateExpectedTranslationY(0.5f) + assertThat(value()).isEqualTo(expected3) + val expected4 = setDozeAmountAndCalculateExpectedTranslationY(1f) + assertThat(value()).isEqualTo(expected4) + } @Test - fun isIndicationAreaPadded() = runBlockingTest { - repository.setKeyguardShowing(true) - val values = mutableListOf<Boolean>() - val job = underTest.isIndicationAreaPadded.onEach(values::add).launchIn(this) - - setUpQuickAffordanceModel( - position = KeyguardQuickAffordancePosition.BOTTOM_START, - testConfig = - TestConfig( - isVisible = true, - isClickable = true, - icon = mock(), - canShowWhileLocked = true, - ) - ) - setUpQuickAffordanceModel( - position = KeyguardQuickAffordancePosition.BOTTOM_END, - testConfig = + fun `isClickable - true when alpha at threshold`() = + testScope.runTest { + repository.setKeyguardShowing(true) + repository.setBottomAreaAlpha( + KeyguardBottomAreaViewModel.AFFORDANCE_FULLY_OPAQUE_ALPHA_THRESHOLD + ) + + val testConfig = TestConfig( isVisible = true, isClickable = true, icon = mock(), canShowWhileLocked = false, + intent = Intent("action"), ) - ) - setUpQuickAffordanceModel( - position = KeyguardQuickAffordancePosition.BOTTOM_START, - testConfig = - TestConfig( - isVisible = false, - ) - ) - setUpQuickAffordanceModel( - position = KeyguardQuickAffordancePosition.BOTTOM_END, - testConfig = - TestConfig( - isVisible = false, - ) - ) - - assertThat(values) - .isEqualTo( - listOf( - // Initially, no button is visible so the indication area is not padded. - false, - // Once we add the first visible button, the indication area becomes padded. - // This - // continues to be true after we add the second visible button and even after we - // make the first button not visible anymore. - true, - // Once both buttons are not visible, the indication area is, again, not padded. - false, + val configKey = + setUpQuickAffordanceModel( + position = KeyguardQuickAffordancePosition.BOTTOM_START, + testConfig = testConfig, ) - ) - job.cancel() - } - - @Test - fun indicationAreaTranslationX() = runBlockingTest { - val values = mutableListOf<Float>() - val job = underTest.indicationAreaTranslationX.onEach(values::add).launchIn(this) - repository.setClockPosition(100, 100) - repository.setClockPosition(200, 100) - repository.setClockPosition(200, 200) - repository.setClockPosition(300, 100) + val latest = collectLastValue(underTest.startButton) - assertThat(values).isEqualTo(listOf(0f, 100f, 200f, 300f)) - job.cancel() - } + assertQuickAffordanceViewModel( + viewModel = latest(), + testConfig = testConfig, + configKey = configKey, + ) + } @Test - fun indicationAreaTranslationY() = runBlockingTest { - val values = mutableListOf<Float>() - val job = - underTest - .indicationAreaTranslationY(DEFAULT_BURN_IN_OFFSET) - .onEach(values::add) - .launchIn(this) - - val expectedTranslationValues = - listOf( - -0f, // Negative 0 - apparently there's a difference in floating point arithmetic - - // FML - setDozeAmountAndCalculateExpectedTranslationY(0.1f), - setDozeAmountAndCalculateExpectedTranslationY(0.2f), - setDozeAmountAndCalculateExpectedTranslationY(0.5f), - setDozeAmountAndCalculateExpectedTranslationY(1f), + fun `isClickable - true when alpha above threshold`() = + testScope.runTest { + repository.setKeyguardShowing(true) + val latest = collectLastValue(underTest.startButton) + repository.setBottomAreaAlpha( + min(1f, KeyguardBottomAreaViewModel.AFFORDANCE_FULLY_OPAQUE_ALPHA_THRESHOLD + 0.1f), ) - assertThat(values).isEqualTo(expectedTranslationValues) - job.cancel() - } + val testConfig = + TestConfig( + isVisible = true, + isClickable = true, + icon = mock(), + canShowWhileLocked = false, + intent = Intent("action"), + ) + val configKey = + setUpQuickAffordanceModel( + position = KeyguardQuickAffordancePosition.BOTTOM_START, + testConfig = testConfig, + ) - @Test - fun `isClickable - true when alpha at threshold`() = runBlockingTest { - repository.setKeyguardShowing(true) - repository.setBottomAreaAlpha( - KeyguardBottomAreaViewModel.AFFORDANCE_FULLY_OPAQUE_ALPHA_THRESHOLD - ) - - val testConfig = - TestConfig( - isVisible = true, - isClickable = true, - icon = mock(), - canShowWhileLocked = false, - intent = Intent("action"), - ) - val configKey = - setUpQuickAffordanceModel( - position = KeyguardQuickAffordancePosition.BOTTOM_START, + assertQuickAffordanceViewModel( + viewModel = latest(), testConfig = testConfig, + configKey = configKey, ) - - var latest: KeyguardQuickAffordanceViewModel? = null - val job = underTest.startButton.onEach { latest = it }.launchIn(this) - // The interactor has an onStart { emit(Hidden) } to cover for upstream configs that don't - // produce an initial value. We yield to give the coroutine time to emit the first real - // value from our config. - yield() - - assertQuickAffordanceViewModel( - viewModel = latest, - testConfig = testConfig, - configKey = configKey, - ) - job.cancel() - } + } @Test - fun `isClickable - true when alpha above threshold`() = runBlockingTest { - repository.setKeyguardShowing(true) - var latest: KeyguardQuickAffordanceViewModel? = null - val job = underTest.startButton.onEach { latest = it }.launchIn(this) - repository.setBottomAreaAlpha( - min(1f, KeyguardBottomAreaViewModel.AFFORDANCE_FULLY_OPAQUE_ALPHA_THRESHOLD + 0.1f), - ) - - val testConfig = - TestConfig( - isVisible = true, - isClickable = true, - icon = mock(), - canShowWhileLocked = false, - intent = Intent("action"), - ) - val configKey = - setUpQuickAffordanceModel( - position = KeyguardQuickAffordancePosition.BOTTOM_START, - testConfig = testConfig, + fun `isClickable - false when alpha below threshold`() = + testScope.runTest { + repository.setKeyguardShowing(true) + val latest = collectLastValue(underTest.startButton) + repository.setBottomAreaAlpha( + max(0f, KeyguardBottomAreaViewModel.AFFORDANCE_FULLY_OPAQUE_ALPHA_THRESHOLD - 0.1f), ) - assertQuickAffordanceViewModel( - viewModel = latest, - testConfig = testConfig, - configKey = configKey, - ) - job.cancel() - } + val testConfig = + TestConfig( + isVisible = true, + isClickable = false, + icon = mock(), + canShowWhileLocked = false, + intent = Intent("action"), + ) + val configKey = + setUpQuickAffordanceModel( + position = KeyguardQuickAffordancePosition.BOTTOM_START, + testConfig = testConfig, + ) - @Test - fun `isClickable - false when alpha below threshold`() = runBlockingTest { - repository.setKeyguardShowing(true) - var latest: KeyguardQuickAffordanceViewModel? = null - val job = underTest.startButton.onEach { latest = it }.launchIn(this) - repository.setBottomAreaAlpha( - max(0f, KeyguardBottomAreaViewModel.AFFORDANCE_FULLY_OPAQUE_ALPHA_THRESHOLD - 0.1f), - ) - - val testConfig = - TestConfig( - isVisible = true, - isClickable = false, - icon = mock(), - canShowWhileLocked = false, - intent = Intent("action"), - ) - val configKey = - setUpQuickAffordanceModel( - position = KeyguardQuickAffordancePosition.BOTTOM_START, + assertQuickAffordanceViewModel( + viewModel = latest(), testConfig = testConfig, + configKey = configKey, ) - - assertQuickAffordanceViewModel( - viewModel = latest, - testConfig = testConfig, - configKey = configKey, - ) - job.cancel() - } + } @Test - fun `isClickable - false when alpha at zero`() = runBlockingTest { - repository.setKeyguardShowing(true) - var latest: KeyguardQuickAffordanceViewModel? = null - val job = underTest.startButton.onEach { latest = it }.launchIn(this) - repository.setBottomAreaAlpha(0f) - - val testConfig = - TestConfig( - isVisible = true, - isClickable = false, - icon = mock(), - canShowWhileLocked = false, - intent = Intent("action"), - ) - val configKey = - setUpQuickAffordanceModel( - position = KeyguardQuickAffordancePosition.BOTTOM_START, + fun `isClickable - false when alpha at zero`() = + testScope.runTest { + repository.setKeyguardShowing(true) + val latest = collectLastValue(underTest.startButton) + repository.setBottomAreaAlpha(0f) + + val testConfig = + TestConfig( + isVisible = true, + isClickable = false, + icon = mock(), + canShowWhileLocked = false, + intent = Intent("action"), + ) + val configKey = + setUpQuickAffordanceModel( + position = KeyguardQuickAffordancePosition.BOTTOM_START, + testConfig = testConfig, + ) + + assertQuickAffordanceViewModel( + viewModel = latest(), testConfig = testConfig, + configKey = configKey, ) + } - assertQuickAffordanceViewModel( - viewModel = latest, - testConfig = testConfig, - configKey = configKey, - ) - job.cancel() - } - - private suspend fun setDozeAmountAndCalculateExpectedTranslationY(dozeAmount: Float): Float { + private fun setDozeAmountAndCalculateExpectedTranslationY(dozeAmount: Float): Float { repository.setDozeAmount(dozeAmount) return dozeAmount * (RETURNED_BURN_IN_OFFSET - DEFAULT_BURN_IN_OFFSET) } @@ -583,7 +615,6 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { when (testConfig.isActivated) { true -> ActivationState.Active false -> ActivationState.Inactive - null -> ActivationState.NotSupported } ) } else { @@ -636,6 +667,5 @@ class KeyguardBottomAreaViewModelTest : SysuiTestCase() { companion object { private const val DEFAULT_BURN_IN_OFFSET = 5 private const val RETURNED_BURN_IN_OFFSET = 3 - private val IMMEDIATE = Dispatchers.Main.immediate } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerTest.kt index e009e8651f2a..0e7bf8d9d465 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerTest.kt @@ -22,6 +22,7 @@ import com.android.systemui.dump.DumpManager import com.android.systemui.log.LogBufferFactory import com.android.systemui.plugins.log.LogBuffer import com.android.systemui.plugins.log.LogcatEchoTracker +import com.android.systemui.temporarydisplay.TemporaryViewInfo import com.google.common.truth.Truth.assertThat import java.io.PrintWriter import java.io.StringWriter @@ -33,7 +34,7 @@ import org.mockito.Mockito.mock class MediaTttLoggerTest : SysuiTestCase() { private lateinit var buffer: LogBuffer - private lateinit var logger: MediaTttLogger + private lateinit var logger: MediaTttLogger<TemporaryViewInfo> @Before fun setUp () { diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttUtilsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttUtilsTest.kt index cce3e369c0b8..561867f78e60 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttUtilsTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttUtilsTest.kt @@ -25,6 +25,7 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.common.shared.model.ContentDescription import com.android.systemui.common.shared.model.ContentDescription.Companion.loadContentDescription import com.android.systemui.common.shared.model.Icon +import com.android.systemui.temporarydisplay.TemporaryViewInfo import com.android.systemui.util.mockito.any import com.google.common.truth.Truth.assertThat import org.junit.Before @@ -40,7 +41,7 @@ class MediaTttUtilsTest : SysuiTestCase() { private lateinit var appIconFromPackageName: Drawable @Mock private lateinit var packageManager: PackageManager @Mock private lateinit var applicationInfo: ApplicationInfo - @Mock private lateinit var logger: MediaTttLogger + @Mock private lateinit var logger: MediaTttLogger<TemporaryViewInfo> @Before fun setUp() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/FakeMediaTttChipControllerReceiver.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/FakeMediaTttChipControllerReceiver.kt index 4aa982ed1609..bad3f0374a31 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/FakeMediaTttChipControllerReceiver.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/FakeMediaTttChipControllerReceiver.kt @@ -27,13 +27,14 @@ import com.android.systemui.media.taptotransfer.common.MediaTttLogger import com.android.systemui.statusbar.CommandQueue import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.util.concurrency.DelayableExecutor +import com.android.systemui.util.time.SystemClock import com.android.systemui.util.view.ViewUtil import com.android.systemui.util.wakelock.WakeLock class FakeMediaTttChipControllerReceiver( commandQueue: CommandQueue, context: Context, - logger: MediaTttLogger, + logger: MediaTttLogger<ChipReceiverInfo>, windowManager: WindowManager, mainExecutor: DelayableExecutor, accessibilityManager: AccessibilityManager, @@ -44,6 +45,7 @@ class FakeMediaTttChipControllerReceiver( uiEventLogger: MediaTttReceiverUiEventLogger, viewUtil: ViewUtil, wakeLockBuilder: WakeLock.Builder, + systemClock: SystemClock, ) : MediaTttChipControllerReceiver( commandQueue, @@ -59,6 +61,7 @@ class FakeMediaTttChipControllerReceiver( uiEventLogger, viewUtil, wakeLockBuilder, + systemClock, ) { override fun animateViewOut(view: ViewGroup, onAnimationEnd: Runnable) { // Just bypass the animation in tests diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt index 23f7cdb45026..ef0bfb7b6700 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt @@ -67,7 +67,7 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() { @Mock private lateinit var applicationInfo: ApplicationInfo @Mock - private lateinit var logger: MediaTttLogger + private lateinit var logger: MediaTttLogger<ChipReceiverInfo> @Mock private lateinit var accessibilityManager: AccessibilityManager @Mock @@ -128,6 +128,7 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() { receiverUiEventLogger, viewUtil, fakeWakeLockBuilder, + fakeClock, ) controllerReceiver.start() @@ -155,6 +156,7 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() { receiverUiEventLogger, viewUtil, fakeWakeLockBuilder, + fakeClock, ) controllerReceiver.start() @@ -193,6 +195,36 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() { } @Test + fun commandQueueCallback_transferToReceiverSucceeded_noChipShown() { + commandQueueCallback.updateMediaTapToTransferReceiverDisplay( + StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED, + routeInfo, + null, + null + ) + + verify(windowManager, never()).addView(any(), any()) + assertThat(uiEventLoggerFake.eventId(0)).isEqualTo( + MediaTttReceiverUiEvents.MEDIA_TTT_RECEIVER_TRANSFER_TO_RECEIVER_SUCCEEDED.id + ) + } + + @Test + fun commandQueueCallback_transferToReceiverFailed_noChipShown() { + commandQueueCallback.updateMediaTapToTransferReceiverDisplay( + StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_TRANSFER_TO_RECEIVER_FAILED, + routeInfo, + null, + null + ) + + verify(windowManager, never()).addView(any(), any()) + assertThat(uiEventLoggerFake.eventId(0)).isEqualTo( + MediaTttReceiverUiEvents.MEDIA_TTT_RECEIVER_TRANSFER_TO_RECEIVER_FAILED.id + ) + } + + @Test fun commandQueueCallback_closeThenFar_chipShownThenHidden() { commandQueueCallback.updateMediaTapToTransferReceiverDisplay( StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER, @@ -214,6 +246,48 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() { } @Test + fun commandQueueCallback_closeThenSucceeded_chipShownThenHidden() { + commandQueueCallback.updateMediaTapToTransferReceiverDisplay( + StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER, + routeInfo, + null, + null + ) + + commandQueueCallback.updateMediaTapToTransferReceiverDisplay( + StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED, + routeInfo, + null, + null + ) + + val viewCaptor = ArgumentCaptor.forClass(View::class.java) + verify(windowManager).addView(viewCaptor.capture(), any()) + verify(windowManager).removeView(viewCaptor.value) + } + + @Test + fun commandQueueCallback_closeThenFailed_chipShownThenHidden() { + commandQueueCallback.updateMediaTapToTransferReceiverDisplay( + StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER, + routeInfo, + null, + null + ) + + commandQueueCallback.updateMediaTapToTransferReceiverDisplay( + StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_TRANSFER_TO_RECEIVER_FAILED, + routeInfo, + null, + null + ) + + val viewCaptor = ArgumentCaptor.forClass(View::class.java) + verify(windowManager).addView(viewCaptor.capture(), any()) + verify(windowManager).removeView(viewCaptor.value) + } + + @Test fun commandQueueCallback_closeThenFar_wakeLockAcquiredThenReleased() { commandQueueCallback.updateMediaTapToTransferReceiverDisplay( StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER, diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinatorTest.kt index 311740e17310..b03a545f787f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinatorTest.kt @@ -45,6 +45,7 @@ import com.android.systemui.statusbar.CommandQueue import com.android.systemui.statusbar.VibratorHelper import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.temporarydisplay.chipbar.ChipbarCoordinator +import com.android.systemui.temporarydisplay.chipbar.ChipbarInfo import com.android.systemui.temporarydisplay.chipbar.ChipbarLogger import com.android.systemui.temporarydisplay.chipbar.FakeChipbarCoordinator import com.android.systemui.util.concurrency.FakeExecutor @@ -83,7 +84,7 @@ class MediaTttSenderCoordinatorTest : SysuiTestCase() { @Mock private lateinit var falsingManager: FalsingManager @Mock private lateinit var falsingCollector: FalsingCollector @Mock private lateinit var chipbarLogger: ChipbarLogger - @Mock private lateinit var logger: MediaTttLogger + @Mock private lateinit var logger: MediaTttLogger<ChipbarInfo> @Mock private lateinit var mediaTttFlags: MediaTttFlags @Mock private lateinit var packageManager: PackageManager @Mock private lateinit var powerManager: PowerManager @@ -142,6 +143,7 @@ class MediaTttSenderCoordinatorTest : SysuiTestCase() { viewUtil, vibratorHelper, fakeWakeLockBuilder, + fakeClock, ) chipbarCoordinator.start() diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt index 4d9db8c28e07..58325697a408 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt @@ -518,7 +518,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() { val childHunView = createHunViewMock( isShadeOpen = true, fullyVisible = false, - headerVisibleAmount = 1f + headerVisibleAmount = 1f, ) val algorithmState = StackScrollAlgorithm.StackScrollAlgorithmState() algorithmState.visibleChildren.add(childHunView) @@ -526,7 +526,6 @@ class StackScrollAlgorithmTest : SysuiTestCase() { // When: updateChildZValue() is called for the top HUN stackScrollAlgorithm.updateChildZValue( /* i= */ 0, - /* childrenOnTop= */ 0.0f, /* StackScrollAlgorithmState= */ algorithmState, /* ambientState= */ ambientState, /* shouldElevateHun= */ true @@ -546,7 +545,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() { val childHunView = createHunViewMock( isShadeOpen = true, fullyVisible = false, - headerVisibleAmount = 1f + headerVisibleAmount = 1f, ) // Use half of the HUN's height as overlap childHunView.viewState.yTranslation = (childHunView.viewState.height + 1 shr 1).toFloat() @@ -556,7 +555,6 @@ class StackScrollAlgorithmTest : SysuiTestCase() { // When: updateChildZValue() is called for the top HUN stackScrollAlgorithm.updateChildZValue( /* i= */ 0, - /* childrenOnTop= */ 0.0f, /* StackScrollAlgorithmState= */ algorithmState, /* ambientState= */ ambientState, /* shouldElevateHun= */ true @@ -580,7 +578,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() { val childHunView = createHunViewMock( isShadeOpen = true, fullyVisible = true, - headerVisibleAmount = 1f + headerVisibleAmount = 1f, ) // HUN doesn't overlap with QQS Panel childHunView.viewState.yTranslation = ambientState.topPadding + @@ -591,7 +589,6 @@ class StackScrollAlgorithmTest : SysuiTestCase() { // When: updateChildZValue() is called for the top HUN stackScrollAlgorithm.updateChildZValue( /* i= */ 0, - /* childrenOnTop= */ 0.0f, /* StackScrollAlgorithmState= */ algorithmState, /* ambientState= */ ambientState, /* shouldElevateHun= */ true @@ -611,7 +608,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() { val childHunView = createHunViewMock( isShadeOpen = false, fullyVisible = false, - headerVisibleAmount = 0f + headerVisibleAmount = 0f, ) childHunView.viewState.yTranslation = 0f // Shade is closed, thus childHunView's headerVisibleAmount is 0 @@ -622,7 +619,6 @@ class StackScrollAlgorithmTest : SysuiTestCase() { // When: updateChildZValue() is called for the top HUN stackScrollAlgorithm.updateChildZValue( /* i= */ 0, - /* childrenOnTop= */ 0.0f, /* StackScrollAlgorithmState= */ algorithmState, /* ambientState= */ ambientState, /* shouldElevateHun= */ true @@ -642,7 +638,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() { val childHunView = createHunViewMock( isShadeOpen = false, fullyVisible = false, - headerVisibleAmount = 0.5f + headerVisibleAmount = 0.5f, ) childHunView.viewState.yTranslation = 0f // Shade is being opened, thus childHunView's headerVisibleAmount is between 0 and 1 @@ -654,7 +650,6 @@ class StackScrollAlgorithmTest : SysuiTestCase() { // When: updateChildZValue() is called for the top HUN stackScrollAlgorithm.updateChildZValue( /* i= */ 0, - /* childrenOnTop= */ 0.0f, /* StackScrollAlgorithmState= */ algorithmState, /* ambientState= */ ambientState, /* shouldElevateHun= */ true @@ -669,7 +664,7 @@ class StackScrollAlgorithmTest : SysuiTestCase() { private fun createHunViewMock( isShadeOpen: Boolean, fullyVisible: Boolean, - headerVisibleAmount: Float + headerVisibleAmount: Float, ) = mock<ExpandableNotificationRow>().apply { val childViewStateMock = createHunChildViewState(isShadeOpen, fullyVisible) @@ -680,7 +675,10 @@ class StackScrollAlgorithmTest : SysuiTestCase() { } - private fun createHunChildViewState(isShadeOpen: Boolean, fullyVisible: Boolean) = + private fun createHunChildViewState( + isShadeOpen: Boolean, + fullyVisible: Boolean, + ) = ExpandableViewState().apply { // Mock the HUN's height with ambientState.topPadding + // ambientState.stackTranslation diff --git a/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusUsiPowerStartableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusUsiPowerStartableTest.kt new file mode 100644 index 000000000000..ff382a3ec19f --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusUsiPowerStartableTest.kt @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.stylus + +import android.hardware.BatteryState +import android.hardware.input.InputManager +import android.testing.AndroidTestingRunner +import android.view.InputDevice +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.flags.FeatureFlags +import com.android.systemui.flags.Flags +import com.android.systemui.util.mockito.whenever +import java.util.concurrent.Executor +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito.inOrder +import org.mockito.Mockito.mock +import org.mockito.Mockito.never +import org.mockito.Mockito.times +import org.mockito.Mockito.verify +import org.mockito.Mockito.verifyNoMoreInteractions +import org.mockito.MockitoAnnotations + +@RunWith(AndroidTestingRunner::class) +@SmallTest +class StylusUsiPowerStartableTest : SysuiTestCase() { + @Mock lateinit var inputManager: InputManager + @Mock lateinit var stylusManager: StylusManager + @Mock lateinit var stylusDevice: InputDevice + @Mock lateinit var externalDevice: InputDevice + @Mock lateinit var featureFlags: FeatureFlags + @Mock lateinit var stylusUsiPowerUi: StylusUsiPowerUI + + lateinit var startable: StylusUsiPowerStartable + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + + startable = + StylusUsiPowerStartable( + stylusManager, + inputManager, + stylusUsiPowerUi, + featureFlags, + DIRECT_EXECUTOR, + ) + + whenever(featureFlags.isEnabled(Flags.ENABLE_USI_BATTERY_NOTIFICATIONS)).thenReturn(true) + + whenever(inputManager.getInputDevice(EXTERNAL_DEVICE_ID)).thenReturn(externalDevice) + whenever(inputManager.getInputDevice(STYLUS_DEVICE_ID)).thenReturn(stylusDevice) + whenever(inputManager.inputDeviceIds) + .thenReturn(intArrayOf(EXTERNAL_DEVICE_ID, STYLUS_DEVICE_ID)) + + whenever(stylusDevice.supportsSource(InputDevice.SOURCE_STYLUS)).thenReturn(true) + whenever(stylusDevice.isExternal).thenReturn(false) + whenever(stylusDevice.id).thenReturn(STYLUS_DEVICE_ID) + whenever(externalDevice.supportsSource(InputDevice.SOURCE_STYLUS)).thenReturn(true) + whenever(externalDevice.isExternal).thenReturn(true) + whenever(externalDevice.id).thenReturn(EXTERNAL_DEVICE_ID) + } + + @Test + fun start_addsBatteryListenerForInternalStylus() { + startable.start() + + verify(inputManager, times(1)) + .addInputDeviceBatteryListener(STYLUS_DEVICE_ID, DIRECT_EXECUTOR, startable) + } + + @Test + fun onStylusAdded_internalStylus_addsBatteryListener() { + startable.onStylusAdded(STYLUS_DEVICE_ID) + + verify(inputManager, times(1)) + .addInputDeviceBatteryListener(STYLUS_DEVICE_ID, DIRECT_EXECUTOR, startable) + } + + @Test + fun onStylusAdded_externalStylus_doesNotAddBatteryListener() { + startable.onStylusAdded(EXTERNAL_DEVICE_ID) + + verify(inputManager, never()) + .addInputDeviceBatteryListener(EXTERNAL_DEVICE_ID, DIRECT_EXECUTOR, startable) + } + + @Test + fun onStylusRemoved_registeredStylus_removesBatteryListener() { + startable.onStylusAdded(STYLUS_DEVICE_ID) + startable.onStylusRemoved(STYLUS_DEVICE_ID) + + inOrder(inputManager).let { + it.verify(inputManager, times(1)) + .addInputDeviceBatteryListener(STYLUS_DEVICE_ID, DIRECT_EXECUTOR, startable) + it.verify(inputManager, times(1)) + .removeInputDeviceBatteryListener(STYLUS_DEVICE_ID, startable) + } + } + + @Test + fun onStylusBluetoothConnected_refreshesNotification() { + startable.onStylusBluetoothConnected(STYLUS_DEVICE_ID, "ANY") + + verify(stylusUsiPowerUi, times(1)).refresh() + } + + @Test + fun onStylusBluetoothDisconnected_refreshesNotification() { + startable.onStylusBluetoothDisconnected(STYLUS_DEVICE_ID, "ANY") + + verify(stylusUsiPowerUi, times(1)).refresh() + } + + @Test + fun onBatteryStateChanged_batteryPresent_refreshesNotification() { + val batteryState = mock(BatteryState::class.java) + whenever(batteryState.isPresent).thenReturn(true) + + startable.onBatteryStateChanged(STYLUS_DEVICE_ID, 123, batteryState) + + verify(stylusUsiPowerUi, times(1)).updateBatteryState(batteryState) + } + + @Test + fun onBatteryStateChanged_batteryNotPresent_noop() { + val batteryState = mock(BatteryState::class.java) + whenever(batteryState.isPresent).thenReturn(false) + + startable.onBatteryStateChanged(STYLUS_DEVICE_ID, 123, batteryState) + + verifyNoMoreInteractions(stylusUsiPowerUi) + } + + companion object { + private val DIRECT_EXECUTOR = Executor { r -> r.run() } + + private const val EXTERNAL_DEVICE_ID = 0 + private const val STYLUS_DEVICE_ID = 1 + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusUsiPowerUiTest.kt b/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusUsiPowerUiTest.kt new file mode 100644 index 000000000000..59875507341d --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusUsiPowerUiTest.kt @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.stylus + +import android.hardware.BatteryState +import android.hardware.input.InputManager +import android.os.Handler +import android.testing.AndroidTestingRunner +import android.view.InputDevice +import androidx.core.app.NotificationManagerCompat +import androidx.test.filters.SmallTest +import com.android.systemui.R +import com.android.systemui.SysuiTestCase +import com.android.systemui.util.mockito.any +import com.android.systemui.util.mockito.eq +import com.android.systemui.util.mockito.whenever +import org.junit.Before +import org.junit.Ignore +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito.inOrder +import org.mockito.Mockito.times +import org.mockito.Mockito.verify +import org.mockito.Mockito.verifyNoMoreInteractions +import org.mockito.MockitoAnnotations + +@RunWith(AndroidTestingRunner::class) +@SmallTest +class StylusUsiPowerUiTest : SysuiTestCase() { + @Mock lateinit var notificationManager: NotificationManagerCompat + @Mock lateinit var inputManager: InputManager + @Mock lateinit var handler: Handler + @Mock lateinit var btStylusDevice: InputDevice + + private lateinit var stylusUsiPowerUi: StylusUsiPowerUI + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + + whenever(handler.post(any())).thenAnswer { + (it.arguments[0] as Runnable).run() + true + } + + whenever(inputManager.inputDeviceIds).thenReturn(intArrayOf()) + whenever(inputManager.getInputDevice(0)).thenReturn(btStylusDevice) + whenever(btStylusDevice.supportsSource(InputDevice.SOURCE_STYLUS)).thenReturn(true) + // whenever(btStylusDevice.bluetoothAddress).thenReturn("SO:ME:AD:DR:ES") + + stylusUsiPowerUi = StylusUsiPowerUI(mContext, notificationManager, inputManager, handler) + } + + @Test + fun updateBatteryState_capacityBelowThreshold_notifies() { + stylusUsiPowerUi.updateBatteryState(FixedCapacityBatteryState(0.1f)) + + verify(notificationManager, times(1)).notify(eq(R.string.stylus_battery_low), any()) + verifyNoMoreInteractions(notificationManager) + } + + @Test + fun updateBatteryState_capacityAboveThreshold_cancelsNotificattion() { + stylusUsiPowerUi.updateBatteryState(FixedCapacityBatteryState(0.8f)) + + verify(notificationManager, times(1)).cancel(R.string.stylus_battery_low) + verifyNoMoreInteractions(notificationManager) + } + + @Test + fun updateBatteryState_existingNotification_capacityAboveThreshold_cancelsNotification() { + stylusUsiPowerUi.updateBatteryState(FixedCapacityBatteryState(0.1f)) + stylusUsiPowerUi.updateBatteryState(FixedCapacityBatteryState(0.8f)) + + inOrder(notificationManager).let { + it.verify(notificationManager, times(1)).notify(eq(R.string.stylus_battery_low), any()) + it.verify(notificationManager, times(1)).cancel(R.string.stylus_battery_low) + it.verifyNoMoreInteractions() + } + } + + @Test + fun updateBatteryState_existingNotification_capacityBelowThreshold_updatesNotification() { + stylusUsiPowerUi.updateBatteryState(FixedCapacityBatteryState(0.1f)) + stylusUsiPowerUi.updateBatteryState(FixedCapacityBatteryState(0.15f)) + + verify(notificationManager, times(2)).notify(eq(R.string.stylus_battery_low), any()) + verifyNoMoreInteractions(notificationManager) + } + + @Test + fun updateBatteryState_capacityAboveThenBelowThreshold_hidesThenShowsNotification() { + stylusUsiPowerUi.updateBatteryState(FixedCapacityBatteryState(0.1f)) + stylusUsiPowerUi.updateBatteryState(FixedCapacityBatteryState(0.5f)) + stylusUsiPowerUi.updateBatteryState(FixedCapacityBatteryState(0.1f)) + + inOrder(notificationManager).let { + it.verify(notificationManager, times(1)).notify(eq(R.string.stylus_battery_low), any()) + it.verify(notificationManager, times(1)).cancel(R.string.stylus_battery_low) + it.verify(notificationManager, times(1)).notify(eq(R.string.stylus_battery_low), any()) + it.verifyNoMoreInteractions() + } + } + + @Test + fun updateSuppression_noExistingNotification_cancelsNotification() { + stylusUsiPowerUi.updateSuppression(true) + + verify(notificationManager, times(1)).cancel(R.string.stylus_battery_low) + verifyNoMoreInteractions(notificationManager) + } + + @Test + fun updateSuppression_existingNotification_cancelsNotification() { + stylusUsiPowerUi.updateBatteryState(FixedCapacityBatteryState(0.1f)) + + stylusUsiPowerUi.updateSuppression(true) + + inOrder(notificationManager).let { + it.verify(notificationManager, times(1)).notify(eq(R.string.stylus_battery_low), any()) + it.verify(notificationManager, times(1)).cancel(R.string.stylus_battery_low) + it.verifyNoMoreInteractions() + } + } + + @Test + @Ignore("TODO(b/257936830): get bt address once input api available") + fun refresh_hasConnectedBluetoothStylus_doesNotNotify() { + whenever(inputManager.inputDeviceIds).thenReturn(intArrayOf(0)) + + stylusUsiPowerUi.refresh() + + verifyNoMoreInteractions(notificationManager) + } + + @Test + @Ignore("TODO(b/257936830): get bt address once input api available") + fun refresh_hasConnectedBluetoothStylus_existingNotification_cancelsNotification() { + stylusUsiPowerUi.updateBatteryState(FixedCapacityBatteryState(0.1f)) + whenever(inputManager.inputDeviceIds).thenReturn(intArrayOf(0)) + + stylusUsiPowerUi.refresh() + + verify(notificationManager).cancel(R.string.stylus_battery_low) + } + + class FixedCapacityBatteryState(private val capacity: Float) : BatteryState() { + override fun getCapacity() = capacity + override fun getStatus() = 0 + override fun isPresent() = true + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt index 09f0d4a10410..82153d5610a5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt @@ -35,6 +35,7 @@ import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.argumentCaptor import com.android.systemui.util.mockito.capture import com.android.systemui.util.time.FakeSystemClock +import com.android.systemui.util.time.SystemClock import com.android.systemui.util.wakelock.WakeLock import com.android.systemui.util.wakelock.WakeLockFake import com.google.common.truth.Truth.assertThat @@ -59,7 +60,7 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() { private lateinit var fakeWakeLock: WakeLockFake @Mock - private lateinit var logger: TemporaryViewLogger + private lateinit var logger: TemporaryViewLogger<ViewInfo> @Mock private lateinit var accessibilityManager: AccessibilityManager @Mock @@ -74,7 +75,7 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() { MockitoAnnotations.initMocks(this) whenever(accessibilityManager.getRecommendedTimeoutMillis(any(), any())) - .thenReturn(TIMEOUT_MS.toInt()) + .thenAnswer { it.arguments[0] } fakeClock = FakeSystemClock() fakeExecutor = FakeExecutor(fakeClock) @@ -84,14 +85,15 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() { fakeWakeLockBuilder.setWakeLock(fakeWakeLock) underTest = TestController( - context, - logger, - windowManager, - fakeExecutor, - accessibilityManager, - configurationController, - powerManager, - fakeWakeLockBuilder, + context, + logger, + windowManager, + fakeExecutor, + accessibilityManager, + configurationController, + powerManager, + fakeWakeLockBuilder, + fakeClock, ) underTest.start() } @@ -112,14 +114,14 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() { @Test fun displayView_logged() { - underTest.displayView( - ViewInfo( - name = "name", - windowTitle = "Fake Window Title", - ) + val info = ViewInfo( + name = "name", + windowTitle = "Fake Window Title", ) - verify(logger).logViewAddition("id", "Fake Window Title") + underTest.displayView(info) + + verify(logger).logViewAddition(info) } @Test @@ -168,10 +170,11 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() { } @Test - fun displayView_twiceWithDifferentWindowTitles_oldViewRemovedNewViewAdded() { + fun displayView_twiceWithDifferentIds_oldViewRemovedNewViewAdded() { underTest.displayView( ViewInfo( name = "name", + id = "First", windowTitle = "First Fake Window Title", ) ) @@ -179,6 +182,7 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() { underTest.displayView( ViewInfo( name = "name", + id = "Second", windowTitle = "Second Fake Window Title", ) ) @@ -263,19 +267,69 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() { } @Test + fun viewUpdatedWithNewOnViewTimeoutRunnable_newRunnableUsed() { + var runnable1Run = false + underTest.displayView(ViewInfo(name = "name", id = "id1", windowTitle = "1")) { + runnable1Run = true + } + + var runnable2Run = false + underTest.displayView(ViewInfo(name = "name", id = "id1", windowTitle = "1")) { + runnable2Run = true + } + + fakeClock.advanceTime(TIMEOUT_MS + 1) + + assertThat(runnable1Run).isFalse() + assertThat(runnable2Run).isTrue() + } + + @Test + fun multipleViewsWithDifferentIds_moreRecentReplacesOlder() { + underTest.displayView( + ViewInfo( + name = "name", + windowTitle = "First Fake Window Title", + id = "id1" + ) + ) + + underTest.displayView( + ViewInfo( + name = "name", + windowTitle = "Second Fake Window Title", + id = "id2" + ) + ) + + val viewCaptor = argumentCaptor<View>() + val windowParamsCaptor = argumentCaptor<WindowManager.LayoutParams>() + + verify(windowManager, times(2)).addView(capture(viewCaptor), capture(windowParamsCaptor)) + + assertThat(windowParamsCaptor.allValues[0].title).isEqualTo("First Fake Window Title") + assertThat(windowParamsCaptor.allValues[1].title).isEqualTo("Second Fake Window Title") + verify(windowManager).removeView(viewCaptor.allValues[0]) + verify(configurationController, never()).removeCallback(any()) + } + + @Test fun multipleViewsWithDifferentIds_recentActiveViewIsDisplayed() { underTest.displayView(ViewInfo("First name", id = "id1")) verify(windowManager).addView(any(), any()) - reset(windowManager) + underTest.displayView(ViewInfo("Second name", id = "id2")) - underTest.removeView("id2", "test reason") verify(windowManager).removeView(any()) + verify(windowManager).addView(any(), any()) + reset(windowManager) - fakeClock.advanceTime(DISPLAY_VIEW_DELAY + 1) + underTest.removeView("id2", "test reason") + verify(windowManager).removeView(any()) + verify(windowManager).addView(any(), any()) assertThat(underTest.mostRecentViewInfo?.id).isEqualTo("id1") assertThat(underTest.mostRecentViewInfo?.name).isEqualTo("First name") @@ -284,6 +338,7 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() { verify(windowManager).removeView(any()) assertThat(underTest.activeViews.size).isEqualTo(0) + verify(configurationController).removeCallback(any()) } @Test @@ -291,19 +346,28 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() { underTest.displayView(ViewInfo("First name", id = "id1")) verify(windowManager).addView(any(), any()) - reset(windowManager) + underTest.displayView(ViewInfo("Second name", id = "id2")) + + verify(windowManager).removeView(any()) + verify(windowManager).addView(any(), any()) + reset(windowManager) + + // WHEN an old view is removed underTest.removeView("id1", "test reason") + // THEN we don't update anything verify(windowManager, never()).removeView(any()) assertThat(underTest.mostRecentViewInfo?.id).isEqualTo("id2") assertThat(underTest.mostRecentViewInfo?.name).isEqualTo("Second name") + verify(configurationController, never()).removeCallback(any()) fakeClock.advanceTime(TIMEOUT_MS + 1) verify(windowManager).removeView(any()) assertThat(underTest.activeViews.size).isEqualTo(0) + verify(configurationController).removeCallback(any()) } @Test @@ -312,33 +376,31 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() { underTest.displayView(ViewInfo("Second name", id = "id2")) underTest.displayView(ViewInfo("Third name", id = "id3")) - verify(windowManager).addView(any(), any()) + verify(windowManager, times(3)).addView(any(), any()) + verify(windowManager, times(2)).removeView(any()) reset(windowManager) underTest.removeView("id3", "test reason") verify(windowManager).removeView(any()) - - fakeClock.advanceTime(DISPLAY_VIEW_DELAY + 1) - assertThat(underTest.mostRecentViewInfo?.id).isEqualTo("id2") assertThat(underTest.mostRecentViewInfo?.name).isEqualTo("Second name") + verify(configurationController, never()).removeCallback(any()) reset(windowManager) underTest.removeView("id2", "test reason") verify(windowManager).removeView(any()) - - fakeClock.advanceTime(DISPLAY_VIEW_DELAY + 1) - assertThat(underTest.mostRecentViewInfo?.id).isEqualTo("id1") assertThat(underTest.mostRecentViewInfo?.name).isEqualTo("First name") + verify(configurationController, never()).removeCallback(any()) reset(windowManager) fakeClock.advanceTime(TIMEOUT_MS + 1) verify(windowManager).removeView(any()) assertThat(underTest.activeViews.size).isEqualTo(0) + verify(configurationController).removeCallback(any()) } @Test @@ -347,18 +409,21 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() { underTest.displayView(ViewInfo("New name", id = "id1")) verify(windowManager).addView(any(), any()) - reset(windowManager) + underTest.displayView(ViewInfo("Second name", id = "id2")) - underTest.removeView("id2", "test reason") verify(windowManager).removeView(any()) + verify(windowManager).addView(any(), any()) + reset(windowManager) - fakeClock.advanceTime(DISPLAY_VIEW_DELAY + 1) + underTest.removeView("id2", "test reason") + verify(windowManager).removeView(any()) + verify(windowManager).addView(any(), any()) assertThat(underTest.mostRecentViewInfo?.id).isEqualTo("id1") assertThat(underTest.mostRecentViewInfo?.name).isEqualTo("New name") - assertThat(underTest.activeViews[0].second.name).isEqualTo("New name") + assertThat(underTest.activeViews[0].info.name).isEqualTo("New name") reset(windowManager) fakeClock.advanceTime(TIMEOUT_MS + 1) @@ -368,19 +433,523 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() { } @Test - fun multipleViewsWithDifferentIds_viewsTimeouts_noViewLeftToDisplay() { - underTest.displayView(ViewInfo("First name", id = "id1")) - fakeClock.advanceTime(TIMEOUT_MS / 3) - underTest.displayView(ViewInfo("Second name", id = "id2")) - fakeClock.advanceTime(TIMEOUT_MS / 3) - underTest.displayView(ViewInfo("Third name", id = "id3")) + fun multipleViews_mostRecentViewRemoved_otherViewsTimedOutAndNotDisplayed() { + underTest.displayView(ViewInfo("First name", id = "id1", timeoutMs = 4000)) + fakeClock.advanceTime(1000) + underTest.displayView(ViewInfo("Second name", id = "id2", timeoutMs = 4000)) + fakeClock.advanceTime(1000) + underTest.displayView(ViewInfo("Third name", id = "id3", timeoutMs = 20000)) reset(windowManager) - fakeClock.advanceTime(TIMEOUT_MS + 1) + fakeClock.advanceTime(20000 + 1) verify(windowManager).removeView(any()) verify(windowManager, never()).addView(any(), any()) assertThat(underTest.activeViews.size).isEqualTo(0) + verify(configurationController).removeCallback(any()) + } + + @Test + fun multipleViews_mostRecentViewRemoved_viewWithShortTimeLeftNotDisplayed() { + underTest.displayView(ViewInfo("First name", id = "id1", timeoutMs = 4000)) + fakeClock.advanceTime(1000) + underTest.displayView(ViewInfo("Second name", id = "id2", timeoutMs = 2500)) + + reset(windowManager) + fakeClock.advanceTime(2500 + 1) + // At this point, 3501ms have passed, so id1 only has 499ms left which is not enough. + // So, it shouldn't be displayed. + + verify(windowManager, never()).addView(any(), any()) + assertThat(underTest.activeViews.size).isEqualTo(0) + verify(configurationController).removeCallback(any()) + } + + @Test + fun lowerThenHigherPriority_higherReplacesLower() { + underTest.displayView( + ViewInfo( + name = "normal", + windowTitle = "Normal Window Title", + id = "normal", + priority = ViewPriority.NORMAL, + ) + ) + + val viewCaptor = argumentCaptor<View>() + val windowParamsCaptor = argumentCaptor<WindowManager.LayoutParams>() + verify(windowManager).addView(capture(viewCaptor), capture(windowParamsCaptor)) + assertThat(windowParamsCaptor.value.title).isEqualTo("Normal Window Title") + reset(windowManager) + + underTest.displayView( + ViewInfo( + name = "critical", + windowTitle = "Critical Window Title", + id = "critical", + priority = ViewPriority.CRITICAL, + ) + ) + + verify(windowManager).removeView(viewCaptor.value) + verify(windowManager).addView(capture(viewCaptor), capture(windowParamsCaptor)) + assertThat(windowParamsCaptor.value.title).isEqualTo("Critical Window Title") + verify(configurationController, never()).removeCallback(any()) + } + + @Test + fun lowerThenHigherPriority_lowerPriorityRedisplayed() { + underTest.displayView( + ViewInfo( + name = "normal", + windowTitle = "Normal Window Title", + id = "normal", + priority = ViewPriority.NORMAL, + timeoutMs = 10000 + ) + ) + + underTest.displayView( + ViewInfo( + name = "critical", + windowTitle = "Critical Window Title", + id = "critical", + priority = ViewPriority.CRITICAL, + timeoutMs = 2000 + ) + ) + + val viewCaptor = argumentCaptor<View>() + val windowParamsCaptor = argumentCaptor<WindowManager.LayoutParams>() + verify(windowManager, times(2)).addView(capture(viewCaptor), capture(windowParamsCaptor)) + assertThat(windowParamsCaptor.allValues[0].title).isEqualTo("Normal Window Title") + assertThat(windowParamsCaptor.allValues[1].title).isEqualTo("Critical Window Title") + verify(windowManager).removeView(viewCaptor.allValues[0]) + + reset(windowManager) + + // WHEN the critical's timeout has expired + fakeClock.advanceTime(2000 + 1) + + // THEN the normal view is re-displayed + verify(windowManager).removeView(viewCaptor.allValues[1]) + verify(windowManager).addView(any(), capture(windowParamsCaptor)) + assertThat(windowParamsCaptor.value.title).isEqualTo("Normal Window Title") + verify(configurationController, never()).removeCallback(any()) + } + + @Test + fun lowerThenHigherPriority_lowerPriorityNotRedisplayedBecauseTimedOut() { + underTest.displayView( + ViewInfo( + name = "normal", + windowTitle = "Normal Window Title", + id = "normal", + priority = ViewPriority.NORMAL, + timeoutMs = 1000 + ) + ) + + underTest.displayView( + ViewInfo( + name = "critical", + windowTitle = "Critical Window Title", + id = "critical", + priority = ViewPriority.CRITICAL, + timeoutMs = 2000 + ) + ) + reset(windowManager) + + // WHEN the critical's timeout has expired + fakeClock.advanceTime(2000 + 1) + + // THEN the normal view is not re-displayed since it already timed out + verify(windowManager).removeView(any()) + verify(windowManager, never()).addView(any(), any()) + assertThat(underTest.activeViews).isEmpty() + verify(configurationController).removeCallback(any()) + } + + @Test + fun higherThenLowerPriority_higherStaysDisplayed() { + underTest.displayView( + ViewInfo( + name = "critical", + windowTitle = "Critical Window Title", + id = "critical", + priority = ViewPriority.CRITICAL, + ) + ) + + val viewCaptor = argumentCaptor<View>() + val windowParamsCaptor = argumentCaptor<WindowManager.LayoutParams>() + verify(windowManager).addView(capture(viewCaptor), capture(windowParamsCaptor)) + assertThat(windowParamsCaptor.value.title).isEqualTo("Critical Window Title") + reset(windowManager) + + underTest.displayView( + ViewInfo( + name = "normal", + windowTitle = "Normal Window Title", + id = "normal", + priority = ViewPriority.NORMAL, + ) + ) + + verify(windowManager, never()).removeView(viewCaptor.value) + verify(windowManager, never()).addView(any(), any()) + assertThat(underTest.activeViews.size).isEqualTo(2) + verify(configurationController, never()).removeCallback(any()) + } + + @Test + fun higherThenLowerPriority_lowerEventuallyDisplayed() { + underTest.displayView( + ViewInfo( + name = "critical", + windowTitle = "Critical Window Title", + id = "critical", + priority = ViewPriority.CRITICAL, + timeoutMs = 3000, + ) + ) + + val viewCaptor = argumentCaptor<View>() + val windowParamsCaptor = argumentCaptor<WindowManager.LayoutParams>() + verify(windowManager).addView(capture(viewCaptor), capture(windowParamsCaptor)) + assertThat(windowParamsCaptor.value.title).isEqualTo("Critical Window Title") + reset(windowManager) + + underTest.displayView( + ViewInfo( + name = "normal", + windowTitle = "Normal Window Title", + id = "normal", + priority = ViewPriority.NORMAL, + timeoutMs = 5000, + ) + ) + + verify(windowManager, never()).removeView(viewCaptor.value) + verify(windowManager, never()).addView(any(), any()) + assertThat(underTest.activeViews.size).isEqualTo(2) + + // WHEN the first critical view has timed out + fakeClock.advanceTime(3000 + 1) + + // THEN the second normal view is displayed + verify(windowManager).removeView(viewCaptor.value) + verify(windowManager).addView(capture(viewCaptor), capture(windowParamsCaptor)) + assertThat(windowParamsCaptor.value.title).isEqualTo("Normal Window Title") + assertThat(underTest.activeViews.size).isEqualTo(1) + verify(configurationController, never()).removeCallback(any()) + } + + @Test + fun higherThenLowerPriority_lowerNotDisplayedBecauseTimedOut() { + underTest.displayView( + ViewInfo( + name = "critical", + windowTitle = "Critical Window Title", + id = "critical", + priority = ViewPriority.CRITICAL, + timeoutMs = 3000, + ) + ) + + val viewCaptor = argumentCaptor<View>() + val windowParamsCaptor = argumentCaptor<WindowManager.LayoutParams>() + verify(windowManager).addView(capture(viewCaptor), capture(windowParamsCaptor)) + assertThat(windowParamsCaptor.value.title).isEqualTo("Critical Window Title") + reset(windowManager) + + underTest.displayView( + ViewInfo( + name = "normal", + windowTitle = "Normal Window Title", + id = "normal", + priority = ViewPriority.NORMAL, + timeoutMs = 200, + ) + ) + + verify(windowManager, never()).removeView(viewCaptor.value) + verify(windowManager, never()).addView(any(), any()) + assertThat(underTest.activeViews.size).isEqualTo(2) + reset(windowManager) + + // WHEN the first critical view has timed out + fakeClock.advanceTime(3000 + 1) + + // THEN the second normal view is not displayed because it's already timed out + verify(windowManager).removeView(viewCaptor.value) + verify(windowManager, never()).addView(any(), any()) + assertThat(underTest.activeViews).isEmpty() + verify(configurationController).removeCallback(any()) + } + + @Test + fun criticalThenNewCritical_newCriticalDisplayed() { + underTest.displayView( + ViewInfo( + name = "critical 1", + windowTitle = "Critical Window Title 1", + id = "critical1", + priority = ViewPriority.CRITICAL, + ) + ) + + val viewCaptor = argumentCaptor<View>() + val windowParamsCaptor = argumentCaptor<WindowManager.LayoutParams>() + verify(windowManager).addView(capture(viewCaptor), capture(windowParamsCaptor)) + assertThat(windowParamsCaptor.value.title).isEqualTo("Critical Window Title 1") + reset(windowManager) + + underTest.displayView( + ViewInfo( + name = "critical 2", + windowTitle = "Critical Window Title 2", + id = "critical2", + priority = ViewPriority.CRITICAL, + ) + ) + + verify(windowManager).removeView(viewCaptor.value) + verify(windowManager).addView(capture(viewCaptor), capture(windowParamsCaptor)) + assertThat(windowParamsCaptor.value.title).isEqualTo("Critical Window Title 2") + assertThat(underTest.activeViews.size).isEqualTo(2) + verify(configurationController, never()).removeCallback(any()) + } + + @Test + fun normalThenNewNormal_newNormalDisplayed() { + underTest.displayView( + ViewInfo( + name = "normal 1", + windowTitle = "Normal Window Title 1", + id = "normal1", + priority = ViewPriority.NORMAL, + ) + ) + + val viewCaptor = argumentCaptor<View>() + val windowParamsCaptor = argumentCaptor<WindowManager.LayoutParams>() + verify(windowManager).addView(capture(viewCaptor), capture(windowParamsCaptor)) + assertThat(windowParamsCaptor.value.title).isEqualTo("Normal Window Title 1") + reset(windowManager) + + underTest.displayView( + ViewInfo( + name = "normal 2", + windowTitle = "Normal Window Title 2", + id = "normal2", + priority = ViewPriority.NORMAL, + ) + ) + + verify(windowManager).removeView(viewCaptor.value) + verify(windowManager).addView(capture(viewCaptor), capture(windowParamsCaptor)) + assertThat(windowParamsCaptor.value.title).isEqualTo("Normal Window Title 2") + assertThat(underTest.activeViews.size).isEqualTo(2) + verify(configurationController, never()).removeCallback(any()) + } + + @Test + fun lowerPriorityViewUpdatedWhileHigherPriorityDisplayed_eventuallyDisplaysUpdated() { + // First, display a lower priority view + underTest.displayView( + ViewInfo( + name = "normal", + windowTitle = "Normal Window Title", + id = "normal", + priority = ViewPriority.NORMAL, + // At the end of the test, we'll verify that this information isn't re-displayed. + // Use a super long timeout so that, when we verify it wasn't re-displayed, we know + // that it wasn't because the view just timed out. + timeoutMs = 100000, + ) + ) + + val viewCaptor = argumentCaptor<View>() + val windowParamsCaptor = argumentCaptor<WindowManager.LayoutParams>() + verify(windowManager).addView(capture(viewCaptor), capture(windowParamsCaptor)) + assertThat(windowParamsCaptor.value.title).isEqualTo("Normal Window Title") + reset(windowManager) + + // Then, display a higher priority view + fakeClock.advanceTime(1000) + underTest.displayView( + ViewInfo( + name = "critical", + windowTitle = "Critical Window Title", + id = "critical", + priority = ViewPriority.CRITICAL, + timeoutMs = 3000, + ) + ) + + verify(windowManager).removeView(viewCaptor.value) + verify(windowManager).addView(capture(viewCaptor), capture(windowParamsCaptor)) + assertThat(windowParamsCaptor.value.title).isEqualTo("Critical Window Title") + assertThat(underTest.activeViews.size).isEqualTo(2) + reset(windowManager) + + // While the higher priority view is displayed, update the lower priority view with new + // information + fakeClock.advanceTime(1000) + val updatedViewInfo = ViewInfo( + name = "normal with update", + windowTitle = "Normal Window Title", + id = "normal", + priority = ViewPriority.NORMAL, + timeoutMs = 4000, + ) + underTest.displayView(updatedViewInfo) + + verify(windowManager, never()).removeView(viewCaptor.value) + verify(windowManager, never()).addView(any(), any()) + assertThat(underTest.activeViews.size).isEqualTo(2) + reset(windowManager) + + // WHEN the higher priority view times out + fakeClock.advanceTime(2001) + + // THEN the higher priority view disappears and the lower priority view *with the updated + // information* gets displayed. + verify(windowManager).removeView(viewCaptor.value) + verify(windowManager).addView(capture(viewCaptor), capture(windowParamsCaptor)) + assertThat(windowParamsCaptor.value.title).isEqualTo("Normal Window Title") + assertThat(underTest.activeViews.size).isEqualTo(1) + assertThat(underTest.mostRecentViewInfo).isEqualTo(updatedViewInfo) + reset(windowManager) + + // WHEN the updated view times out + fakeClock.advanceTime(2001) + + // THEN the old information is never displayed + verify(windowManager).removeView(viewCaptor.value) + verify(windowManager, never()).addView(any(), any()) + assertThat(underTest.activeViews.size).isEqualTo(0) + } + + @Test + fun oldViewUpdatedWhileNewViewDisplayed_eventuallyDisplaysUpdated() { + // First, display id1 view + underTest.displayView( + ViewInfo( + name = "name 1", + windowTitle = "Name 1 Title", + id = "id1", + priority = ViewPriority.NORMAL, + // At the end of the test, we'll verify that this information isn't re-displayed. + // Use a super long timeout so that, when we verify it wasn't re-displayed, we know + // that it wasn't because the view just timed out. + timeoutMs = 100000, + ) + ) + + val viewCaptor = argumentCaptor<View>() + val windowParamsCaptor = argumentCaptor<WindowManager.LayoutParams>() + verify(windowManager).addView(capture(viewCaptor), capture(windowParamsCaptor)) + assertThat(windowParamsCaptor.value.title).isEqualTo("Name 1 Title") + reset(windowManager) + + // Then, display a new id2 view + fakeClock.advanceTime(1000) + underTest.displayView( + ViewInfo( + name = "name 2", + windowTitle = "Name 2 Title", + id = "id2", + priority = ViewPriority.NORMAL, + timeoutMs = 3000, + ) + ) + + verify(windowManager).removeView(viewCaptor.value) + verify(windowManager).addView(capture(viewCaptor), capture(windowParamsCaptor)) + assertThat(windowParamsCaptor.value.title).isEqualTo("Name 2 Title") + assertThat(underTest.activeViews.size).isEqualTo(2) + reset(windowManager) + + // While the id2 view is displayed, re-display the id1 view with new information + fakeClock.advanceTime(1000) + val updatedViewInfo = ViewInfo( + name = "name 1 with update", + windowTitle = "Name 1 Title", + id = "id1", + priority = ViewPriority.NORMAL, + timeoutMs = 3000, + ) + underTest.displayView(updatedViewInfo) + + verify(windowManager).removeView(viewCaptor.value) + verify(windowManager).addView(capture(viewCaptor), capture(windowParamsCaptor)) + assertThat(windowParamsCaptor.value.title).isEqualTo("Name 1 Title") + assertThat(underTest.activeViews.size).isEqualTo(2) + reset(windowManager) + + // WHEN the id1 view with new information times out + fakeClock.advanceTime(3001) + + // THEN the id1 view disappears and the old id1 information is never displayed + verify(windowManager).removeView(viewCaptor.value) + verify(windowManager, never()).addView(any(), any()) + assertThat(underTest.activeViews.size).isEqualTo(0) + } + + @Test + fun oldViewUpdatedWhileNewViewDisplayed_usesNewTimeout() { + // First, display id1 view + underTest.displayView( + ViewInfo( + name = "name 1", + windowTitle = "Name 1 Title", + id = "id1", + priority = ViewPriority.NORMAL, + timeoutMs = 5000, + ) + ) + + // Then, display a new id2 view + fakeClock.advanceTime(1000) + underTest.displayView( + ViewInfo( + name = "name 2", + windowTitle = "Name 2 Title", + id = "id2", + priority = ViewPriority.NORMAL, + timeoutMs = 3000, + ) + ) + reset(windowManager) + + // While the id2 view is displayed, re-display the id1 view with new information *and a + // longer timeout* + fakeClock.advanceTime(1000) + val updatedViewInfo = ViewInfo( + name = "name 1 with update", + windowTitle = "Name 1 Title", + id = "id1", + priority = ViewPriority.NORMAL, + timeoutMs = 30000, + ) + underTest.displayView(updatedViewInfo) + + val viewCaptor = argumentCaptor<View>() + val windowParamsCaptor = argumentCaptor<WindowManager.LayoutParams>() + verify(windowManager).addView(capture(viewCaptor), capture(windowParamsCaptor)) + assertThat(windowParamsCaptor.value.title).isEqualTo("Name 1 Title") + assertThat(underTest.activeViews.size).isEqualTo(2) + reset(windowManager) + + // WHEN id1's *old* timeout occurs + fakeClock.advanceTime(3001) + + // THEN id1 is still displayed because it was updated with a new timeout + verify(windowManager, never()).removeView(viewCaptor.value) + assertThat(underTest.activeViews.size).isEqualTo(1) } @Test @@ -395,6 +964,7 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() { verify(windowManager).removeView(any()) verify(logger).logViewRemoval(deviceId, reason) + verify(configurationController).removeCallback(any()) } @Test @@ -414,14 +984,15 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() { inner class TestController( context: Context, - logger: TemporaryViewLogger, + logger: TemporaryViewLogger<ViewInfo>, windowManager: WindowManager, @Main mainExecutor: DelayableExecutor, accessibilityManager: AccessibilityManager, configurationController: ConfigurationController, powerManager: PowerManager, wakeLockBuilder: WakeLock.Builder, - ) : TemporaryViewDisplayController<ViewInfo, TemporaryViewLogger>( + systemClock: SystemClock, + ) : TemporaryViewDisplayController<ViewInfo, TemporaryViewLogger<ViewInfo>>( context, logger, windowManager, @@ -431,6 +1002,7 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() { powerManager, R.layout.chipbar, wakeLockBuilder, + systemClock, ) { var mostRecentViewInfo: ViewInfo? = null @@ -447,12 +1019,13 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() { override fun start() {} } - inner class ViewInfo( + data class ViewInfo( val name: String, override val windowTitle: String = "Window Title", override val wakeReason: String = "WAKE_REASON", - override val timeoutMs: Int = 1, + override val timeoutMs: Int = TIMEOUT_MS.toInt(), override val id: String = "id", + override val priority: ViewPriority = ViewPriority.NORMAL, ) : TemporaryViewInfo() } diff --git a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewLoggerTest.kt index 116b8fe62b37..2e66b205bfd5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewLoggerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewLoggerTest.kt @@ -32,7 +32,7 @@ import org.mockito.Mockito @SmallTest class TemporaryViewLoggerTest : SysuiTestCase() { private lateinit var buffer: LogBuffer - private lateinit var logger: TemporaryViewLogger + private lateinit var logger: TemporaryViewLogger<TemporaryViewInfo> @Before fun setUp() { @@ -44,13 +44,22 @@ class TemporaryViewLoggerTest : SysuiTestCase() { @Test fun logViewAddition_bufferHasLog() { - logger.logViewAddition("test id", "Test Window Title") + val info = + object : TemporaryViewInfo() { + override val id: String = "test id" + override val priority: ViewPriority = ViewPriority.CRITICAL + override val windowTitle: String = "Test Window Title" + override val wakeReason: String = "wake reason" + } + + logger.logViewAddition(info) val stringWriter = StringWriter() buffer.dump(PrintWriter(stringWriter), tailLength = 0) val actualString = stringWriter.toString() assertThat(actualString).contains(TAG) + assertThat(actualString).contains("test id") assertThat(actualString).contains("Test Window Title") } diff --git a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt index 7014f93fba4a..2e4d8e74ad6e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt @@ -39,6 +39,7 @@ import com.android.systemui.common.shared.model.TintedIcon import com.android.systemui.plugins.FalsingManager import com.android.systemui.statusbar.VibratorHelper import com.android.systemui.statusbar.policy.ConfigurationController +import com.android.systemui.temporarydisplay.ViewPriority import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.eq @@ -105,6 +106,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() { viewUtil, vibratorHelper, fakeWakeLockBuilder, + fakeClock, ) underTest.start() } @@ -408,6 +410,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() { wakeReason = WAKE_REASON, timeoutMs = TIMEOUT, id = DEVICE_ID, + priority = ViewPriority.NORMAL, ) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/FakeChipbarCoordinator.kt b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/FakeChipbarCoordinator.kt index beedf9f337bc..d5167b3890b9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/FakeChipbarCoordinator.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/FakeChipbarCoordinator.kt @@ -26,6 +26,7 @@ import com.android.systemui.plugins.FalsingManager import com.android.systemui.statusbar.VibratorHelper import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.util.concurrency.DelayableExecutor +import com.android.systemui.util.time.SystemClock import com.android.systemui.util.view.ViewUtil import com.android.systemui.util.wakelock.WakeLock @@ -43,6 +44,7 @@ class FakeChipbarCoordinator( viewUtil: ViewUtil, vibratorHelper: VibratorHelper, wakeLockBuilder: WakeLock.Builder, + systemClock: SystemClock, ) : ChipbarCoordinator( context, @@ -57,6 +59,7 @@ class FakeChipbarCoordinator( viewUtil, vibratorHelper, wakeLockBuilder, + systemClock, ) { override fun animateViewOut(view: ViewGroup, onAnimationEnd: Runnable) { // Just bypass the animation in tests diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index 5c11e2c2327e..60890d529ef2 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -24,6 +24,7 @@ import static android.service.autofill.FillEventHistory.Event.UI_TYPE_MENU; import static android.service.autofill.FillEventHistory.Event.UI_TYPE_UNKNOWN; import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST; import static android.service.autofill.FillRequest.FLAG_PASSWORD_INPUT_TYPE; +import static android.service.autofill.FillRequest.FLAG_RESET_FILL_DIALOG_STATE; import static android.service.autofill.FillRequest.FLAG_SUPPORTS_FILL_DIALOG; import static android.service.autofill.FillRequest.FLAG_VIEW_NOT_FOCUSED; import static android.service.autofill.FillRequest.INVALID_REQUEST_ID; @@ -411,6 +412,14 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState @GuardedBy("mLock") private boolean mStartedLogEventWithoutFocus; + /** + * Keeps the fill dialog trigger ids of the last response. This invalidates + * the trigger ids of the previous response. + */ + @Nullable + @GuardedBy("mLock") + private AutofillId[] mLastFillDialogTriggerIds; + void onSwitchInputMethodLocked() { // One caveat is that for the case where the focus is on a field for which regular autofill // returns null, and augmented autofill is triggered, and then the user switches the input @@ -1171,6 +1180,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState return; } + mLastFillDialogTriggerIds = response.getFillDialogTriggerIds(); + final int flags = response.getFlags(); if ((flags & FillResponse.FLAG_DELAY_FILL) != 0) { Slog.v(TAG, "Service requested to wait for delayed fill response."); @@ -1277,6 +1288,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState + (timedOut ? "timeout" : "failure")); } mService.resetLastResponse(); + mLastFillDialogTriggerIds = null; final LogMaker requestLog = mRequestLogs.get(requestId); if (requestLog == null) { Slog.w(TAG, "onFillRequestFailureOrTimeout(): no log for id " + requestId); @@ -2973,6 +2985,11 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } } + if ((flags & FLAG_RESET_FILL_DIALOG_STATE) != 0) { + if (sDebug) Log.d(TAG, "force to reset fill dialog state"); + mSessionFlags.mFillDialogDisabled = false; + } + switch(action) { case ACTION_START_SESSION: // View is triggering autofill. @@ -3402,10 +3419,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } private boolean isFillDialogUiEnabled() { - // TODO read from Settings or somewhere - final boolean isSettingsEnabledFillDialog = true; synchronized (mLock) { - return isSettingsEnabledFillDialog && !mSessionFlags.mFillDialogDisabled; + return !mSessionFlags.mFillDialogDisabled; } } @@ -3431,14 +3446,25 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState AutofillId filledId, String filterText, int flags) { if (!isFillDialogUiEnabled()) { // Unsupported fill dialog UI + if (sDebug) Log.w(TAG, "requestShowFillDialog: fill dialog is disabled"); return false; } if ((flags & FillRequest.FLAG_IME_SHOWING) != 0) { // IME is showing, fallback to normal suggestions UI + if (sDebug) Log.w(TAG, "requestShowFillDialog: IME is showing"); return false; } + synchronized (mLock) { + if (mLastFillDialogTriggerIds == null + || !ArrayUtils.contains(mLastFillDialogTriggerIds, filledId)) { + // Last fill dialog triggered ids are changed. + if (sDebug) Log.w(TAG, "Last fill dialog triggered ids are changed."); + return false; + } + } + final Drawable serviceIcon = getServiceIcon(); getUiForShowing().showFillDialog(filledId, response, filterText, @@ -4278,6 +4304,13 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState if (mSessionFlags.mAugmentedAutofillOnly) { pw.print(prefix); pw.println("For Augmented Autofill Only"); } + if (mSessionFlags.mFillDialogDisabled) { + pw.print(prefix); pw.println("Fill Dialog disabled"); + } + if (mLastFillDialogTriggerIds != null) { + pw.print(prefix); pw.println("Last Fill Dialog trigger ids: "); + pw.println(mSelectedDatasetIds); + } if (mAugmentedAutofillDestroyer != null) { pw.print(prefix); pw.println("has mAugmentedAutofillDestroyer"); } diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java index 2be2d584f9a3..401d184dd7fb 100644 --- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java +++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java @@ -36,16 +36,19 @@ import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.display.BrightnessSynchronizer; import com.android.server.display.config.AutoBrightness; +import com.android.server.display.config.BlockingZoneConfig; import com.android.server.display.config.BrightnessThresholds; import com.android.server.display.config.BrightnessThrottlingMap; import com.android.server.display.config.BrightnessThrottlingPoint; import com.android.server.display.config.Density; +import com.android.server.display.config.DisplayBrightnessPoint; import com.android.server.display.config.DisplayConfiguration; import com.android.server.display.config.DisplayQuirks; import com.android.server.display.config.HbmTiming; import com.android.server.display.config.HighBrightnessMode; import com.android.server.display.config.NitsMap; import com.android.server.display.config.Point; +import com.android.server.display.config.RefreshRateConfigs; import com.android.server.display.config.RefreshRateRange; import com.android.server.display.config.SdrHdrRatioMap; import com.android.server.display.config.SdrHdrRatioPoint; @@ -130,6 +133,35 @@ import javax.xml.datatype.DatatypeConfigurationException; * </brightnessThrottlingMap> * </thermalThrottling> * + * <refreshRate> + * <lowerBlockingZoneConfigs> + * <defaultRefreshRate>75</defaultRefreshRate> + * <blockingZoneThreshold> + * <displayBrightnessPoint> + * <lux>50</lux> + * <nits>45.3</nits> + * </displayBrightnessPoint> + * <displayBrightnessPoint> + * <lux>60</lux> + * <nits>55.2</nits> + * </displayBrightnessPoint> + * </blockingZoneThreshold> + * </lowerBlockingZoneConfigs> + * <higherBlockingZoneConfigs> + * <defaultRefreshRate>90</defaultRefreshRate> + * <blockingZoneThreshold> + * <displayBrightnessPoint> + * <lux>500</lux> + * <nits>245.3</nits> + * </displayBrightnessPoint> + * <displayBrightnessPoint> + * <lux>600</lux> + * <nits>232.3</nits> + * </displayBrightnessPoint> + * </blockingZoneThreshold> + * </higherBlockingZoneConfigs> + * </refreshRate> + * * <highBrightnessMode enabled="true"> * <transitionPoint>0.62</transitionPoint> * <minimumLux>10000</minimumLux> @@ -358,6 +390,9 @@ public class DisplayDeviceConfig { private static final String STABLE_ID_SUFFIX_FORMAT = "id_%d"; private static final String NO_SUFFIX_FORMAT = "%d"; private static final long STABLE_FLAG = 1L << 62; + private static final int DEFAULT_LOW_REFRESH_RATE = 60; + private static final int DEFAULT_HIGH_REFRESH_RATE = 0; + private static final int[] DEFAULT_BRIGHTNESS_THRESHOLDS = new int[]{}; private static final float[] DEFAULT_AMBIENT_THRESHOLD_LEVELS = new float[]{0f}; private static final float[] DEFAULT_AMBIENT_BRIGHTENING_THRESHOLDS = new float[]{100f}; @@ -512,6 +547,49 @@ public class DisplayDeviceConfig { // This stores the raw value loaded from the config file - true if not written. private boolean mDdcAutoBrightnessAvailable = true; + /** + * The default peak refresh rate for a given device. This value prevents the framework from + * using higher refresh rates, even if display modes with higher refresh rates are available + * from hardware composer. Only has an effect if the value is non-zero. + */ + private int mDefaultHighRefreshRate = DEFAULT_HIGH_REFRESH_RATE; + + /** + * The default refresh rate for a given device. This value sets the higher default + * refresh rate. If the hardware composer on the device supports display modes with + * a higher refresh rate than the default value specified here, the framework may use those + * higher refresh rate modes if an app chooses one by setting preferredDisplayModeId or calling + * setFrameRate(). We have historically allowed fallback to mDefaultHighRefreshRate if + * mDefaultLowRefreshRate is set to 0, but this is not supported anymore. + */ + private int mDefaultLowRefreshRate = DEFAULT_LOW_REFRESH_RATE; + + /** + * The display uses different gamma curves for different refresh rates. It's hard for panel + * vendors to tune the curves to have exact same brightness for different refresh rate. So + * brightness flickers could be observed at switch time. The issue is worse at the gamma lower + * end. In addition, human eyes are more sensitive to the flicker at darker environment. To + * prevent flicker, we only support higher refresh rates if the display brightness is above a + * threshold. For example, no higher refresh rate if display brightness <= disp0 && ambient + * brightness <= amb0 || display brightness <= disp1 && ambient brightness <= amb1 + */ + private int[] mLowDisplayBrightnessThresholds = DEFAULT_BRIGHTNESS_THRESHOLDS; + private int[] mLowAmbientBrightnessThresholds = DEFAULT_BRIGHTNESS_THRESHOLDS; + + /** + * The display uses different gamma curves for different refresh rates. It's hard for panel + * vendors to tune the curves to have exact same brightness for different refresh rate. So + * brightness flickers could be observed at switch time. The issue can be observed on the screen + * with even full white content at the high brightness. To prevent flickering, we support fixed + * refresh rates if the display and ambient brightness are equal to or above the provided + * thresholds. You can define multiple threshold levels as higher brightness environments may + * have lower display brightness requirements for the flickering is visible. For example, fixed + * refresh rate if display brightness >= disp0 && ambient brightness >= amb0 || display + * brightness >= disp1 && ambient brightness >= amb1 + */ + private int[] mHighDisplayBrightnessThresholds = DEFAULT_BRIGHTNESS_THRESHOLDS; + private int[] mHighAmbientBrightnessThresholds = DEFAULT_BRIGHTNESS_THRESHOLDS; + // Brightness Throttling data may be updated via the DeviceConfig. Here we store the original // data, which comes from the ddc, and the current one, which may be the DeviceConfig // overwritten value. @@ -1196,15 +1274,15 @@ public class DisplayDeviceConfig { /** * @return Default peak refresh rate of the associated display */ - public int getDefaultPeakRefreshRate() { - return mContext.getResources().getInteger(R.integer.config_defaultPeakRefreshRate); + public int getDefaultHighRefreshRate() { + return mDefaultHighRefreshRate; } /** * @return Default refresh rate of the associated display */ - public int getDefaultRefreshRate() { - return mContext.getResources().getInteger(R.integer.config_defaultRefreshRate); + public int getDefaultLowRefreshRate() { + return mDefaultLowRefreshRate; } /** @@ -1213,8 +1291,7 @@ public class DisplayDeviceConfig { * allowed */ public int[] getLowDisplayBrightnessThresholds() { - return mContext.getResources().getIntArray( - R.array.config_brightnessThresholdsOfPeakRefreshRate); + return mLowDisplayBrightnessThresholds; } /** @@ -1223,8 +1300,7 @@ public class DisplayDeviceConfig { * allowed */ public int[] getLowAmbientBrightnessThresholds() { - return mContext.getResources().getIntArray( - R.array.config_ambientThresholdsOfPeakRefreshRate); + return mLowAmbientBrightnessThresholds; } /** @@ -1233,8 +1309,7 @@ public class DisplayDeviceConfig { * allowed */ public int[] getHighDisplayBrightnessThresholds() { - return mContext.getResources().getIntArray( - R.array.config_highDisplayBrightnessThresholdsOfFixedRefreshRate); + return mHighDisplayBrightnessThresholds; } /** @@ -1243,8 +1318,7 @@ public class DisplayDeviceConfig { * allowed */ public int[] getHighAmbientBrightnessThresholds() { - return mContext.getResources().getIntArray( - R.array.config_highAmbientBrightnessThresholdsOfFixedRefreshRate); + return mHighAmbientBrightnessThresholds; } @Override @@ -1336,6 +1410,17 @@ public class DisplayDeviceConfig { + ", mBrightnessLevelsNits= " + Arrays.toString(mBrightnessLevelsNits) + ", mDdcAutoBrightnessAvailable= " + mDdcAutoBrightnessAvailable + ", mAutoBrightnessAvailable= " + mAutoBrightnessAvailable + + "\n" + + ", mDefaultRefreshRate= " + mDefaultLowRefreshRate + + ", mDefaultPeakRefreshRate= " + mDefaultHighRefreshRate + + ", mLowDisplayBrightnessThresholds= " + + Arrays.toString(mLowDisplayBrightnessThresholds) + + ", mLowAmbientBrightnessThresholds= " + + Arrays.toString(mLowAmbientBrightnessThresholds) + + ", mHighDisplayBrightnessThresholds= " + + Arrays.toString(mHighDisplayBrightnessThresholds) + + ", mHighAmbientBrightnessThresholds= " + + Arrays.toString(mHighAmbientBrightnessThresholds) + "}"; } @@ -1393,6 +1478,7 @@ public class DisplayDeviceConfig { loadAmbientHorizonFromDdc(config); loadBrightnessChangeThresholds(config); loadAutoBrightnessConfigValues(config); + loadRefreshRateSetting(config); } else { Slog.w(TAG, "DisplayDeviceConfig file is null"); } @@ -1415,6 +1501,7 @@ public class DisplayDeviceConfig { useFallbackProxSensor(); loadAutoBrightnessConfigsFromConfigXml(); loadAutoBrightnessAvailableFromConfigXml(); + loadRefreshRateSetting(null); mLoadedFrom = "<config.xml>"; } @@ -1625,6 +1712,143 @@ public class DisplayDeviceConfig { } } + private void loadRefreshRateSetting(DisplayConfiguration config) { + final RefreshRateConfigs refreshRateConfigs = + (config == null) ? null : config.getRefreshRate(); + BlockingZoneConfig lowerBlockingZoneConfig = + (refreshRateConfigs == null) ? null + : refreshRateConfigs.getLowerBlockingZoneConfigs(); + BlockingZoneConfig higherBlockingZoneConfig = + (refreshRateConfigs == null) ? null + : refreshRateConfigs.getHigherBlockingZoneConfigs(); + loadLowerRefreshRateBlockingZones(lowerBlockingZoneConfig); + loadHigherRefreshRateBlockingZones(higherBlockingZoneConfig); + } + + + /** + * Loads the refresh rate configurations pertaining to the upper blocking zones. + */ + private void loadLowerRefreshRateBlockingZones(BlockingZoneConfig lowerBlockingZoneConfig) { + loadLowerBlockingZoneDefaultRefreshRate(lowerBlockingZoneConfig); + loadLowerBrightnessThresholds(lowerBlockingZoneConfig); + } + + /** + * Loads the refresh rate configurations pertaining to the upper blocking zones. + */ + private void loadHigherRefreshRateBlockingZones(BlockingZoneConfig upperBlockingZoneConfig) { + loadHigherBlockingZoneDefaultRefreshRate(upperBlockingZoneConfig); + loadHigherBrightnessThresholds(upperBlockingZoneConfig); + } + + /** + * Loads the default peak refresh rate. Internally, this takes care of loading + * the value from the display config, and if not present, falls back to config.xml. + */ + private void loadHigherBlockingZoneDefaultRefreshRate( + BlockingZoneConfig upperBlockingZoneConfig) { + if (upperBlockingZoneConfig == null) { + mDefaultHighRefreshRate = mContext.getResources().getInteger( + com.android.internal.R.integer.config_defaultPeakRefreshRate); + } else { + mDefaultHighRefreshRate = + upperBlockingZoneConfig.getDefaultRefreshRate().intValue(); + } + } + + /** + * Loads the default refresh rate. Internally, this takes care of loading + * the value from the display config, and if not present, falls back to config.xml. + */ + private void loadLowerBlockingZoneDefaultRefreshRate( + BlockingZoneConfig lowerBlockingZoneConfig) { + if (lowerBlockingZoneConfig == null) { + mDefaultLowRefreshRate = mContext.getResources().getInteger( + com.android.internal.R.integer.config_defaultRefreshRate); + } else { + mDefaultLowRefreshRate = + lowerBlockingZoneConfig.getDefaultRefreshRate().intValue(); + } + } + + /** + * Loads the lower brightness thresholds for refresh rate switching. Internally, this takes care + * of loading the value from the display config, and if not present, falls back to config.xml. + */ + private void loadLowerBrightnessThresholds(BlockingZoneConfig lowerBlockingZoneConfig) { + if (lowerBlockingZoneConfig == null) { + mLowDisplayBrightnessThresholds = mContext.getResources().getIntArray( + R.array.config_brightnessThresholdsOfPeakRefreshRate); + mLowAmbientBrightnessThresholds = mContext.getResources().getIntArray( + R.array.config_ambientThresholdsOfPeakRefreshRate); + if (mLowDisplayBrightnessThresholds == null || mLowAmbientBrightnessThresholds == null + || mLowDisplayBrightnessThresholds.length + != mLowAmbientBrightnessThresholds.length) { + throw new RuntimeException("display low brightness threshold array and ambient " + + "brightness threshold array have different length: " + + "mLowDisplayBrightnessThresholds=" + + Arrays.toString(mLowDisplayBrightnessThresholds) + + ", mLowAmbientBrightnessThresholds=" + + Arrays.toString(mLowAmbientBrightnessThresholds)); + } + } else { + List<DisplayBrightnessPoint> lowerThresholdDisplayBrightnessPoints = + lowerBlockingZoneConfig.getBlockingZoneThreshold().getDisplayBrightnessPoint(); + int size = lowerThresholdDisplayBrightnessPoints.size(); + mLowDisplayBrightnessThresholds = new int[size]; + mLowAmbientBrightnessThresholds = new int[size]; + for (int i = 0; i < size; i++) { + // We are explicitly casting this value to an integer to be able to reuse the + // existing DisplayBrightnessPoint type. It is fine to do this because the round off + // will have the negligible and unnoticeable impact on the loaded thresholds. + mLowDisplayBrightnessThresholds[i] = (int) lowerThresholdDisplayBrightnessPoints + .get(i).getNits().floatValue(); + mLowAmbientBrightnessThresholds[i] = lowerThresholdDisplayBrightnessPoints + .get(i).getLux().intValue(); + } + } + } + + /** + * Loads the higher brightness thresholds for refresh rate switching. Internally, this takes + * care of loading the value from the display config, and if not present, falls back to + * config.xml. + */ + private void loadHigherBrightnessThresholds(BlockingZoneConfig blockingZoneConfig) { + if (blockingZoneConfig == null) { + mHighDisplayBrightnessThresholds = mContext.getResources().getIntArray( + R.array.config_highDisplayBrightnessThresholdsOfFixedRefreshRate); + mHighAmbientBrightnessThresholds = mContext.getResources().getIntArray( + R.array.config_highAmbientBrightnessThresholdsOfFixedRefreshRate); + if (mHighAmbientBrightnessThresholds == null || mHighDisplayBrightnessThresholds == null + || mHighAmbientBrightnessThresholds.length + != mHighDisplayBrightnessThresholds.length) { + throw new RuntimeException("display high brightness threshold array and ambient " + + "brightness threshold array have different length: " + + "mHighDisplayBrightnessThresholds=" + + Arrays.toString(mHighDisplayBrightnessThresholds) + + ", mHighAmbientBrightnessThresholds=" + + Arrays.toString(mHighAmbientBrightnessThresholds)); + } + } else { + List<DisplayBrightnessPoint> higherThresholdDisplayBrightnessPoints = + blockingZoneConfig.getBlockingZoneThreshold().getDisplayBrightnessPoint(); + int size = higherThresholdDisplayBrightnessPoints.size(); + mHighDisplayBrightnessThresholds = new int[size]; + mHighAmbientBrightnessThresholds = new int[size]; + for (int i = 0; i < size; i++) { + // We are explicitly casting this value to an integer to be able to reuse the + // existing DisplayBrightnessPoint type. It is fine to do this because the round off + // will have the negligible and unnoticeable impact on the loaded thresholds. + mHighDisplayBrightnessThresholds[i] = (int) higherThresholdDisplayBrightnessPoints + .get(i).getNits().floatValue(); + mHighAmbientBrightnessThresholds[i] = higherThresholdDisplayBrightnessPoints + .get(i).getLux().intValue(); + } + } + } + private void loadAutoBrightnessConfigValues(DisplayConfiguration config) { final AutoBrightness autoBrightness = config.getAutoBrightness(); loadAutoBrightnessBrighteningLightDebounce(autoBrightness); diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index f9c8f064de96..3da7d830a23f 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -3652,44 +3652,21 @@ public final class DisplayManagerService extends SystemService { @Override public Set<DisplayInfo> getPossibleDisplayInfo(int displayId) { synchronized (mSyncRoot) { - // Retrieve the group associated with this display id. - final int displayGroupId = - mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked(displayId); - if (displayGroupId == Display.INVALID_DISPLAY_GROUP) { - Slog.w(TAG, - "Can't get possible display info since display group for " + displayId - + " does not exist"); - return new ArraySet<>(); - } - - // Assume any display in this group can be swapped out for the given display id. Set<DisplayInfo> possibleInfo = new ArraySet<>(); - final DisplayGroup group = mLogicalDisplayMapper.getDisplayGroupLocked( - displayGroupId); - for (int i = 0; i < group.getSizeLocked(); i++) { - final int id = group.getIdLocked(i); - final LogicalDisplay logical = mLogicalDisplayMapper.getDisplayLocked(id); - if (logical == null) { - Slog.w(TAG, - "Can't get possible display info since logical display for " - + "display id " + id + " does not exist, as part of group " - + displayGroupId); - } else { - possibleInfo.add(logical.getDisplayInfoLocked()); - } - } - - // For the supported device states, retrieve the DisplayInfos for the logical - // display layout. + // For each of supported device states, retrieve the display layout of that state, + // and return all of the DisplayInfos (one per state) for the given display id. if (mDeviceStateManager == null) { Slog.w(TAG, "Can't get supported states since DeviceStateManager not ready"); - } else { - final int[] supportedStates = - mDeviceStateManager.getSupportedStateIdentifiers(); - for (int state : supportedStates) { - possibleInfo.addAll( - mLogicalDisplayMapper.getDisplayInfoForStateLocked(state, displayId, - displayGroupId)); + return possibleInfo; + } + final int[] supportedStates = + mDeviceStateManager.getSupportedStateIdentifiers(); + DisplayInfo displayInfo; + for (int state : supportedStates) { + displayInfo = mLogicalDisplayMapper.getDisplayInfoForStateLocked(state, + displayId); + if (displayInfo != null) { + possibleInfo.add(displayInfo); } } return possibleInfo; diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java index ecae8330d532..6331a5dd07b4 100644 --- a/services/core/java/com/android/server/display/DisplayModeDirector.java +++ b/services/core/java/com/android/server/display/DisplayModeDirector.java @@ -1163,7 +1163,7 @@ public class DisplayModeDirector { mDefaultRefreshRate = (displayDeviceConfig == null) ? (float) mContext.getResources().getInteger( R.integer.config_defaultRefreshRate) - : (float) displayDeviceConfig.getDefaultRefreshRate(); + : (float) displayDeviceConfig.getDefaultLowRefreshRate(); } public void observe() { @@ -1250,7 +1250,7 @@ public class DisplayModeDirector { defaultPeakRefreshRate = (displayDeviceConfig == null) ? (float) mContext.getResources().getInteger( R.integer.config_defaultPeakRefreshRate) - : (float) displayDeviceConfig.getDefaultPeakRefreshRate(); + : (float) displayDeviceConfig.getDefaultHighRefreshRate(); } mDefaultPeakRefreshRate = defaultPeakRefreshRate; } diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index bb27651ed0ed..2fc6fd2254a7 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -459,6 +459,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call // PowerManager.BRIGHTNESS_INVALID_FLOAT when there's no temporary adjustment set. private float mTemporaryAutoBrightnessAdjustment; + private boolean mUseAutoBrightness; + private boolean mIsRbcActive; // Whether there's a callback to tell listeners the display has changed scheduled to run. When @@ -692,6 +694,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call public void onSwitchUser(@UserIdInt int newUserId) { handleSettingsChange(true /* userSwitch */); + handleBrightnessModeChange(); if (mBrightnessTracker != null) { mBrightnessTracker.onSwitchUser(newUserId); } @@ -941,6 +944,10 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mContext.getContentResolver().registerContentObserver( Settings.System.getUriFor(Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ), false /*notifyForDescendants*/, mSettingsObserver, UserHandle.USER_ALL); + mContext.getContentResolver().registerContentObserver( + Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS_MODE), + false /*notifyForDescendants*/, mSettingsObserver, UserHandle.USER_ALL); + handleBrightnessModeChange(); } private void setUpAutoBrightness(Resources resources, Handler handler) { @@ -1344,11 +1351,11 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call final boolean autoBrightnessEnabledInDoze = mAllowAutoBrightnessWhileDozingConfig && Display.isDozeState(state); - final boolean autoBrightnessEnabled = mPowerRequest.useAutoBrightness + final boolean autoBrightnessEnabled = mUseAutoBrightness && (state == Display.STATE_ON || autoBrightnessEnabledInDoze) && Float.isNaN(brightnessState) && mAutomaticBrightnessController != null; - final boolean autoBrightnessDisabledDueToDisplayOff = mPowerRequest.useAutoBrightness + final boolean autoBrightnessDisabledDueToDisplayOff = mUseAutoBrightness && !(state == Display.STATE_ON || autoBrightnessEnabledInDoze); final int autoBrightnessState = autoBrightnessEnabled ? AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED @@ -1700,7 +1707,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call || brightnessAdjustmentFlags != 0) { float lastBrightness = mLastBrightnessEvent.brightness; mTempBrightnessEvent.initialBrightness = lastBrightness; - mTempBrightnessEvent.automaticBrightnessEnabled = mPowerRequest.useAutoBrightness; + mTempBrightnessEvent.automaticBrightnessEnabled = mUseAutoBrightness; mLastBrightnessEvent.copyFrom(mTempBrightnessEvent); BrightnessEvent newEvent = new BrightnessEvent(mTempBrightnessEvent); @@ -2372,6 +2379,18 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call sendUpdatePowerState(); } + private void handleBrightnessModeChange() { + final int screenBrightnessModeSetting = Settings.System.getIntForUser( + mContext.getContentResolver(), + Settings.System.SCREEN_BRIGHTNESS_MODE, + Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL, UserHandle.USER_CURRENT); + mHandler.post(() -> { + mUseAutoBrightness = screenBrightnessModeSetting + == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC; + updatePowerState(); + }); + } + private float getAutoBrightnessAdjustmentSetting() { final float adj = Settings.System.getFloatForUser(mContext.getContentResolver(), Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, 0.0f, UserHandle.USER_CURRENT); @@ -2461,7 +2480,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call private void notifyBrightnessTrackerChanged(float brightness, boolean userInitiated, boolean hadUserDataPoint) { final float brightnessInNits = convertToNits(brightness); - if (mPowerRequest.useAutoBrightness && brightnessInNits >= 0.0f + if (mUseAutoBrightness && brightnessInNits >= 0.0f && mAutomaticBrightnessController != null && mBrightnessTracker != null) { // We only want to track changes on devices that can actually map the display backlight // values into a physical brightness unit since the value provided by the API is in @@ -3099,7 +3118,11 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call @Override public void onChange(boolean selfChange, Uri uri) { - handleSettingsChange(false /* userSwitch */); + if (uri.equals(Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS_MODE))) { + handleBrightnessModeChange(); + } else { + handleSettingsChange(false /* userSwitch */); + } } } diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java index 778e41820433..17e7340216ff 100644 --- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java +++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java @@ -19,6 +19,7 @@ package com.android.server.display; import static android.view.Display.DEFAULT_DISPLAY; import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.Context; import android.hardware.devicestate.DeviceStateManager; import android.os.Handler; @@ -28,7 +29,6 @@ import android.os.PowerManager; import android.os.SystemClock; import android.os.SystemProperties; import android.text.TextUtils; -import android.util.ArraySet; import android.util.IndentingPrintWriter; import android.util.Slog; import android.util.SparseArray; @@ -43,7 +43,6 @@ import com.android.server.display.layout.Layout; import java.io.PrintWriter; import java.util.Arrays; -import java.util.Set; import java.util.function.Consumer; /** @@ -304,58 +303,44 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { } /** - * Returns the set of {@link DisplayInfo} for this device state, only fetching the info that is - * part of the same display group as the provided display id. The DisplayInfo represent the - * logical display layouts possible for the given device state. + * Returns the {@link DisplayInfo} for this device state, indicated by the given display id. The + * DisplayInfo represents the attributes of the indicated display in the layout associated with + * this state. This is used to get display information for various displays in various states; + * e.g. to help apps preload resources for the possible display states. * * @param deviceState the state to query possible layouts for - * @param displayId the display id to apply to all displays within the group - * @param groupId the display group to filter display info for. Must be the same group as - * the display with the provided display id. + * @param displayId the display id to retrieve + * @return {@code null} if no corresponding {@link DisplayInfo} could be found, or the + * {@link DisplayInfo} with a matching display id. */ - public Set<DisplayInfo> getDisplayInfoForStateLocked(int deviceState, int displayId, - int groupId) { - Set<DisplayInfo> displayInfos = new ArraySet<>(); + @Nullable + public DisplayInfo getDisplayInfoForStateLocked(int deviceState, int displayId) { + // Retrieve the layout for this particular state. final Layout layout = mDeviceStateToLayoutMap.get(deviceState); - final int layoutSize = layout.size(); - for (int i = 0; i < layoutSize; i++) { - Layout.Display displayLayout = layout.getAt(i); - if (displayLayout == null) { - continue; - } - - // If the underlying display-device we want to use for this display - // doesn't exist, then skip it. This can happen at startup as display-devices - // trickle in one at a time. When the new display finally shows up, the layout is - // recalculated so that the display is properly added to the current layout. - final DisplayAddress address = displayLayout.getAddress(); - final DisplayDevice device = mDisplayDeviceRepo.getByAddressLocked(address); - if (device == null) { - Slog.w(TAG, "The display device (" + address + "), is not available" - + " for the display state " + deviceState); - continue; - } - - // Find or create the LogicalDisplay to map the DisplayDevice to. - final int logicalDisplayId = displayLayout.getLogicalDisplayId(); - final LogicalDisplay logicalDisplay = getDisplayLocked(logicalDisplayId); - if (logicalDisplay == null) { - Slog.w(TAG, "The logical display (" + address + "), is not available" - + " for the display state " + deviceState); - continue; - } - final DisplayInfo temp = logicalDisplay.getDisplayInfoLocked(); - DisplayInfo displayInfo = new DisplayInfo(temp); - if (displayInfo.displayGroupId != groupId) { - // Ignore any displays not in the provided group. - continue; - } - // A display in the same group can be swapped out at any point, so set the display id - // for all results to the provided display id. - displayInfo.displayId = displayId; - displayInfos.add(displayInfo); + if (layout == null) { + return null; + } + // Retrieve the details of the given display within this layout. + Layout.Display display = layout.getById(displayId); + if (display == null) { + return null; + } + // Retrieve the display info for the display that matches the display id. + final DisplayDevice device = mDisplayDeviceRepo.getByAddressLocked(display.getAddress()); + if (device == null) { + Slog.w(TAG, "The display device (" + display.getAddress() + "), is not available" + + " for the display state " + mDeviceState); + return null; + } + LogicalDisplay logicalDisplay = getDisplayLocked(device, /* includeDisabled= */ true); + if (logicalDisplay == null) { + Slog.w(TAG, "The logical display associated with address (" + display.getAddress() + + "), is not available for the display state " + mDeviceState); + return null; } - return displayInfos; + DisplayInfo displayInfo = new DisplayInfo(logicalDisplay.getDisplayInfoLocked()); + displayInfo.displayId = displayId; + return displayInfo; } public void dumpLocked(PrintWriter pw) { diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index 1ea949ede03d..2f818fa10b72 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -123,6 +123,7 @@ import static android.telephony.CarrierConfigManager.KEY_DATA_RAPID_NOTIFICATION import static android.telephony.CarrierConfigManager.KEY_DATA_WARNING_NOTIFICATION_BOOL; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; +import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE; import static com.android.internal.util.ArrayUtils.appendInt; import static com.android.internal.util.XmlUtils.readBooleanAttribute; import static com.android.internal.util.XmlUtils.readIntAttribute; @@ -3148,7 +3149,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { * active merge set [A,B], we'd return a new template that primarily matches * A, but also matches B. */ - private static NetworkTemplate normalizeTemplate(@NonNull NetworkTemplate template, + @VisibleForTesting(visibility = PRIVATE) + static NetworkTemplate normalizeTemplate(@NonNull NetworkTemplate template, @NonNull List<String[]> mergedList) { // Now there are several types of network which uses Subscriber Id to store network // information. For instance: @@ -3158,6 +3160,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { if (template.getSubscriberIds().isEmpty()) return template; for (final String[] merged : mergedList) { + // In some rare cases (e.g. b/243015487), merged subscriberId list might contain + // duplicated items. Deduplication for better error handling. + final ArraySet mergedSet = new ArraySet(merged); + if (mergedSet.size() != merged.length) { + Log.wtf(TAG, "Duplicated merged list detected: " + Arrays.toString(merged)); + } // TODO: Handle incompatible subscriberIds if that happens in practice. for (final String subscriberId : template.getSubscriberIds()) { if (com.android.net.module.util.CollectionUtils.contains(merged, subscriberId)) { @@ -3165,7 +3173,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // a template that matches all merged subscribers. return new NetworkTemplate.Builder(template.getMatchRule()) .setWifiNetworkKeys(template.getWifiNetworkKeys()) - .setSubscriberIds(Set.of(merged)) + .setSubscriberIds(mergedSet) .setMeteredness(template.getMeteredness()) .build(); } diff --git a/services/core/java/com/android/server/power/PowerGroup.java b/services/core/java/com/android/server/power/PowerGroup.java index 431cf3861804..791b40783d5d 100644 --- a/services/core/java/com/android/server/power/PowerGroup.java +++ b/services/core/java/com/android/server/power/PowerGroup.java @@ -419,16 +419,14 @@ public class PowerGroup { return mDisplayPowerRequest.policy; } - boolean updateLocked(float screenBrightnessOverride, boolean autoBrightness, - boolean useProximitySensor, boolean boostScreenBrightness, int dozeScreenState, - float dozeScreenBrightness, boolean overrideDrawWakeLock, - PowerSaveState powerSaverState, boolean quiescent, boolean dozeAfterScreenOff, - boolean vrModeEnabled, boolean bootCompleted, boolean screenBrightnessBoostInProgress, - boolean waitForNegativeProximity) { + boolean updateLocked(float screenBrightnessOverride, boolean useProximitySensor, + boolean boostScreenBrightness, int dozeScreenState, float dozeScreenBrightness, + boolean overrideDrawWakeLock, PowerSaveState powerSaverState, boolean quiescent, + boolean dozeAfterScreenOff, boolean vrModeEnabled, boolean bootCompleted, + boolean screenBrightnessBoostInProgress, boolean waitForNegativeProximity) { mDisplayPowerRequest.policy = getDesiredScreenPolicyLocked(quiescent, dozeAfterScreenOff, vrModeEnabled, bootCompleted, screenBrightnessBoostInProgress); mDisplayPowerRequest.screenBrightnessOverride = screenBrightnessOverride; - mDisplayPowerRequest.useAutoBrightness = autoBrightness; mDisplayPowerRequest.useProximitySensor = useProximitySensor; mDisplayPowerRequest.boostScreenBrightness = boostScreenBrightness; diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index b1c986e6558a..1fb7144d2d4d 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -584,10 +584,6 @@ public final class PowerManagerService extends SystemService private boolean mIsFaceDown = false; private long mLastFlipTime = 0L; - // The screen brightness mode. - // One of the Settings.System.SCREEN_BRIGHTNESS_MODE_* constants. - private int mScreenBrightnessModeSetting; - // The screen brightness setting override from the window manager // to allow the current foreground activity to override the brightness. private float mScreenBrightnessOverrideFromWindowManager = @@ -1481,10 +1477,6 @@ public final class PowerManagerService extends SystemService mSystemProperties.set(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED, retailDemoValue); } - mScreenBrightnessModeSetting = Settings.System.getIntForUser(resolver, - Settings.System.SCREEN_BRIGHTNESS_MODE, - Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL, UserHandle.USER_CURRENT); - mDirty |= DIRTY_SETTINGS; } @@ -3466,23 +3458,18 @@ public final class PowerManagerService extends SystemService final PowerGroup powerGroup = mPowerGroups.valueAt(idx); final int groupId = powerGroup.getGroupId(); - // Determine appropriate screen brightness and auto-brightness adjustments. - final boolean autoBrightness; + // Determine appropriate screen brightness. final float screenBrightnessOverride; if (!mBootCompleted) { // Keep the brightness steady during boot. This requires the // bootloader brightness and the default brightness to be identical. - autoBrightness = false; screenBrightnessOverride = mScreenBrightnessDefault; } else if (isValidBrightness(mScreenBrightnessOverrideFromWindowManager)) { - autoBrightness = false; screenBrightnessOverride = mScreenBrightnessOverrideFromWindowManager; } else { - autoBrightness = (mScreenBrightnessModeSetting - == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); screenBrightnessOverride = PowerManager.BRIGHTNESS_INVALID_FLOAT; } - boolean ready = powerGroup.updateLocked(screenBrightnessOverride, autoBrightness, + boolean ready = powerGroup.updateLocked(screenBrightnessOverride, shouldUseProximitySensorLocked(), shouldBoostScreenBrightness(), mDozeScreenStateOverrideFromDreamManager, mDozeScreenBrightnessOverrideFromDreamManagerFloat, @@ -3503,7 +3490,6 @@ public final class PowerManagerService extends SystemService powerGroup.getUserActivitySummaryLocked()) + ", mBootCompleted=" + mBootCompleted + ", screenBrightnessOverride=" + screenBrightnessOverride - + ", useAutoBrightness=" + autoBrightness + ", mScreenBrightnessBoostInProgress=" + mScreenBrightnessBoostInProgress + ", mIsVrModeEnabled= " + mIsVrModeEnabled @@ -4525,7 +4511,6 @@ public final class PowerManagerService extends SystemService + mMaximumScreenOffTimeoutFromDeviceAdmin + " (enforced=" + isMaximumScreenOffTimeoutFromDeviceAdminEnforcedLocked() + ")"); pw.println(" mStayOnWhilePluggedInSetting=" + mStayOnWhilePluggedInSetting); - pw.println(" mScreenBrightnessModeSetting=" + mScreenBrightnessModeSetting); pw.println(" mScreenBrightnessOverrideFromWindowManager=" + mScreenBrightnessOverrideFromWindowManager); pw.println(" mUserActivityTimeoutOverrideFromWindowManager=" @@ -4904,9 +4889,6 @@ public final class PowerManagerService extends SystemService proto.end(stayOnWhilePluggedInToken); proto.write( - PowerServiceSettingsAndConfigurationDumpProto.SCREEN_BRIGHTNESS_MODE_SETTING, - mScreenBrightnessModeSetting); - proto.write( PowerServiceSettingsAndConfigurationDumpProto .SCREEN_BRIGHTNESS_OVERRIDE_FROM_WINDOW_MANAGER, mScreenBrightnessOverrideFromWindowManager); diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java index 2888b9a2d3cc..6c191eb3842d 100644 --- a/services/core/java/com/android/server/trust/TrustManagerService.java +++ b/services/core/java/com/android/server/trust/TrustManagerService.java @@ -690,7 +690,7 @@ public class TrustManagerService extends SystemService { */ public void lockUser(int userId) { mLockPatternUtils.requireStrongAuth( - StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST, userId); + StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED, userId); try { WindowManagerGlobal.getWindowManagerService().lockNow(null); } catch (RemoteException e) { @@ -2087,7 +2087,7 @@ public class TrustManagerService extends SystemService { if (mStrongAuthTracker.isTrustAllowedForUser(mUserId)) { if (DEBUG) Slog.d(TAG, "Revoking all trust because of trust timeout"); mLockPatternUtils.requireStrongAuth( - mStrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST, mUserId); + mStrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED, mUserId); } maybeLockScreen(mUserId); } diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java index ae4f8947cc86..7a3fd634ebe1 100644 --- a/services/core/java/com/android/server/wm/TaskFragment.java +++ b/services/core/java/com/android/server/wm/TaskFragment.java @@ -2223,7 +2223,8 @@ class TaskFragment extends WindowContainer<WindowContainer> { // task, because they should not be affected by insets. inOutConfig.smallestScreenWidthDp = (int) (0.5f + Math.min(mTmpFullBounds.width(), mTmpFullBounds.height()) / density); - } else if (isEmbedded()) { + } else if (windowingMode == WINDOWING_MODE_MULTI_WINDOW + && isEmbeddedWithBoundsOverride()) { // For embedded TFs, the smallest width should be updated. Otherwise, inherit // from the parent task would result in applications loaded wrong resource. inOutConfig.smallestScreenWidthDp = diff --git a/services/core/xsd/display-device-config/display-device-config.xsd b/services/core/xsd/display-device-config/display-device-config.xsd index f53a1cfcfb3c..7bc89313c75e 100644 --- a/services/core/xsd/display-device-config/display-device-config.xsd +++ b/services/core/xsd/display-device-config/display-device-config.xsd @@ -44,9 +44,11 @@ </xs:element> <xs:element type="highBrightnessMode" name="highBrightnessMode" minOccurs="0" maxOccurs="1"/> - <xs:element type="displayQuirks" name="quirks" minOccurs="0" maxOccurs="1" /> + <xs:element type="displayQuirks" name="quirks" minOccurs="0" maxOccurs="1"/> <xs:element type="autoBrightness" name="autoBrightness" minOccurs="0" - maxOccurs="1" /> + maxOccurs="1"/> + <xs:element type="refreshRateConfigs" name="refreshRate" minOccurs="0" + maxOccurs="1"/> <xs:element type="nonNegativeDecimal" name="screenBrightnessRampFastDecrease"> <xs:annotation name="final"/> </xs:element> @@ -324,7 +326,7 @@ <xs:annotation name="final"/> </xs:element> </xs:sequence> - </xs:complexType> + </xs:complexType> <!-- Thresholds for brightness changes. --> <xs:complexType name="thresholds"> @@ -452,4 +454,35 @@ </xs:element> </xs:sequence> </xs:complexType> + + <xs:complexType name="refreshRateConfigs"> + <xs:element name="lowerBlockingZoneConfigs" type="blockingZoneConfig" + minOccurs="0" maxOccurs="1"> + <xs:annotation name="final"/> + </xs:element> + <xs:element name="higherBlockingZoneConfigs" type="blockingZoneConfig" + minOccurs="0" maxOccurs="1"> + <xs:annotation name="final"/> + </xs:element> + </xs:complexType> + + <xs:complexType name="blockingZoneConfig"> + <xs:element name="defaultRefreshRate" type="xs:nonNegativeInteger" + minOccurs="1" maxOccurs="1"> + <xs:annotation name="final"/> + </xs:element> + <xs:element name="blockingZoneThreshold" type="blockingZoneThreshold" + minOccurs="1" maxOccurs="1"> + <xs:annotation name="final"/> + </xs:element> + </xs:complexType> + + <xs:complexType name="blockingZoneThreshold"> + <xs:sequence> + <xs:element name="displayBrightnessPoint" type="displayBrightnessPoint" + minOccurs="1" maxOccurs="unbounded"> + <xs:annotation name="final"/> + </xs:element> + </xs:sequence> + </xs:complexType> </xs:schema> diff --git a/services/core/xsd/display-device-config/schema/current.txt b/services/core/xsd/display-device-config/schema/current.txt index d89bd7cc9aa2..6276edaf3ebc 100644 --- a/services/core/xsd/display-device-config/schema/current.txt +++ b/services/core/xsd/display-device-config/schema/current.txt @@ -13,6 +13,19 @@ package com.android.server.display.config { method public void setEnabled(boolean); } + public class BlockingZoneConfig { + ctor public BlockingZoneConfig(); + method public final com.android.server.display.config.BlockingZoneThreshold getBlockingZoneThreshold(); + method public final java.math.BigInteger getDefaultRefreshRate(); + method public final void setBlockingZoneThreshold(com.android.server.display.config.BlockingZoneThreshold); + method public final void setDefaultRefreshRate(java.math.BigInteger); + } + + public class BlockingZoneThreshold { + ctor public BlockingZoneThreshold(); + method public final java.util.List<com.android.server.display.config.DisplayBrightnessPoint> getDisplayBrightnessPoint(); + } + public class BrightnessThresholds { ctor public BrightnessThresholds(); method public final com.android.server.display.config.ThresholdPoints getBrightnessThresholdPoints(); @@ -76,6 +89,7 @@ package com.android.server.display.config { method public final com.android.server.display.config.SensorDetails getLightSensor(); method public final com.android.server.display.config.SensorDetails getProxSensor(); method public com.android.server.display.config.DisplayQuirks getQuirks(); + method public com.android.server.display.config.RefreshRateConfigs getRefreshRate(); method @NonNull public final java.math.BigDecimal getScreenBrightnessDefault(); method @NonNull public final com.android.server.display.config.NitsMap getScreenBrightnessMap(); method public final java.math.BigInteger getScreenBrightnessRampDecreaseMaxMillis(); @@ -97,6 +111,7 @@ package com.android.server.display.config { method public final void setLightSensor(com.android.server.display.config.SensorDetails); method public final void setProxSensor(com.android.server.display.config.SensorDetails); method public void setQuirks(com.android.server.display.config.DisplayQuirks); + method public void setRefreshRate(com.android.server.display.config.RefreshRateConfigs); method public final void setScreenBrightnessDefault(@NonNull java.math.BigDecimal); method public final void setScreenBrightnessMap(@NonNull com.android.server.display.config.NitsMap); method public final void setScreenBrightnessRampDecreaseMaxMillis(java.math.BigInteger); @@ -160,6 +175,14 @@ package com.android.server.display.config { method public final void setValue(@NonNull java.math.BigDecimal); } + public class RefreshRateConfigs { + ctor public RefreshRateConfigs(); + method public final com.android.server.display.config.BlockingZoneConfig getHigherBlockingZoneConfigs(); + method public final com.android.server.display.config.BlockingZoneConfig getLowerBlockingZoneConfigs(); + method public final void setHigherBlockingZoneConfigs(com.android.server.display.config.BlockingZoneConfig); + method public final void setLowerBlockingZoneConfigs(com.android.server.display.config.BlockingZoneConfig); + } + public class RefreshRateRange { ctor public RefreshRateRange(); method public final java.math.BigInteger getMaximum(); diff --git a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java index ed369c016770..82236bfd98e0 100644 --- a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java @@ -155,6 +155,18 @@ public class LocalDisplayAdapterTest { when(mMockedResources.getIntArray( com.android.internal.R.array.config_autoBrightnessLevels)) .thenReturn(new int[]{}); + when(mMockedResources.getIntArray( + com.android.internal.R.array.config_brightnessThresholdsOfPeakRefreshRate)) + .thenReturn(new int[]{}); + when(mMockedResources.getIntArray( + com.android.internal.R.array.config_ambientThresholdsOfPeakRefreshRate)) + .thenReturn(new int[]{}); + when(mMockedResources.getIntArray( + com.android.internal.R.array.config_highDisplayBrightnessThresholdsOfFixedRefreshRate)) + .thenReturn(new int[]{}); + when(mMockedResources.getIntArray( + com.android.internal.R.array.config_highAmbientBrightnessThresholdsOfFixedRefreshRate)) + .thenReturn(new int[]{}); } @After diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java index 7f341fff514d..6b705aaf9721 100644 --- a/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java +++ b/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java @@ -150,6 +150,16 @@ public final class DisplayDeviceConfigTest { assertEquals("ProximitySensor123", mDisplayDeviceConfig.getProximitySensor().name); assertEquals("prox_type_1", mDisplayDeviceConfig.getProximitySensor().type); + assertEquals(75, mDisplayDeviceConfig.getDefaultLowRefreshRate()); + assertEquals(90, mDisplayDeviceConfig.getDefaultHighRefreshRate()); + assertArrayEquals(new int[]{45, 55}, + mDisplayDeviceConfig.getLowDisplayBrightnessThresholds()); + assertArrayEquals(new int[]{50, 60}, + mDisplayDeviceConfig.getLowAmbientBrightnessThresholds()); + assertArrayEquals(new int[]{65, 75}, + mDisplayDeviceConfig.getHighDisplayBrightnessThresholds()); + assertArrayEquals(new int[]{70, 80}, + mDisplayDeviceConfig.getHighAmbientBrightnessThresholds()); // Todo(brup): Add asserts for BrightnessThrottlingData, DensityMapping, // HighBrightnessModeData AmbientLightSensor, RefreshRateLimitations and ProximitySensor. @@ -212,9 +222,8 @@ public final class DisplayDeviceConfigTest { mDisplayDeviceConfig.getAmbientDarkeningLevelsIdle(), ZERO_DELTA); assertArrayEquals(new float[]{29, 30, 31}, mDisplayDeviceConfig.getAmbientDarkeningPercentagesIdle(), ZERO_DELTA); - - assertEquals(mDisplayDeviceConfig.getDefaultRefreshRate(), DEFAULT_REFRESH_RATE); - assertEquals(mDisplayDeviceConfig.getDefaultPeakRefreshRate(), DEFAULT_PEAK_REFRESH_RATE); + assertEquals(mDisplayDeviceConfig.getDefaultLowRefreshRate(), DEFAULT_REFRESH_RATE); + assertEquals(mDisplayDeviceConfig.getDefaultHighRefreshRate(), DEFAULT_PEAK_REFRESH_RATE); assertArrayEquals(mDisplayDeviceConfig.getLowDisplayBrightnessThresholds(), LOW_BRIGHTNESS_THRESHOLD_OF_PEAK_REFRESH_RATE); assertArrayEquals(mDisplayDeviceConfig.getLowAmbientBrightnessThresholds(), @@ -426,6 +435,38 @@ public final class DisplayDeviceConfigTest { + "<name>ProximitySensor123</name>\n" + "<type>prox_type_1</type>\n" + "</proxSensor>\n" + + "<refreshRate>\n" + + "<lowerBlockingZoneConfigs>\n" + + "<defaultRefreshRate>75</defaultRefreshRate>\n" + + "<blockingZoneThreshold>\n" + + "<displayBrightnessPoint>\n" + + "<lux>50</lux>\n" + // This number will be rounded to integer when read by the system + + "<nits>45.3</nits>\n" + + "</displayBrightnessPoint>\n" + + "<displayBrightnessPoint>\n" + + "<lux>60</lux>\n" + // This number will be rounded to integer when read by the system + + "<nits>55.2</nits>\n" + + "</displayBrightnessPoint>\n" + + "</blockingZoneThreshold>\n" + + "</lowerBlockingZoneConfigs>\n" + + "<higherBlockingZoneConfigs>\n" + + "<defaultRefreshRate>90</defaultRefreshRate>\n" + + "<blockingZoneThreshold>\n" + + "<displayBrightnessPoint>\n" + + "<lux>70</lux>\n" + // This number will be rounded to integer when read by the system + + "<nits>65.6</nits>\n" + + "</displayBrightnessPoint>\n" + + "<displayBrightnessPoint>\n" + + "<lux>80</lux>\n" + // This number will be rounded to integer when read by the system + + "<nits>75</nits>\n" + + "</displayBrightnessPoint>\n" + + "</blockingZoneThreshold>\n" + + "</higherBlockingZoneConfigs>\n" + + "</refreshRate>\n" + "</displayConfiguration>\n"; } diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java index fb0cdfa9a680..cfea63babac3 100644 --- a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java +++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java @@ -1896,8 +1896,8 @@ public class DisplayModeDirectorTest { // Notify that the default display is updated, such that DisplayDeviceConfig has new values DisplayDeviceConfig displayDeviceConfig = mock(DisplayDeviceConfig.class); - when(displayDeviceConfig.getDefaultRefreshRate()).thenReturn(50); - when(displayDeviceConfig.getDefaultPeakRefreshRate()).thenReturn(55); + when(displayDeviceConfig.getDefaultLowRefreshRate()).thenReturn(50); + when(displayDeviceConfig.getDefaultHighRefreshRate()).thenReturn(55); when(displayDeviceConfig.getLowDisplayBrightnessThresholds()).thenReturn(new int[]{25}); when(displayDeviceConfig.getLowAmbientBrightnessThresholds()).thenReturn(new int[]{30}); when(displayDeviceConfig.getHighDisplayBrightnessThresholds()).thenReturn(new int[]{210}); diff --git a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java index d515fae4afe2..638637d544de 100644 --- a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java +++ b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java @@ -18,10 +18,14 @@ package com.android.server.display; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.DEFAULT_DISPLAY_GROUP; +import static android.view.Display.TYPE_INTERNAL; +import static android.view.Display.TYPE_VIRTUAL; +import static com.android.server.display.DeviceStateToLayoutMap.STATE_DEFAULT; import static com.android.server.display.DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED; import static com.android.server.display.DisplayAdapter.DISPLAY_DEVICE_EVENT_CHANGED; import static com.android.server.display.DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED; +import static com.android.server.display.DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY; import static com.android.server.display.LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_ADDED; import static com.android.server.display.LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_REMOVED; @@ -69,7 +73,6 @@ import org.mockito.Spy; import java.io.InputStream; import java.io.OutputStream; import java.util.Arrays; -import java.util.Set; @SmallTest @Presubmit @@ -151,8 +154,8 @@ public class LogicalDisplayMapperTest { @Test public void testDisplayDeviceAddAndRemove_Internal() { - DisplayDevice device = createDisplayDevice(Display.TYPE_INTERNAL, 600, 800, - DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY); + DisplayDevice device = createDisplayDevice(TYPE_INTERNAL, 600, 800, + FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY); // add LogicalDisplay displayAdded = add(device); @@ -173,7 +176,7 @@ public class LogicalDisplayMapperTest { testDisplayDeviceAddAndRemove_NonInternal(Display.TYPE_EXTERNAL); testDisplayDeviceAddAndRemove_NonInternal(Display.TYPE_WIFI); testDisplayDeviceAddAndRemove_NonInternal(Display.TYPE_OVERLAY); - testDisplayDeviceAddAndRemove_NonInternal(Display.TYPE_VIRTUAL); + testDisplayDeviceAddAndRemove_NonInternal(TYPE_VIRTUAL); testDisplayDeviceAddAndRemove_NonInternal(Display.TYPE_UNKNOWN); // Call the internal test again, just to verify that adding non-internal displays @@ -183,9 +186,9 @@ public class LogicalDisplayMapperTest { @Test public void testDisplayDeviceAdd_TwoInternalOneDefault() { - DisplayDevice device1 = createDisplayDevice(Display.TYPE_INTERNAL, 600, 800, 0); - DisplayDevice device2 = createDisplayDevice(Display.TYPE_INTERNAL, 600, 800, - DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY); + DisplayDevice device1 = createDisplayDevice(TYPE_INTERNAL, 600, 800, 0); + DisplayDevice device2 = createDisplayDevice(TYPE_INTERNAL, 600, 800, + FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY); LogicalDisplay display1 = add(device1); assertEquals(info(display1).address, info(device1).address); @@ -198,10 +201,10 @@ public class LogicalDisplayMapperTest { @Test public void testDisplayDeviceAdd_TwoInternalBothDefault() { - DisplayDevice device1 = createDisplayDevice(Display.TYPE_INTERNAL, 600, 800, - DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY); - DisplayDevice device2 = createDisplayDevice(Display.TYPE_INTERNAL, 600, 800, - DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY); + DisplayDevice device1 = createDisplayDevice(TYPE_INTERNAL, 600, 800, + FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY); + DisplayDevice device2 = createDisplayDevice(TYPE_INTERNAL, 600, 800, + FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY); LogicalDisplay display1 = add(device1); assertEquals(info(display1).address, info(device1).address); @@ -216,7 +219,7 @@ public class LogicalDisplayMapperTest { @Test public void testDisplayDeviceAddAndRemove_OneExternalDefault() { DisplayDevice device = createDisplayDevice(Display.TYPE_EXTERNAL, 600, 800, - DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY); + FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY); // add LogicalDisplay displayAdded = add(device); @@ -234,10 +237,10 @@ public class LogicalDisplayMapperTest { @Test public void testDisplayDeviceAddAndRemove_SwitchDefault() { - DisplayDevice device1 = createDisplayDevice(Display.TYPE_INTERNAL, 600, 800, - DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY); - DisplayDevice device2 = createDisplayDevice(Display.TYPE_INTERNAL, 600, 800, - DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY); + DisplayDevice device1 = createDisplayDevice(TYPE_INTERNAL, 600, 800, + FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY); + DisplayDevice device2 = createDisplayDevice(TYPE_INTERNAL, 600, 800, + FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY); LogicalDisplay display1 = add(device1); assertEquals(info(display1).address, info(device1).address); @@ -263,10 +266,10 @@ public class LogicalDisplayMapperTest { @Test public void testGetDisplayIdsLocked() { - add(createDisplayDevice(Display.TYPE_INTERNAL, 600, 800, - DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY)); + add(createDisplayDevice(TYPE_INTERNAL, 600, 800, + FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY)); add(createDisplayDevice(Display.TYPE_EXTERNAL, 600, 800, 0)); - add(createDisplayDevice(Display.TYPE_VIRTUAL, 600, 800, 0)); + add(createDisplayDevice(TYPE_VIRTUAL, 600, 800, 0)); int [] ids = mLogicalDisplayMapper.getDisplayIdsLocked(Process.SYSTEM_UID, /* includeDisabled= */ true); @@ -276,71 +279,98 @@ public class LogicalDisplayMapperTest { } @Test - public void testGetDisplayInfoForStateLocked_oneDisplayGroup_internalType() { - add(createDisplayDevice(Display.TYPE_INTERNAL, 600, 800, - DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY)); - add(createDisplayDevice(Display.TYPE_INTERNAL, 200, 800, - DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY)); - add(createDisplayDevice(Display.TYPE_INTERNAL, 700, 800, - DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY)); - - Set<DisplayInfo> displayInfos = mLogicalDisplayMapper.getDisplayInfoForStateLocked( - DeviceStateToLayoutMap.STATE_DEFAULT, DEFAULT_DISPLAY, DEFAULT_DISPLAY_GROUP); - assertThat(displayInfos.size()).isEqualTo(1); - for (DisplayInfo displayInfo : displayInfos) { - assertThat(displayInfo.displayId).isEqualTo(DEFAULT_DISPLAY); - assertThat(displayInfo.displayGroupId).isEqualTo(DEFAULT_DISPLAY_GROUP); - assertThat(displayInfo.logicalWidth).isEqualTo(600); - assertThat(displayInfo.logicalHeight).isEqualTo(800); - } - } + public void testGetDisplayInfoForStateLocked_defaultLayout() { + final DisplayDevice device1 = createDisplayDevice(TYPE_INTERNAL, 600, 800, + FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY); + final DisplayDevice device2 = createDisplayDevice(TYPE_INTERNAL, 200, 800, + FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY); - @Test - public void testGetDisplayInfoForStateLocked_oneDisplayGroup_differentTypes() { - add(createDisplayDevice(Display.TYPE_INTERNAL, 600, 800, - DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY)); - add(createDisplayDevice(Display.TYPE_INTERNAL, 200, 800, - DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY)); - add(createDisplayDevice(Display.TYPE_EXTERNAL, 700, 800, - DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY)); - - Set<DisplayInfo> displayInfos = mLogicalDisplayMapper.getDisplayInfoForStateLocked( - DeviceStateToLayoutMap.STATE_DEFAULT, DEFAULT_DISPLAY, DEFAULT_DISPLAY_GROUP); - assertThat(displayInfos.size()).isEqualTo(1); - for (DisplayInfo displayInfo : displayInfos) { - assertThat(displayInfo.displayId).isEqualTo(DEFAULT_DISPLAY); - assertThat(displayInfo.displayGroupId).isEqualTo(DEFAULT_DISPLAY_GROUP); - assertThat(displayInfo.logicalWidth).isEqualTo(600); - assertThat(displayInfo.logicalHeight).isEqualTo(800); - } + add(device1); + add(device2); + + Layout layout1 = new Layout(); + layout1.createDisplayLocked(info(device1).address, /* isDefault= */ true, + /* isEnabled= */ true); + layout1.createDisplayLocked(info(device2).address, /* isDefault= */ false, + /* isEnabled= */ true); + when(mDeviceStateToLayoutMapSpy.get(STATE_DEFAULT)).thenReturn(layout1); + assertThat(layout1.size()).isEqualTo(2); + final int logicalId2 = layout1.getByAddress(info(device2).address).getLogicalDisplayId(); + + final DisplayInfo displayInfoDefault = mLogicalDisplayMapper.getDisplayInfoForStateLocked( + STATE_DEFAULT, DEFAULT_DISPLAY); + assertThat(displayInfoDefault.displayId).isEqualTo(DEFAULT_DISPLAY); + assertThat(displayInfoDefault.logicalWidth).isEqualTo(width(device1)); + assertThat(displayInfoDefault.logicalHeight).isEqualTo(height(device1)); + + final DisplayInfo displayInfoOther = mLogicalDisplayMapper.getDisplayInfoForStateLocked( + STATE_DEFAULT, logicalId2); + assertThat(displayInfoOther).isNotNull(); + assertThat(displayInfoOther.displayId).isEqualTo(logicalId2); + assertThat(displayInfoOther.logicalWidth).isEqualTo(width(device2)); + assertThat(displayInfoOther.logicalHeight).isEqualTo(height(device2)); } @Test - public void testGetDisplayInfoForStateLocked_multipleDisplayGroups_defaultGroup() { - add(createDisplayDevice(Display.TYPE_INTERNAL, 600, 800, - DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY)); - add(createDisplayDevice(Display.TYPE_INTERNAL, 200, 800, - DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY)); - add(createDisplayDevice(Display.TYPE_VIRTUAL, 700, 800, - DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP)); - - Set<DisplayInfo> displayInfos = mLogicalDisplayMapper.getDisplayInfoForStateLocked( - DeviceStateToLayoutMap.STATE_DEFAULT, DEFAULT_DISPLAY, DEFAULT_DISPLAY_GROUP); - assertThat(displayInfos.size()).isEqualTo(1); - for (DisplayInfo displayInfo : displayInfos) { - assertThat(displayInfo.displayId).isEqualTo(DEFAULT_DISPLAY); - assertThat(displayInfo.displayGroupId).isEqualTo(DEFAULT_DISPLAY_GROUP); - assertThat(displayInfo.logicalWidth).isEqualTo(600); - assertThat(displayInfo.logicalHeight).isEqualTo(800); - } + public void testGetDisplayInfoForStateLocked_multipleLayouts() { + final DisplayDevice device1 = createDisplayDevice(TYPE_INTERNAL, 600, 800, + FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY); + final DisplayDevice device2 = createDisplayDevice(TYPE_INTERNAL, 200, 800, + FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY); + final DisplayDevice device3 = createDisplayDevice(TYPE_VIRTUAL, 700, 800, + DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP); + + add(device1); + add(device2); + add(device3); + + Layout layout1 = new Layout(); + layout1.createDisplayLocked(info(device1).address, + /* isDefault= */ true, /* isEnabled= */ true); + when(mDeviceStateToLayoutMapSpy.get(STATE_DEFAULT)).thenReturn(layout1); + + final int layoutState2 = 2; + Layout layout2 = new Layout(); + layout2.createDisplayLocked(info(device2).address, + /* isDefault= */ false, /* isEnabled= */ true); + // Device3 is the default display. + layout2.createDisplayLocked(info(device3).address, + /* isDefault= */ true, /* isEnabled= */ true); + when(mDeviceStateToLayoutMapSpy.get(layoutState2)).thenReturn(layout2); + assertThat(layout2.size()).isEqualTo(2); + final int logicalId2 = layout2.getByAddress(info(device2).address).getLogicalDisplayId(); + + // Default layout. + final DisplayInfo displayInfoLayout1Default = + mLogicalDisplayMapper.getDisplayInfoForStateLocked( + STATE_DEFAULT, DEFAULT_DISPLAY); + assertThat(displayInfoLayout1Default.displayId).isEqualTo(DEFAULT_DISPLAY); + assertThat(displayInfoLayout1Default.logicalWidth).isEqualTo(width(device1)); + assertThat(displayInfoLayout1Default.logicalHeight).isEqualTo(height(device1)); + + // Second layout, where device3 is the default display. + final DisplayInfo displayInfoLayout2Default = + mLogicalDisplayMapper.getDisplayInfoForStateLocked( + layoutState2, DEFAULT_DISPLAY); + assertThat(displayInfoLayout2Default.displayId).isEqualTo(DEFAULT_DISPLAY); + assertThat(displayInfoLayout2Default.logicalWidth).isEqualTo(width(device3)); + assertThat(displayInfoLayout2Default.logicalHeight).isEqualTo(height(device3)); + + final DisplayInfo displayInfoLayout2Other = + mLogicalDisplayMapper.getDisplayInfoForStateLocked( + layoutState2, logicalId2); + assertThat(displayInfoLayout2Other).isNotNull(); + assertThat(displayInfoLayout2Other.displayId).isEqualTo(logicalId2); + assertThat(displayInfoLayout2Other.logicalWidth).isEqualTo(width(device2)); + assertThat(displayInfoLayout2Other.logicalHeight).isEqualTo(height(device2)); } @Test public void testSingleDisplayGroup() { - LogicalDisplay display1 = add(createDisplayDevice(Display.TYPE_INTERNAL, 600, 800, - DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY)); - LogicalDisplay display2 = add(createDisplayDevice(Display.TYPE_INTERNAL, 600, 800, 0)); - LogicalDisplay display3 = add(createDisplayDevice(Display.TYPE_VIRTUAL, 600, 800, 0)); + LogicalDisplay display1 = add(createDisplayDevice(TYPE_INTERNAL, 600, 800, + FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY)); + LogicalDisplay display2 = add(createDisplayDevice(TYPE_INTERNAL, 600, 800, 0)); + LogicalDisplay display3 = add(createDisplayDevice(TYPE_VIRTUAL, 600, 800, 0)); assertEquals(DEFAULT_DISPLAY_GROUP, mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked(id(display1))); @@ -352,12 +382,12 @@ public class LogicalDisplayMapperTest { @Test public void testMultipleDisplayGroups() { - LogicalDisplay display1 = add(createDisplayDevice(Display.TYPE_INTERNAL, 600, 800, - DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY)); - LogicalDisplay display2 = add(createDisplayDevice(Display.TYPE_INTERNAL, 600, 800, 0)); + LogicalDisplay display1 = add(createDisplayDevice(TYPE_INTERNAL, 600, 800, + FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY)); + LogicalDisplay display2 = add(createDisplayDevice(TYPE_INTERNAL, 600, 800, 0)); - TestDisplayDevice device3 = createDisplayDevice(Display.TYPE_VIRTUAL, 600, 800, + TestDisplayDevice device3 = createDisplayDevice(TYPE_VIRTUAL, 600, 800, DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP); LogicalDisplay display3 = add(device3); @@ -423,10 +453,10 @@ public class LogicalDisplayMapperTest { @Test public void testDeviceStateLocked() { - DisplayDevice device1 = createDisplayDevice(Display.TYPE_INTERNAL, 600, 800, - DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY); - DisplayDevice device2 = createDisplayDevice(Display.TYPE_INTERNAL, 600, 800, - DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY); + DisplayDevice device1 = createDisplayDevice(TYPE_INTERNAL, 600, 800, + FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY); + DisplayDevice device2 = createDisplayDevice(TYPE_INTERNAL, 600, 800, + FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY); Layout layout = new Layout(); layout.createDisplayLocked(device1.getDisplayDeviceInfoLocked().address, true, true); @@ -479,13 +509,13 @@ public class LogicalDisplayMapperTest { DisplayAddress displayAddressTwo = new TestUtils.TestDisplayAddress(); DisplayAddress displayAddressThree = new TestUtils.TestDisplayAddress(); - TestDisplayDevice device1 = createDisplayDevice(displayAddressOne, Display.TYPE_INTERNAL, + TestDisplayDevice device1 = createDisplayDevice(displayAddressOne, TYPE_INTERNAL, 600, 800, - DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY); - TestDisplayDevice device2 = createDisplayDevice(displayAddressTwo, Display.TYPE_INTERNAL, + FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY); + TestDisplayDevice device2 = createDisplayDevice(displayAddressTwo, TYPE_INTERNAL, 200, 800, DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP); - TestDisplayDevice device3 = createDisplayDevice(displayAddressThree, Display.TYPE_INTERNAL, + TestDisplayDevice device3 = createDisplayDevice(displayAddressThree, TYPE_INTERNAL, 600, 900, DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP); Layout threeDevicesEnabledLayout = new Layout(); @@ -502,7 +532,7 @@ public class LogicalDisplayMapperTest { /* isDefault= */ false, /* isEnabled= */ true); - when(mDeviceStateToLayoutMapSpy.get(DeviceStateToLayoutMap.STATE_DEFAULT)) + when(mDeviceStateToLayoutMapSpy.get(STATE_DEFAULT)) .thenReturn(threeDevicesEnabledLayout); LogicalDisplay display1 = add(device1); @@ -620,6 +650,14 @@ public class LogicalDisplayMapperTest { return device.getDisplayDeviceInfoLocked(); } + private int width(DisplayDevice device) { + return info(device).width; + } + + private int height(DisplayDevice device) { + return info(device).height; + } + private DisplayInfo info(LogicalDisplay display) { return display.getDisplayInfoLocked(); } diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java index 07009cb9a207..7c7e2ee53f3c 100644 --- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java @@ -75,6 +75,7 @@ import static com.android.server.net.NetworkPolicyManagerService.TYPE_LIMIT_SNOO import static com.android.server.net.NetworkPolicyManagerService.TYPE_RAPID; import static com.android.server.net.NetworkPolicyManagerService.TYPE_WARNING; import static com.android.server.net.NetworkPolicyManagerService.UidBlockedState.getEffectiveBlockedReasons; +import static com.android.server.net.NetworkPolicyManagerService.normalizeTemplate; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -2059,6 +2060,18 @@ public class NetworkPolicyManagerServiceTest { METERED_NO, actualPolicy.template.getMeteredness()); } + @Test + public void testNormalizeTemplate_duplicatedMergedImsiList() { + final NetworkTemplate template = new NetworkTemplate.Builder(MATCH_CARRIER) + .setSubscriberIds(Set.of(TEST_IMSI)).build(); + final String[] mergedImsiGroup = new String[] {TEST_IMSI, TEST_IMSI}; + final ArrayList<String[]> mergedList = new ArrayList<>(); + mergedList.add(mergedImsiGroup); + // Verify the duplicated items in the merged IMSI list won't crash the system. + final NetworkTemplate result = normalizeTemplate(template, mergedList); + assertEquals(template, result); + } + private String formatBlockedStateError(int uid, int rule, boolean metered, boolean backgroundRestricted) { return String.format( diff --git a/services/tests/servicestests/src/com/android/server/power/PowerGroupTest.java b/services/tests/servicestests/src/com/android/server/power/PowerGroupTest.java index e3ca1707ae0c..5bc750f4f6ac 100644 --- a/services/tests/servicestests/src/com/android/server/power/PowerGroupTest.java +++ b/services/tests/servicestests/src/com/android/server/power/PowerGroupTest.java @@ -258,7 +258,6 @@ public class PowerGroupTest { .build(); mPowerGroup.updateLocked(/* screenBrightnessOverride= */ BRIGHTNESS, - /* autoBrightness = */ false, /* useProximitySensor= */ false, /* boostScreenBrightness= */ false, /* dozeScreenStateOverride= */ Display.STATE_ON, @@ -275,7 +274,6 @@ public class PowerGroupTest { mPowerGroup.mDisplayPowerRequest; assertThat(displayPowerRequest.policy).isEqualTo(POLICY_DIM); assertThat(displayPowerRequest.screenBrightnessOverride).isWithin(PRECISION).of(BRIGHTNESS); - assertThat(displayPowerRequest.useAutoBrightness).isEqualTo(false); assertThat(displayPowerRequest.useProximitySensor).isEqualTo(false); assertThat(displayPowerRequest.boostScreenBrightness).isEqualTo(false); assertThat(displayPowerRequest.dozeScreenState).isEqualTo(Display.STATE_UNKNOWN); @@ -299,7 +297,6 @@ public class PowerGroupTest { mPowerGroup.setWakeLockSummaryLocked(WAKE_LOCK_DOZE); mPowerGroup.updateLocked(/* screenBrightnessOverride= */ BRIGHTNESS, - /* autoBrightness = */ true, /* useProximitySensor= */ true, /* boostScreenBrightness= */ true, /* dozeScreenStateOverride= */ Display.STATE_ON, @@ -316,7 +313,6 @@ public class PowerGroupTest { mPowerGroup.mDisplayPowerRequest; assertThat(displayPowerRequest.policy).isEqualTo(POLICY_DOZE); assertThat(displayPowerRequest.screenBrightnessOverride).isWithin(PRECISION).of(BRIGHTNESS); - assertThat(displayPowerRequest.useAutoBrightness).isEqualTo(true); assertThat(displayPowerRequest.useProximitySensor).isEqualTo(true); assertThat(displayPowerRequest.boostScreenBrightness).isEqualTo(true); assertThat(displayPowerRequest.dozeScreenState).isEqualTo(Display.STATE_ON); @@ -339,7 +335,6 @@ public class PowerGroupTest { assertThat(mPowerGroup.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_DOZING); mPowerGroup.updateLocked(/* screenBrightnessOverride= */ BRIGHTNESS, - /* autoBrightness = */ true, /* useProximitySensor= */ true, /* boostScreenBrightness= */ true, /* dozeScreenStateOverride= */ Display.STATE_ON, @@ -356,7 +351,6 @@ public class PowerGroupTest { mPowerGroup.mDisplayPowerRequest; assertThat(displayPowerRequest.policy).isEqualTo(POLICY_OFF); assertThat(displayPowerRequest.screenBrightnessOverride).isWithin(PRECISION).of(BRIGHTNESS); - assertThat(displayPowerRequest.useAutoBrightness).isEqualTo(true); assertThat(displayPowerRequest.useProximitySensor).isEqualTo(true); assertThat(displayPowerRequest.boostScreenBrightness).isEqualTo(true); assertThat(displayPowerRequest.dozeScreenState).isEqualTo(Display.STATE_UNKNOWN); @@ -378,7 +372,6 @@ public class PowerGroupTest { assertThat(mPowerGroup.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE); mPowerGroup.updateLocked(/* screenBrightnessOverride= */ BRIGHTNESS, - /* autoBrightness = */ true, /* useProximitySensor= */ true, /* boostScreenBrightness= */ true, /* dozeScreenStateOverride= */ Display.STATE_ON, @@ -395,7 +388,6 @@ public class PowerGroupTest { mPowerGroup.mDisplayPowerRequest; assertThat(displayPowerRequest.policy).isEqualTo(POLICY_OFF); assertThat(displayPowerRequest.screenBrightnessOverride).isWithin(PRECISION).of(BRIGHTNESS); - assertThat(displayPowerRequest.useAutoBrightness).isEqualTo(true); assertThat(displayPowerRequest.useProximitySensor).isEqualTo(true); assertThat(displayPowerRequest.boostScreenBrightness).isEqualTo(true); assertThat(displayPowerRequest.dozeScreenState).isEqualTo(Display.STATE_UNKNOWN); @@ -417,7 +409,6 @@ public class PowerGroupTest { mPowerGroup.sleepLocked(TIMESTAMP1, UID, GO_TO_SLEEP_REASON_TIMEOUT); assertThat(mPowerGroup.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP); mPowerGroup.updateLocked(/* screenBrightnessOverride= */ BRIGHTNESS, - /* autoBrightness = */ true, /* useProximitySensor= */ true, /* boostScreenBrightness= */ true, /* dozeScreenStateOverride= */ Display.STATE_ON, @@ -434,7 +425,6 @@ public class PowerGroupTest { mPowerGroup.mDisplayPowerRequest; assertThat(displayPowerRequest.policy).isEqualTo(POLICY_OFF); assertThat(displayPowerRequest.screenBrightnessOverride).isWithin(PRECISION).of(BRIGHTNESS); - assertThat(displayPowerRequest.useAutoBrightness).isEqualTo(true); assertThat(displayPowerRequest.useProximitySensor).isEqualTo(true); assertThat(displayPowerRequest.boostScreenBrightness).isEqualTo(true); assertThat(displayPowerRequest.dozeScreenState).isEqualTo(Display.STATE_UNKNOWN); @@ -455,7 +445,6 @@ public class PowerGroupTest { .build(); assertThat(mPowerGroup.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE); mPowerGroup.updateLocked(/* screenBrightnessOverride= */ BRIGHTNESS, - /* autoBrightness = */ true, /* useProximitySensor= */ true, /* boostScreenBrightness= */ true, /* dozeScreenStateOverride= */ Display.STATE_ON, @@ -472,7 +461,6 @@ public class PowerGroupTest { mPowerGroup.mDisplayPowerRequest; assertThat(displayPowerRequest.policy).isEqualTo(POLICY_VR); assertThat(displayPowerRequest.screenBrightnessOverride).isWithin(PRECISION).of(BRIGHTNESS); - assertThat(displayPowerRequest.useAutoBrightness).isEqualTo(true); assertThat(displayPowerRequest.useProximitySensor).isEqualTo(true); assertThat(displayPowerRequest.boostScreenBrightness).isEqualTo(true); assertThat(displayPowerRequest.dozeScreenState).isEqualTo(Display.STATE_UNKNOWN); @@ -494,7 +482,6 @@ public class PowerGroupTest { mPowerGroup.sleepLocked(TIMESTAMP1, UID, GO_TO_SLEEP_REASON_TIMEOUT); assertThat(mPowerGroup.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP); mPowerGroup.updateLocked(/* screenBrightnessOverride= */ BRIGHTNESS, - /* autoBrightness = */ true, /* useProximitySensor= */ true, /* boostScreenBrightness= */ true, /* dozeScreenStateOverride= */ Display.STATE_ON, @@ -511,7 +498,6 @@ public class PowerGroupTest { mPowerGroup.mDisplayPowerRequest; assertThat(displayPowerRequest.policy).isEqualTo(POLICY_OFF); assertThat(displayPowerRequest.screenBrightnessOverride).isWithin(PRECISION).of(BRIGHTNESS); - assertThat(displayPowerRequest.useAutoBrightness).isEqualTo(true); assertThat(displayPowerRequest.useProximitySensor).isEqualTo(true); assertThat(displayPowerRequest.boostScreenBrightness).isEqualTo(true); assertThat(displayPowerRequest.dozeScreenState).isEqualTo(Display.STATE_UNKNOWN); @@ -534,7 +520,6 @@ public class PowerGroupTest { assertThat(mPowerGroup.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_DREAMING); mPowerGroup.setWakeLockSummaryLocked(WAKE_LOCK_SCREEN_BRIGHT); mPowerGroup.updateLocked(/* screenBrightnessOverride= */ BRIGHTNESS, - /* autoBrightness = */ true, /* useProximitySensor= */ true, /* boostScreenBrightness= */ true, /* dozeScreenStateOverride= */ Display.STATE_ON, @@ -551,7 +536,6 @@ public class PowerGroupTest { mPowerGroup.mDisplayPowerRequest; assertThat(displayPowerRequest.policy).isEqualTo(POLICY_BRIGHT); assertThat(displayPowerRequest.screenBrightnessOverride).isWithin(PRECISION).of(BRIGHTNESS); - assertThat(displayPowerRequest.useAutoBrightness).isEqualTo(true); assertThat(displayPowerRequest.useProximitySensor).isEqualTo(true); assertThat(displayPowerRequest.boostScreenBrightness).isEqualTo(true); assertThat(displayPowerRequest.dozeScreenState).isEqualTo(Display.STATE_UNKNOWN); @@ -572,7 +556,6 @@ public class PowerGroupTest { .build(); assertThat(mPowerGroup.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE); mPowerGroup.updateLocked(/* screenBrightnessOverride= */ BRIGHTNESS, - /* autoBrightness = */ true, /* useProximitySensor= */ true, /* boostScreenBrightness= */ true, /* dozeScreenStateOverride= */ Display.STATE_ON, @@ -589,7 +572,6 @@ public class PowerGroupTest { mPowerGroup.mDisplayPowerRequest; assertThat(displayPowerRequest.policy).isEqualTo(POLICY_BRIGHT); assertThat(displayPowerRequest.screenBrightnessOverride).isWithin(PRECISION).of(BRIGHTNESS); - assertThat(displayPowerRequest.useAutoBrightness).isEqualTo(true); assertThat(displayPowerRequest.useProximitySensor).isEqualTo(true); assertThat(displayPowerRequest.boostScreenBrightness).isEqualTo(true); assertThat(displayPowerRequest.dozeScreenState).isEqualTo(Display.STATE_UNKNOWN); @@ -611,7 +593,6 @@ public class PowerGroupTest { assertThat(mPowerGroup.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE); mPowerGroup.setUserActivitySummaryLocked(USER_ACTIVITY_SCREEN_BRIGHT); mPowerGroup.updateLocked(/* screenBrightnessOverride= */ BRIGHTNESS, - /* autoBrightness = */ true, /* useProximitySensor= */ true, /* boostScreenBrightness= */ true, /* dozeScreenStateOverride= */ Display.STATE_ON, @@ -628,7 +609,6 @@ public class PowerGroupTest { mPowerGroup.mDisplayPowerRequest; assertThat(displayPowerRequest.policy).isEqualTo(POLICY_BRIGHT); assertThat(displayPowerRequest.screenBrightnessOverride).isWithin(PRECISION).of(BRIGHTNESS); - assertThat(displayPowerRequest.useAutoBrightness).isEqualTo(true); assertThat(displayPowerRequest.useProximitySensor).isEqualTo(true); assertThat(displayPowerRequest.boostScreenBrightness).isEqualTo(true); assertThat(displayPowerRequest.dozeScreenState).isEqualTo(Display.STATE_UNKNOWN); @@ -649,7 +629,6 @@ public class PowerGroupTest { .build(); assertThat(mPowerGroup.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE); mPowerGroup.updateLocked(/* screenBrightnessOverride= */ BRIGHTNESS, - /* autoBrightness = */ true, /* useProximitySensor= */ true, /* boostScreenBrightness= */ true, /* dozeScreenStateOverride= */ Display.STATE_ON, @@ -666,7 +645,6 @@ public class PowerGroupTest { mPowerGroup.mDisplayPowerRequest; assertThat(displayPowerRequest.policy).isEqualTo(POLICY_BRIGHT); assertThat(displayPowerRequest.screenBrightnessOverride).isWithin(PRECISION).of(BRIGHTNESS); - assertThat(displayPowerRequest.useAutoBrightness).isEqualTo(true); assertThat(displayPowerRequest.useProximitySensor).isEqualTo(true); assertThat(displayPowerRequest.boostScreenBrightness).isEqualTo(true); assertThat(displayPowerRequest.dozeScreenState).isEqualTo(Display.STATE_UNKNOWN); diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java index 11ac929327b9..c8932550d877 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java @@ -38,6 +38,7 @@ import static com.android.server.wm.WindowContainer.POSITION_TOP; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyInt; @@ -98,12 +99,25 @@ public class TaskFragmentTest extends WindowTestsBase { } @Test - public void testOnConfigurationChanged_updateSurface() { - final Rect bounds = new Rect(100, 100, 1100, 1100); + public void testOnConfigurationChanged() { + final Configuration parentConfig = mTaskFragment.getParent().getConfiguration(); + final Rect parentBounds = parentConfig.windowConfiguration.getBounds(); + parentConfig.smallestScreenWidthDp += 10; + final int parentSw = parentConfig.smallestScreenWidthDp; + final Rect bounds = new Rect(parentBounds); + bounds.inset(100, 100); mTaskFragment.setBounds(bounds); + mTaskFragment.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); + // Calculate its own sw with smaller bounds in multi-window mode. + assertNotEquals(parentSw, mTaskFragment.getConfiguration().smallestScreenWidthDp); - verify(mTransaction).setPosition(mLeash, 100, 100); - verify(mTransaction).setWindowCrop(mLeash, 1000, 1000); + verify(mTransaction).setPosition(mLeash, bounds.left, bounds.top); + verify(mTransaction).setWindowCrop(mLeash, bounds.width(), bounds.height()); + + mTaskFragment.setBounds(parentBounds); + mTaskFragment.setWindowingMode(WINDOWING_MODE_FULLSCREEN); + // Inherit parent's sw in fullscreen mode. + assertEquals(parentSw, mTaskFragment.getConfiguration().smallestScreenWidthDp); } @Test diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordAudioStreamManager.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordAudioStreamCopier.java index d5eea1f3ff35..b9d2ae6b0d39 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordAudioStreamManager.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordAudioStreamCopier.java @@ -17,16 +17,23 @@ package com.android.server.voiceinteraction; import static android.app.AppOpsManager.MODE_ALLOWED; +import static android.service.voice.HotwordAudioStream.KEY_AUDIO_STREAM_COPY_BUFFER_LENGTH_BYTES; +import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_CLOSE_ERROR_FROM_SYSTEM; +import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_EMPTY_AUDIO_STREAM_LIST; +import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_END; +import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_ILLEGAL_COPY_BUFFER_SIZE; +import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_INTERRUPTED_EXCEPTION; +import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_NO_PERMISSION; +import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_START; import static com.android.server.voiceinteraction.HotwordDetectionConnection.DEBUG; import android.annotation.NonNull; import android.app.AppOpsManager; -import android.media.permission.Identity; import android.os.ParcelFileDescriptor; +import android.os.PersistableBundle; import android.service.voice.HotwordAudioStream; import android.service.voice.HotwordDetectedResult; -import android.util.Pair; import android.util.Slog; import java.io.IOException; @@ -39,21 +46,40 @@ import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -final class HotwordAudioStreamManager { +/** + * Copies the audio streams in {@link HotwordDetectedResult}s. This allows the system to manage the + * lifetime of the {@link ParcelFileDescriptor}s and ensures that the flow of data is in the right + * direction from the {@link android.service.voice.HotwordDetectionService} to the client (i.e., the + * voice interactor). + * + * @hide + */ +final class HotwordAudioStreamCopier { - private static final String TAG = "HotwordAudioStreamManager"; + private static final String TAG = "HotwordAudioStreamCopier"; private static final String OP_MESSAGE = "Streaming hotword audio to VoiceInteractionService"; private static final String TASK_ID_PREFIX = "HotwordDetectedResult@"; private static final String THREAD_NAME_PREFIX = "Copy-"; + private static final int DEFAULT_COPY_BUFFER_LENGTH_BYTES = 2_560; + + // Corresponds to the OS pipe capacity in bytes + private static final int MAX_COPY_BUFFER_LENGTH_BYTES = 65_536; private final AppOpsManager mAppOpsManager; - private final Identity mVoiceInteractorIdentity; + private final int mDetectorType; + private final int mVoiceInteractorUid; + private final String mVoiceInteractorPackageName; + private final String mVoiceInteractorAttributionTag; private final ExecutorService mExecutorService = Executors.newCachedThreadPool(); - HotwordAudioStreamManager(@NonNull AppOpsManager appOpsManager, - @NonNull Identity voiceInteractorIdentity) { + HotwordAudioStreamCopier(@NonNull AppOpsManager appOpsManager, int detectorType, + int voiceInteractorUid, @NonNull String voiceInteractorPackageName, + @NonNull String voiceInteractorAttributionTag) { mAppOpsManager = appOpsManager; - mVoiceInteractorIdentity = voiceInteractorIdentity; + mDetectorType = detectorType; + mVoiceInteractorUid = voiceInteractorUid; + mVoiceInteractorPackageName = voiceInteractorPackageName; + mVoiceInteractorAttributionTag = voiceInteractorAttributionTag; } /** @@ -61,7 +87,7 @@ final class HotwordAudioStreamManager { * <p> * The returned {@link HotwordDetectedResult} is identical the one that was passed in, except * that the {@link ParcelFileDescriptor}s within {@link HotwordDetectedResult#getAudioStreams()} - * are replaced with descriptors from pipes managed by {@link HotwordAudioStreamManager}. The + * are replaced with descriptors from pipes managed by {@link HotwordAudioStreamCopier}. The * returned value should be passed on to the client (i.e., the voice interactor). * </p> * @@ -72,12 +98,14 @@ final class HotwordAudioStreamManager { throws IOException { List<HotwordAudioStream> audioStreams = result.getAudioStreams(); if (audioStreams.isEmpty()) { + HotwordMetricsLogger.writeDetectorEvent(mDetectorType, + HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_EMPTY_AUDIO_STREAM_LIST, + mVoiceInteractorUid); return result; } List<HotwordAudioStream> newAudioStreams = new ArrayList<>(audioStreams.size()); - List<Pair<ParcelFileDescriptor, ParcelFileDescriptor>> sourcesAndSinks = new ArrayList<>( - audioStreams.size()); + List<CopyTaskInfo> copyTaskInfos = new ArrayList<>(audioStreams.size()); for (HotwordAudioStream audioStream : audioStreams) { ParcelFileDescriptor[] clientPipe = ParcelFileDescriptor.createReliablePipe(); ParcelFileDescriptor clientAudioSource = clientPipe[0]; @@ -87,74 +115,114 @@ final class HotwordAudioStreamManager { clientAudioSource).build(); newAudioStreams.add(newAudioStream); + int copyBufferLength = DEFAULT_COPY_BUFFER_LENGTH_BYTES; + PersistableBundle metadata = audioStream.getMetadata(); + if (metadata.containsKey(KEY_AUDIO_STREAM_COPY_BUFFER_LENGTH_BYTES)) { + copyBufferLength = metadata.getInt(KEY_AUDIO_STREAM_COPY_BUFFER_LENGTH_BYTES, -1); + if (copyBufferLength < 1 || copyBufferLength > MAX_COPY_BUFFER_LENGTH_BYTES) { + HotwordMetricsLogger.writeDetectorEvent(mDetectorType, + HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_ILLEGAL_COPY_BUFFER_SIZE, + mVoiceInteractorUid); + Slog.w(TAG, "Attempted to set an invalid copy buffer length (" + + copyBufferLength + ") for: " + audioStream); + copyBufferLength = DEFAULT_COPY_BUFFER_LENGTH_BYTES; + } else if (DEBUG) { + Slog.i(TAG, "Copy buffer length set to " + copyBufferLength + " for: " + + audioStream); + } + } + ParcelFileDescriptor serviceAudioSource = audioStream.getAudioStreamParcelFileDescriptor(); - sourcesAndSinks.add(new Pair<>(serviceAudioSource, clientAudioSink)); + copyTaskInfos.add(new CopyTaskInfo(serviceAudioSource, clientAudioSink, + copyBufferLength)); } String resultTaskId = TASK_ID_PREFIX + System.identityHashCode(result); - mExecutorService.execute(new HotwordDetectedResultCopyTask(resultTaskId, sourcesAndSinks)); + mExecutorService.execute(new HotwordDetectedResultCopyTask(resultTaskId, copyTaskInfos)); return result.buildUpon().setAudioStreams(newAudioStreams).build(); } + private static class CopyTaskInfo { + private final ParcelFileDescriptor mSource; + private final ParcelFileDescriptor mSink; + private final int mCopyBufferLength; + + CopyTaskInfo(ParcelFileDescriptor source, ParcelFileDescriptor sink, int copyBufferLength) { + mSource = source; + mSink = sink; + mCopyBufferLength = copyBufferLength; + } + } + private class HotwordDetectedResultCopyTask implements Runnable { private final String mResultTaskId; - private final List<Pair<ParcelFileDescriptor, ParcelFileDescriptor>> mSourcesAndSinks; + private final List<CopyTaskInfo> mCopyTaskInfos; private final ExecutorService mExecutorService = Executors.newCachedThreadPool(); - HotwordDetectedResultCopyTask(String resultTaskId, - List<Pair<ParcelFileDescriptor, ParcelFileDescriptor>> sourcesAndSinks) { + HotwordDetectedResultCopyTask(String resultTaskId, List<CopyTaskInfo> copyTaskInfos) { mResultTaskId = resultTaskId; - mSourcesAndSinks = sourcesAndSinks; + mCopyTaskInfos = copyTaskInfos; } @Override public void run() { Thread.currentThread().setName(THREAD_NAME_PREFIX + mResultTaskId); - int size = mSourcesAndSinks.size(); + int size = mCopyTaskInfos.size(); List<SingleAudioStreamCopyTask> tasks = new ArrayList<>(size); for (int i = 0; i < size; i++) { - Pair<ParcelFileDescriptor, ParcelFileDescriptor> sourceAndSink = - mSourcesAndSinks.get(i); - ParcelFileDescriptor serviceAudioSource = sourceAndSink.first; - ParcelFileDescriptor clientAudioSink = sourceAndSink.second; + CopyTaskInfo copyTaskInfo = mCopyTaskInfos.get(i); String streamTaskId = mResultTaskId + "@" + i; - tasks.add(new SingleAudioStreamCopyTask(streamTaskId, serviceAudioSource, - clientAudioSink)); + tasks.add(new SingleAudioStreamCopyTask(streamTaskId, copyTaskInfo.mSource, + copyTaskInfo.mSink, copyTaskInfo.mCopyBufferLength, mDetectorType, + mVoiceInteractorUid)); } if (mAppOpsManager.startOpNoThrow(AppOpsManager.OPSTR_RECORD_AUDIO_HOTWORD, - mVoiceInteractorIdentity.uid, mVoiceInteractorIdentity.packageName, - mVoiceInteractorIdentity.attributionTag, OP_MESSAGE) == MODE_ALLOWED) { + mVoiceInteractorUid, mVoiceInteractorPackageName, + mVoiceInteractorAttributionTag, OP_MESSAGE) == MODE_ALLOWED) { try { + HotwordMetricsLogger.writeDetectorEvent(mDetectorType, + HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_START, + mVoiceInteractorUid); // TODO(b/244599891): Set timeout, close after inactivity mExecutorService.invokeAll(tasks); + HotwordMetricsLogger.writeDetectorEvent(mDetectorType, + HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_END, + mVoiceInteractorUid); } catch (InterruptedException e) { + HotwordMetricsLogger.writeDetectorEvent(mDetectorType, + HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_INTERRUPTED_EXCEPTION, + mVoiceInteractorUid); Slog.e(TAG, mResultTaskId + ": Task was interrupted", e); bestEffortPropagateError(e.getMessage()); } finally { mAppOpsManager.finishOp(AppOpsManager.OPSTR_RECORD_AUDIO_HOTWORD, - mVoiceInteractorIdentity.uid, mVoiceInteractorIdentity.packageName, - mVoiceInteractorIdentity.attributionTag); + mVoiceInteractorUid, mVoiceInteractorPackageName, + mVoiceInteractorAttributionTag); } } else { + HotwordMetricsLogger.writeDetectorEvent(mDetectorType, + HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_NO_PERMISSION, + mVoiceInteractorUid); bestEffortPropagateError( - "Failed to obtain RECORD_AUDIO_HOTWORD permission for " - + SoundTriggerSessionPermissionsDecorator.toString( - mVoiceInteractorIdentity)); + "Failed to obtain RECORD_AUDIO_HOTWORD permission for voice interactor with" + + " uid=" + mVoiceInteractorUid + + " packageName=" + mVoiceInteractorPackageName + + " attributionTag=" + mVoiceInteractorAttributionTag); } } private void bestEffortPropagateError(@NonNull String errorMessage) { try { - for (Pair<ParcelFileDescriptor, ParcelFileDescriptor> sourceAndSink : - mSourcesAndSinks) { - ParcelFileDescriptor serviceAudioSource = sourceAndSink.first; - ParcelFileDescriptor clientAudioSink = sourceAndSink.second; - serviceAudioSource.closeWithError(errorMessage); - clientAudioSink.closeWithError(errorMessage); + for (CopyTaskInfo copyTaskInfo : mCopyTaskInfos) { + copyTaskInfo.mSource.closeWithError(errorMessage); + copyTaskInfo.mSink.closeWithError(errorMessage); } + HotwordMetricsLogger.writeDetectorEvent(mDetectorType, + HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_CLOSE_ERROR_FROM_SYSTEM, + mVoiceInteractorUid); } catch (IOException e) { Slog.e(TAG, mResultTaskId + ": Failed to propagate error", e); } @@ -162,18 +230,21 @@ final class HotwordAudioStreamManager { } private static class SingleAudioStreamCopyTask implements Callable<Void> { - // TODO: Make this buffer size customizable from updateState() - private static final int COPY_BUFFER_LENGTH = 2_560; - private final String mStreamTaskId; private final ParcelFileDescriptor mAudioSource; private final ParcelFileDescriptor mAudioSink; + private final int mCopyBufferLength; + private final int mDetectorType; + private final int mUid; SingleAudioStreamCopyTask(String streamTaskId, ParcelFileDescriptor audioSource, - ParcelFileDescriptor audioSink) { + ParcelFileDescriptor audioSink, int copyBufferLength, int detectorType, int uid) { mStreamTaskId = streamTaskId; mAudioSource = audioSource; mAudioSink = audioSink; + mCopyBufferLength = copyBufferLength; + mDetectorType = detectorType; + mUid = uid; } @Override @@ -189,7 +260,7 @@ final class HotwordAudioStreamManager { try { fis = new ParcelFileDescriptor.AutoCloseInputStream(mAudioSource); fos = new ParcelFileDescriptor.AutoCloseOutputStream(mAudioSink); - byte[] buffer = new byte[COPY_BUFFER_LENGTH]; + byte[] buffer = new byte[mCopyBufferLength]; while (true) { if (Thread.interrupted()) { Slog.e(TAG, @@ -217,6 +288,8 @@ final class HotwordAudioStreamManager { mAudioSource.closeWithError(e.getMessage()); mAudioSink.closeWithError(e.getMessage()); Slog.e(TAG, mStreamTaskId + ": Failed to copy audio stream", e); + HotwordMetricsLogger.writeDetectorEvent(mDetectorType, + HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_CLOSE_ERROR_FROM_SYSTEM, mUid); } finally { if (fis != null) { fis.close(); diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java index 6f7d80caa147..55bf2ab3a0e9 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java @@ -170,7 +170,7 @@ final class HotwordDetectionConnection { private final ScheduledExecutorService mScheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); private final AppOpsManager mAppOpsManager; - private final HotwordAudioStreamManager mHotwordAudioStreamManager; + private final HotwordAudioStreamCopier mHotwordAudioStreamCopier; @Nullable private final ScheduledFuture<?> mCancellationTaskFuture; private final AtomicBoolean mUpdateStateAfterStartFinished = new AtomicBoolean(false); private final IBinder.DeathRecipient mAudioServerDeathRecipient = this::audioServerDied; @@ -232,8 +232,9 @@ final class HotwordDetectionConnection { mVoiceInteractionServiceUid = voiceInteractionServiceUid; mVoiceInteractorIdentity = voiceInteractorIdentity; mAppOpsManager = mContext.getSystemService(AppOpsManager.class); - mHotwordAudioStreamManager = new HotwordAudioStreamManager(mAppOpsManager, - mVoiceInteractorIdentity); + mHotwordAudioStreamCopier = new HotwordAudioStreamCopier(mAppOpsManager, detectorType, + mVoiceInteractorIdentity.uid, mVoiceInteractorIdentity.packageName, + mVoiceInteractorIdentity.attributionTag); mDetectionComponentName = serviceName; mUser = userId; mCallback = callback; @@ -267,7 +268,8 @@ final class HotwordDetectionConnection { synchronized (mLock) { restartProcessLocked(); HotwordMetricsLogger.writeServiceRestartEvent(mDetectorType, - HOTWORD_DETECTION_SERVICE_RESTARTED__REASON__SCHEDULE); + HOTWORD_DETECTION_SERVICE_RESTARTED__REASON__SCHEDULE, + mVoiceInteractionServiceUid); } }, mReStartPeriodSeconds, mReStartPeriodSeconds, TimeUnit.SECONDS); } @@ -302,7 +304,8 @@ final class HotwordDetectionConnection { // conditions with audio reading in the service. restartProcessLocked(); HotwordMetricsLogger.writeServiceRestartEvent(mDetectorType, - HOTWORD_DETECTION_SERVICE_RESTARTED__REASON__AUDIO_SERVICE_DIED); + HOTWORD_DETECTION_SERVICE_RESTARTED__REASON__AUDIO_SERVICE_DIED, + mVoiceInteractionServiceUid); } } @@ -333,13 +336,14 @@ final class HotwordDetectionConnection { try { mCallback.onStatusReported(status); HotwordMetricsLogger.writeServiceInitResultEvent(mDetectorType, - initResultMetricsResult); + initResultMetricsResult, mVoiceInteractionServiceUid); } catch (RemoteException e) { // TODO: Add a new atom for RemoteException case, the error doesn't very // correct here Slog.w(TAG, "Failed to report initialization status: " + e); HotwordMetricsLogger.writeServiceInitResultEvent(mDetectorType, - METRICS_INIT_CALLBACK_STATE_ERROR); + METRICS_INIT_CALLBACK_STATE_ERROR, + mVoiceInteractionServiceUid); } } }; @@ -362,11 +366,12 @@ final class HotwordDetectionConnection { try { mCallback.onStatusReported(INITIALIZATION_STATUS_UNKNOWN); HotwordMetricsLogger.writeServiceInitResultEvent(mDetectorType, - METRICS_INIT_UNKNOWN_TIMEOUT); + METRICS_INIT_UNKNOWN_TIMEOUT, mVoiceInteractionServiceUid); } catch (RemoteException e) { Slog.w(TAG, "Failed to report initialization status UNKNOWN", e); HotwordMetricsLogger.writeServiceInitResultEvent(mDetectorType, - METRICS_INIT_CALLBACK_STATE_ERROR); + METRICS_INIT_CALLBACK_STATE_ERROR, + mVoiceInteractionServiceUid); } } else if (err != null) { Slog.w(TAG, "Failed to update state: " + err); @@ -469,12 +474,14 @@ final class HotwordDetectionConnection { synchronized (mLock) { HotwordMetricsLogger.writeKeyphraseTriggerEvent( mDetectorType, - HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__DETECTED); + HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__DETECTED, + mVoiceInteractionServiceUid); if (!mPerformingSoftwareHotwordDetection) { Slog.i(TAG, "Hotword detection has already completed"); HotwordMetricsLogger.writeKeyphraseTriggerEvent( mDetectorType, - METRICS_KEYPHRASE_TRIGGERED_DETECT_UNEXPECTED_CALLBACK); + METRICS_KEYPHRASE_TRIGGERED_DETECT_UNEXPECTED_CALLBACK, + mVoiceInteractionServiceUid); return; } mPerformingSoftwareHotwordDetection = false; @@ -483,14 +490,15 @@ final class HotwordDetectionConnection { } catch (SecurityException e) { HotwordMetricsLogger.writeKeyphraseTriggerEvent( mDetectorType, - METRICS_KEYPHRASE_TRIGGERED_DETECT_SECURITY_EXCEPTION); + METRICS_KEYPHRASE_TRIGGERED_DETECT_SECURITY_EXCEPTION, + mVoiceInteractionServiceUid); mSoftwareCallback.onError(); return; } saveProximityValueToBundle(result); HotwordDetectedResult newResult; try { - newResult = mHotwordAudioStreamManager.startCopyingAudioStreams(result); + newResult = mHotwordAudioStreamCopier.startCopyingAudioStreams(result); } catch (IOException e) { // TODO: Write event mSoftwareCallback.onError(); @@ -512,7 +520,8 @@ final class HotwordDetectionConnection { } HotwordMetricsLogger.writeKeyphraseTriggerEvent( mDetectorType, - HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__REJECTED); + HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__REJECTED, + mVoiceInteractionServiceUid); // onRejected isn't allowed here, and we are not expecting it. } }; @@ -660,12 +669,14 @@ final class HotwordDetectionConnection { } HotwordMetricsLogger.writeKeyphraseTriggerEvent( mDetectorType, - HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__DETECTED); + HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__DETECTED, + mVoiceInteractionServiceUid); if (!mValidatingDspTrigger) { Slog.i(TAG, "Ignoring #onDetected due to a process restart"); HotwordMetricsLogger.writeKeyphraseTriggerEvent( mDetectorType, - METRICS_KEYPHRASE_TRIGGERED_DETECT_UNEXPECTED_CALLBACK); + METRICS_KEYPHRASE_TRIGGERED_DETECT_UNEXPECTED_CALLBACK, + mVoiceInteractionServiceUid); return; } mValidatingDspTrigger = false; @@ -675,14 +686,15 @@ final class HotwordDetectionConnection { Slog.i(TAG, "Ignoring #onDetected due to a SecurityException", e); HotwordMetricsLogger.writeKeyphraseTriggerEvent( mDetectorType, - METRICS_KEYPHRASE_TRIGGERED_DETECT_SECURITY_EXCEPTION); + METRICS_KEYPHRASE_TRIGGERED_DETECT_SECURITY_EXCEPTION, + mVoiceInteractionServiceUid); externalCallback.onError(CALLBACK_ONDETECTED_GOT_SECURITY_EXCEPTION); return; } saveProximityValueToBundle(result); HotwordDetectedResult newResult; try { - newResult = mHotwordAudioStreamManager.startCopyingAudioStreams(result); + newResult = mHotwordAudioStreamCopier.startCopyingAudioStreams(result); } catch (IOException e) { // TODO: Write event externalCallback.onError(CALLBACK_ONDETECTED_STREAM_COPY_ERROR); @@ -708,12 +720,14 @@ final class HotwordDetectionConnection { } HotwordMetricsLogger.writeKeyphraseTriggerEvent( mDetectorType, - HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__REJECTED); + HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__REJECTED, + mVoiceInteractionServiceUid); if (!mValidatingDspTrigger) { Slog.i(TAG, "Ignoring #onRejected due to a process restart"); HotwordMetricsLogger.writeKeyphraseTriggerEvent( mDetectorType, - METRICS_KEYPHRASE_TRIGGERED_REJECT_UNEXPECTED_CALLBACK); + METRICS_KEYPHRASE_TRIGGERED_REJECT_UNEXPECTED_CALLBACK, + mVoiceInteractionServiceUid); return; } mValidatingDspTrigger = false; @@ -727,21 +741,20 @@ final class HotwordDetectionConnection { synchronized (mLock) { mValidatingDspTrigger = true; - mRemoteHotwordDetectionService.run( - service -> { - // TODO: avoid allocate every time - mCancellationKeyPhraseDetectionFuture = mScheduledExecutorService.schedule( - () -> HotwordMetricsLogger - .writeKeyphraseTriggerEvent(mDetectorType, - HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__DETECT_TIMEOUT), - VALIDATION_TIMEOUT_MILLIS, - TimeUnit.MILLISECONDS); - service.detectFromDspSource( - recognitionEvent, - recognitionEvent.getCaptureFormat(), - VALIDATION_TIMEOUT_MILLIS, - internalCallback); - }); + mRemoteHotwordDetectionService.run(service -> { + // TODO: avoid allocate every time + mCancellationKeyPhraseDetectionFuture = mScheduledExecutorService.schedule( + () -> HotwordMetricsLogger.writeKeyphraseTriggerEvent(mDetectorType, + HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__DETECT_TIMEOUT, + mVoiceInteractionServiceUid), + VALIDATION_TIMEOUT_MILLIS, + TimeUnit.MILLISECONDS); + service.detectFromDspSource( + recognitionEvent, + recognitionEvent.getCaptureFormat(), + VALIDATION_TIMEOUT_MILLIS, + internalCallback); + }); } } @@ -789,7 +802,8 @@ final class HotwordDetectionConnection { mCallback.onRejected(new HotwordRejectedResult.Builder().build()); HotwordMetricsLogger.writeKeyphraseTriggerEvent( mDetectorType, - HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__REJECTED_FROM_RESTART); + HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__REJECTED_FROM_RESTART, + mVoiceInteractionServiceUid); } catch (RemoteException e) { Slog.w(TAG, "Failed to call #rejected"); } @@ -835,11 +849,13 @@ final class HotwordDetectionConnection { private SoundTrigger.KeyphraseRecognitionEvent mRecognitionEvent; private final HotwordDetectionConnection mHotwordDetectionConnection; private final IHotwordRecognitionStatusCallback mExternalCallback; + private final int mVoiceInteractionServiceUid; SoundTriggerCallback(IHotwordRecognitionStatusCallback callback, - HotwordDetectionConnection connection) { + HotwordDetectionConnection connection, int uid) { mHotwordDetectionConnection = connection; mExternalCallback = callback; + mVoiceInteractionServiceUid = uid; } @Override @@ -852,14 +868,16 @@ final class HotwordDetectionConnection { if (useHotwordDetectionService) { HotwordMetricsLogger.writeKeyphraseTriggerEvent( HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__DETECTOR_TYPE__TRUSTED_DETECTOR_DSP, - HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__KEYPHRASE_TRIGGER); + HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__KEYPHRASE_TRIGGER, + mVoiceInteractionServiceUid); mRecognitionEvent = recognitionEvent; mHotwordDetectionConnection.detectFromDspSource( recognitionEvent, mExternalCallback); } else { HotwordMetricsLogger.writeKeyphraseTriggerEvent( HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__DETECTOR_TYPE__NORMAL_DETECTOR, - HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__KEYPHRASE_TRIGGER); + HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__KEYPHRASE_TRIGGER, + mVoiceInteractionServiceUid); mExternalCallback.onKeyphraseDetected(recognitionEvent, null); } } @@ -1014,7 +1032,7 @@ final class HotwordDetectionConnection { HotwordDetectedResult newResult; try { newResult = - mHotwordAudioStreamManager.startCopyingAudioStreams( + mHotwordAudioStreamCopier.startCopyingAudioStreams( triggerResult); } catch (IOException e) { // TODO: Write event diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordMetricsLogger.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordMetricsLogger.java index 940aed34b7fb..61c18be6f133 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordMetricsLogger.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordMetricsLogger.java @@ -64,28 +64,28 @@ public final class HotwordMetricsLogger { /** * Logs information related to hotword detection service init result. */ - public static void writeServiceInitResultEvent(int detectorType, int result) { + public static void writeServiceInitResultEvent(int detectorType, int result, int uid) { int metricsDetectorType = getInitMetricsDetectorType(detectorType); FrameworkStatsLog.write(FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED, - metricsDetectorType, result); + metricsDetectorType, result, uid); } /** * Logs information related to hotword detection service restarting. */ - public static void writeServiceRestartEvent(int detectorType, int reason) { + public static void writeServiceRestartEvent(int detectorType, int reason, int uid) { int metricsDetectorType = getRestartMetricsDetectorType(detectorType); FrameworkStatsLog.write(FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_RESTARTED, - metricsDetectorType, reason); + metricsDetectorType, reason, uid); } /** * Logs information related to keyphrase trigger. */ - public static void writeKeyphraseTriggerEvent(int detectorType, int result) { + public static void writeKeyphraseTriggerEvent(int detectorType, int result, int uid) { int metricsDetectorType = getKeyphraseMetricsDetectorType(detectorType); FrameworkStatsLog.write(FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED, - metricsDetectorType, result); + metricsDetectorType, result, uid); } /** diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java index f90fbb249f5d..c4f341e951da 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java @@ -711,7 +711,7 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne Slog.d(TAG, "createSoundTriggerCallbackLocked"); } return new HotwordDetectionConnection.SoundTriggerCallback(callback, - mHotwordDetectionConnection); + mHotwordDetectionConnection, mInfo.getServiceInfo().applicationInfo.uid); } private static ServiceInfo getServiceInfoLocked(@NonNull ComponentName componentName, @@ -880,5 +880,8 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne @Override public void onSessionHidden(VoiceInteractionSessionConnection connection) { mServiceStub.onSessionHidden(); + // Notifies visibility change here can cause duplicate events, it is added to make sure + // client always get the callback even if session is unexpectedly closed. + mServiceStub.setSessionWindowVisible(connection.mToken, false); } } |