diff options
383 files changed, 5211 insertions, 1927 deletions
diff --git a/core/java/android/app/servertransaction/LaunchActivityItem.java b/core/java/android/app/servertransaction/LaunchActivityItem.java index 7dcbebaeba0b..7819e1ef94c6 100644 --- a/core/java/android/app/servertransaction/LaunchActivityItem.java +++ b/core/java/android/app/servertransaction/LaunchActivityItem.java @@ -104,8 +104,8 @@ public class LaunchActivityItem extends ClientTransactionItem { public void execute(@NonNull ClientTransactionHandler client, @NonNull PendingTransactionActions pendingActions) { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart"); - ActivityClientRecord r = new ActivityClientRecord(mActivityToken, mIntent, mIdent, mInfo, - mOverrideConfig, mReferrer, mVoiceInteractor, mState, mPersistentState, + final ActivityClientRecord r = new ActivityClientRecord(mActivityToken, mIntent, mIdent, + mInfo, mOverrideConfig, mReferrer, mVoiceInteractor, mState, mPersistentState, mPendingResults, mPendingNewIntents, mSceneTransitionInfo, mIsForward, mProfilerInfo, client, mAssistToken, mShareableActivityToken, mLaunchedFromBubble, mTaskFragmentToken, mInitialCallerInfoAccessToken, mActivityWindowInfo); diff --git a/core/java/android/app/servertransaction/WindowStateInsetsControlChangeItem.java b/core/java/android/app/servertransaction/WindowStateInsetsControlChangeItem.java index ee04f8cbe3c7..1c8e497edd0a 100644 --- a/core/java/android/app/servertransaction/WindowStateInsetsControlChangeItem.java +++ b/core/java/android/app/servertransaction/WindowStateInsetsControlChangeItem.java @@ -16,8 +16,6 @@ package android.app.servertransaction; -import static java.util.Objects.requireNonNull; - import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ClientTransactionHandler; @@ -35,23 +33,19 @@ import java.util.Objects; * Message to deliver window insets control change info. * @hide */ -public class WindowStateInsetsControlChangeItem extends ClientTransactionItem { +public class WindowStateInsetsControlChangeItem extends WindowStateTransactionItem { private static final String TAG = "WindowStateInsetsControlChangeItem"; - private IWindow mWindow; private InsetsState mInsetsState; private InsetsSourceControl.Array mActiveControls; @Override - public void execute(@NonNull ClientTransactionHandler client, + public void execute(@NonNull ClientTransactionHandler client, @NonNull IWindow window, @NonNull PendingTransactionActions pendingActions) { Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "windowInsetsControlChanged"); - if (mWindow instanceof InsetsControlChangeListener listener) { - listener.onExecutingWindowStateInsetsControlChangeItem(); - } try { - mWindow.insetsControlChanged(mInsetsState, mActiveControls); + window.insetsControlChanged(mInsetsState, mActiveControls); } catch (RemoteException e) { // Should be a local call. // An exception could happen if the process is restarted. It is safe to ignore since @@ -73,7 +67,7 @@ public class WindowStateInsetsControlChangeItem extends ClientTransactionItem { if (instance == null) { instance = new WindowStateInsetsControlChangeItem(); } - instance.mWindow = requireNonNull(window); + instance.setWindow(window); instance.mInsetsState = new InsetsState(insetsState, true /* copySources */); instance.mActiveControls = new InsetsSourceControl.Array(activeControls); @@ -82,7 +76,7 @@ public class WindowStateInsetsControlChangeItem extends ClientTransactionItem { @Override public void recycle() { - mWindow = null; + super.recycle(); mInsetsState = null; mActiveControls = null; ObjectPool.recycle(this); @@ -93,14 +87,14 @@ public class WindowStateInsetsControlChangeItem extends ClientTransactionItem { /** Writes to Parcel. */ @Override public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeStrongBinder(mWindow.asBinder()); + super.writeToParcel(dest, flags); dest.writeTypedObject(mInsetsState, flags); dest.writeTypedObject(mActiveControls, flags); } /** Reads from Parcel. */ private WindowStateInsetsControlChangeItem(@NonNull Parcel in) { - mWindow = IWindow.Stub.asInterface(in.readStrongBinder()); + super(in); mInsetsState = in.readTypedObject(InsetsState.CREATOR); mActiveControls = in.readTypedObject(InsetsSourceControl.Array.CREATOR); @@ -122,19 +116,18 @@ public class WindowStateInsetsControlChangeItem extends ClientTransactionItem { if (this == o) { return true; } - if (o == null || getClass() != o.getClass()) { + if (!super.equals(o)) { return false; } final WindowStateInsetsControlChangeItem other = (WindowStateInsetsControlChangeItem) o; - return Objects.equals(mWindow, other.mWindow) - && Objects.equals(mInsetsState, other.mInsetsState) + return Objects.equals(mInsetsState, other.mInsetsState) && Objects.equals(mActiveControls, other.mActiveControls); } @Override public int hashCode() { int result = 17; - result = 31 * result + Objects.hashCode(mWindow); + result = 31 * result + super.hashCode(); result = 31 * result + Objects.hashCode(mInsetsState); result = 31 * result + Objects.hashCode(mActiveControls); return result; @@ -142,15 +135,6 @@ public class WindowStateInsetsControlChangeItem extends ClientTransactionItem { @Override public String toString() { - return "WindowStateInsetsControlChangeItem{window=" + mWindow + "}"; - } - - /** The interface for IWindow to perform insets control change directly if possible. */ - public interface InsetsControlChangeListener { - /** - * Notifies that IWindow#insetsControlChanged is going to be called from - * WindowStateInsetsControlChangeItem. - */ - void onExecutingWindowStateInsetsControlChangeItem(); + return "WindowStateInsetsControlChangeItem{" + super.toString() + "}"; } } diff --git a/core/java/android/app/servertransaction/WindowStateResizeItem.java b/core/java/android/app/servertransaction/WindowStateResizeItem.java index da99096f022a..3c1fa4b83340 100644 --- a/core/java/android/app/servertransaction/WindowStateResizeItem.java +++ b/core/java/android/app/servertransaction/WindowStateResizeItem.java @@ -18,8 +18,6 @@ package android.app.servertransaction; import static android.view.Display.INVALID_DISPLAY; -import static java.util.Objects.requireNonNull; - import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ClientTransactionHandler; @@ -39,11 +37,10 @@ import java.util.Objects; * Message to deliver window resize info. * @hide */ -public class WindowStateResizeItem extends ClientTransactionItem { +public class WindowStateResizeItem extends WindowStateTransactionItem { private static final String TAG = "WindowStateResizeItem"; - private IWindow mWindow; private ClientWindowFrames mFrames; private boolean mReportDraw; private MergedConfiguration mConfiguration; @@ -59,15 +56,12 @@ public class WindowStateResizeItem extends ClientTransactionItem { private ActivityWindowInfo mActivityWindowInfo; @Override - public void execute(@NonNull ClientTransactionHandler client, + public void execute(@NonNull ClientTransactionHandler client, @NonNull IWindow window, @NonNull PendingTransactionActions pendingActions) { Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, mReportDraw ? "windowResizedReport" : "windowResized"); - if (mWindow instanceof ResizeListener listener) { - listener.onExecutingWindowStateResizeItem(); - } try { - mWindow.resized(mFrames, mReportDraw, mConfiguration, mInsetsState, mForceLayout, + window.resized(mFrames, mReportDraw, mConfiguration, mInsetsState, mForceLayout, mAlwaysConsumeSystemBars, mDisplayId, mSyncSeqId, mDragResizing, mActivityWindowInfo); } catch (RemoteException e) { @@ -94,7 +88,7 @@ public class WindowStateResizeItem extends ClientTransactionItem { if (instance == null) { instance = new WindowStateResizeItem(); } - instance.mWindow = requireNonNull(window); + instance.setWindow(window); instance.mFrames = new ClientWindowFrames(frames); instance.mReportDraw = reportDraw; instance.mConfiguration = new MergedConfiguration(configuration); @@ -113,7 +107,7 @@ public class WindowStateResizeItem extends ClientTransactionItem { @Override public void recycle() { - mWindow = null; + super.recycle(); mFrames = null; mReportDraw = false; mConfiguration = null; @@ -132,7 +126,7 @@ public class WindowStateResizeItem extends ClientTransactionItem { /** Writes to Parcel. */ @Override public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeStrongBinder(mWindow.asBinder()); + super.writeToParcel(dest, flags); dest.writeTypedObject(mFrames, flags); dest.writeBoolean(mReportDraw); dest.writeTypedObject(mConfiguration, flags); @@ -147,7 +141,7 @@ public class WindowStateResizeItem extends ClientTransactionItem { /** Reads from Parcel. */ private WindowStateResizeItem(@NonNull Parcel in) { - mWindow = IWindow.Stub.asInterface(in.readStrongBinder()); + super(in); mFrames = in.readTypedObject(ClientWindowFrames.CREATOR); mReportDraw = in.readBoolean(); mConfiguration = in.readTypedObject(MergedConfiguration.CREATOR); @@ -175,12 +169,11 @@ public class WindowStateResizeItem extends ClientTransactionItem { if (this == o) { return true; } - if (o == null || getClass() != o.getClass()) { + if (!super.equals(o)) { return false; } final WindowStateResizeItem other = (WindowStateResizeItem) o; - return Objects.equals(mWindow, other.mWindow) - && Objects.equals(mFrames, other.mFrames) + return Objects.equals(mFrames, other.mFrames) && mReportDraw == other.mReportDraw && Objects.equals(mConfiguration, other.mConfiguration) && Objects.equals(mInsetsState, other.mInsetsState) @@ -195,7 +188,7 @@ public class WindowStateResizeItem extends ClientTransactionItem { @Override public int hashCode() { int result = 17; - result = 31 * result + Objects.hashCode(mWindow); + result = 31 * result + super.hashCode(); result = 31 * result + Objects.hashCode(mFrames); result = 31 * result + (mReportDraw ? 1 : 0); result = 31 * result + Objects.hashCode(mConfiguration); @@ -211,16 +204,10 @@ public class WindowStateResizeItem extends ClientTransactionItem { @Override public String toString() { - return "WindowStateResizeItem{window=" + mWindow + return "WindowStateResizeItem{" + super.toString() + ", reportDrawn=" + mReportDraw + ", configuration=" + mConfiguration + ", activityWindowInfo=" + mActivityWindowInfo + "}"; } - - /** The interface for IWindow to perform resize directly if possible. */ - public interface ResizeListener { - /** Notifies that IWindow#resized is going to be called from WindowStateResizeItem. */ - void onExecutingWindowStateResizeItem(); - } } diff --git a/core/java/android/app/servertransaction/WindowStateTransactionItem.java b/core/java/android/app/servertransaction/WindowStateTransactionItem.java new file mode 100644 index 000000000000..d556363dd947 --- /dev/null +++ b/core/java/android/app/servertransaction/WindowStateTransactionItem.java @@ -0,0 +1,118 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app.servertransaction; + + +import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE; + +import static java.util.Objects.requireNonNull; + +import android.annotation.CallSuper; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.ClientTransactionHandler; +import android.os.Parcel; +import android.view.IWindow; + +import com.android.internal.annotations.VisibleForTesting; + +import java.util.Objects; + +/** + * {@link ClientTransactionItem} to report changes to a window. + * + * @hide + */ +public abstract class WindowStateTransactionItem extends ClientTransactionItem { + + /** The interface for IWindow to perform callback directly if possible. */ + public interface TransactionListener { + /** Notifies that the transaction item is going to be executed. */ + void onExecutingWindowStateTransactionItem(); + } + + /** Target window. */ + private IWindow mWindow; + + WindowStateTransactionItem() {} + + @Override + public final void execute(@NonNull ClientTransactionHandler client, + @NonNull PendingTransactionActions pendingActions) { + if (mWindow instanceof TransactionListener listener) { + listener.onExecutingWindowStateTransactionItem(); + } + execute(client, mWindow, pendingActions); + } + + /** + * Like {@link #execute(ClientTransactionHandler, PendingTransactionActions)}, + * but take non-null {@link IWindow} as a parameter. + */ + @VisibleForTesting(visibility = PACKAGE) + public abstract void execute(@NonNull ClientTransactionHandler client, + @NonNull IWindow window, @NonNull PendingTransactionActions pendingActions); + + void setWindow(@NonNull IWindow window) { + mWindow = requireNonNull(window); + } + + // To be overridden + + WindowStateTransactionItem(@NonNull Parcel in) { + mWindow = IWindow.Stub.asInterface(in.readStrongBinder()); + } + + @CallSuper + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeStrongBinder(mWindow.asBinder()); + } + + @CallSuper + @Override + public void recycle() { + mWindow = null; + } + + // Subclass must override and call super.equals to compare the mActivityToken. + @SuppressWarnings("EqualsGetClass") + @CallSuper + @Override + public boolean equals(@Nullable Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final WindowStateTransactionItem other = (WindowStateTransactionItem) o; + return Objects.equals(mWindow, other.mWindow); + } + + @CallSuper + @Override + public int hashCode() { + return Objects.hashCode(mWindow); + } + + @CallSuper + @Override + public String toString() { + return "mWindow=" + mWindow; + } +} diff --git a/core/java/android/companion/virtual/flags/flags.aconfig b/core/java/android/companion/virtual/flags/flags.aconfig index 006226eb8c31..ed5d66227574 100644 --- a/core/java/android/companion/virtual/flags/flags.aconfig +++ b/core/java/android/companion/virtual/flags/flags.aconfig @@ -52,4 +52,15 @@ flag { description: "Makes MediaDrm APIs device-aware" bug: "303535376" is_fixed_read_only: true -}
\ No newline at end of file +} + +flag { + namespace: "virtual_devices" + name: "virtual_display_multi_window_mode_support" + description: "Add support for WINDOWING_MODE_MULTI_WINDOW to virtual displays by default" + is_fixed_read_only: true + bug: "341151395" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 9d2a8ee49591..282ede385ba3 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -4397,7 +4397,6 @@ public abstract class PackageManager { * {@link #hasSystemFeature}: The device supports freeform window management. * Windows have title bars and can be moved and resized. */ - // If this feature is present, you also need to set @SdkConstant(SdkConstantType.FEATURE) public static final String FEATURE_FREEFORM_WINDOW_MANAGEMENT = "android.software.freeform_window_management"; diff --git a/core/java/android/view/HandwritingInitiator.java b/core/java/android/view/HandwritingInitiator.java index beb4d95263be..57d1b8d18fe1 100644 --- a/core/java/android/view/HandwritingInitiator.java +++ b/core/java/android/view/HandwritingInitiator.java @@ -227,7 +227,10 @@ public class HandwritingInitiator { mState.mStylusDownY, /* isHover */ false); if (candidateView != null && candidateView.isEnabled()) { boolean candidateHasFocus = candidateView.hasFocus(); - if (shouldShowHandwritingUnavailableMessageForView(candidateView)) { + if (!candidateView.isStylusHandwritingAvailable()) { + mState.mShouldInitHandwriting = false; + return false; + } else if (shouldShowHandwritingUnavailableMessageForView(candidateView)) { int messagesResId = (candidateView instanceof TextView tv && tv.isAnyPasswordInputType()) ? R.string.error_handwriting_unsupported_password diff --git a/core/java/android/view/InsetsFlags.java b/core/java/android/view/InsetsFlags.java index ca8a7a8cf175..2fa57688f0cb 100644 --- a/core/java/android/view/InsetsFlags.java +++ b/core/java/android/view/InsetsFlags.java @@ -17,6 +17,7 @@ package android.view; import static android.view.WindowInsetsController.APPEARANCE_FORCE_LIGHT_NAVIGATION_BARS; +import static android.view.WindowInsetsController.APPEARANCE_LIGHT_CAPTION_BARS; import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS; import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS; import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS; @@ -24,6 +25,7 @@ import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_NAVIGATION_B import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_STATUS_BARS; import static android.view.WindowInsetsController.APPEARANCE_SEMI_TRANSPARENT_NAVIGATION_BARS; import static android.view.WindowInsetsController.APPEARANCE_SEMI_TRANSPARENT_STATUS_BARS; +import static android.view.WindowInsetsController.APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND; import static android.view.WindowInsetsController.BEHAVIOR_DEFAULT; import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE; @@ -69,7 +71,15 @@ public class InsetsFlags { @ViewDebug.FlagToString( mask = APPEARANCE_FORCE_LIGHT_NAVIGATION_BARS, equals = APPEARANCE_FORCE_LIGHT_NAVIGATION_BARS, - name = "FORCE_LIGHT_NAVIGATION_BARS") + name = "FORCE_LIGHT_NAVIGATION_BARS"), + @ViewDebug.FlagToString( + mask = APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND, + equals = APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND, + name = "APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND"), + @ViewDebug.FlagToString( + mask = APPEARANCE_LIGHT_CAPTION_BARS, + equals = APPEARANCE_LIGHT_CAPTION_BARS, + name = "APPEARANCE_LIGHT_CAPTION_BARS") }) public @Appearance int appearance; diff --git a/core/java/android/view/KeyboardShortcutInfo.java b/core/java/android/view/KeyboardShortcutInfo.java index 118b03ce5504..3f6fd646994c 100644 --- a/core/java/android/view/KeyboardShortcutInfo.java +++ b/core/java/android/view/KeyboardShortcutInfo.java @@ -28,8 +28,8 @@ import android.os.Parcelable; * Information about a Keyboard Shortcut. */ public final class KeyboardShortcutInfo implements Parcelable { - private final CharSequence mLabel; - private final Icon mIcon; + @Nullable private final CharSequence mLabel; + @Nullable private Icon mIcon; private final char mBaseCharacter; private final int mKeycode; private final int mModifiers; @@ -116,6 +116,15 @@ public final class KeyboardShortcutInfo implements Parcelable { } /** + * Removes an icon that was previously set. + * + * @hide + */ + public void clearIcon() { + mIcon = null; + } + + /** * Returns the base keycode that, combined with the modifiers, triggers this shortcut. If the * base character was set instead, returns {@link KeyEvent#KEYCODE_UNKNOWN}. Valid keycodes are * defined as constants in {@link KeyEvent}. @@ -165,4 +174,4 @@ public final class KeyboardShortcutInfo implements Parcelable { return new KeyboardShortcutInfo[size]; } }; -}
\ No newline at end of file +} diff --git a/core/java/android/view/NativeVectorDrawableAnimator.java b/core/java/android/view/NativeVectorDrawableAnimator.java index b0556a3f8a91..e92bd1f5d6b8 100644 --- a/core/java/android/view/NativeVectorDrawableAnimator.java +++ b/core/java/android/view/NativeVectorDrawableAnimator.java @@ -16,6 +16,8 @@ package android.view; +import android.animation.Animator; + /** * Exists just to allow for android.graphics & android.view package separation * @@ -26,4 +28,7 @@ package android.view; public interface NativeVectorDrawableAnimator { /** @hide */ long getAnimatorNativePtr(); + + /** @hide */ + void setThreadedRendererAnimatorListener(Animator.AnimatorListener listener); } diff --git a/core/java/android/view/ViewAnimationHostBridge.java b/core/java/android/view/ViewAnimationHostBridge.java index e0fae21bbdf6..62b2b6c053c4 100644 --- a/core/java/android/view/ViewAnimationHostBridge.java +++ b/core/java/android/view/ViewAnimationHostBridge.java @@ -16,14 +16,19 @@ package android.view; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; import android.graphics.RenderNode; +import androidx.annotation.NonNull; + /** * Maps a View to a RenderNode's AnimationHost * * @hide */ -public class ViewAnimationHostBridge implements RenderNode.AnimationHost { +public class ViewAnimationHostBridge extends AnimatorListenerAdapter + implements RenderNode.AnimationHost { private final View mView; /** @@ -34,17 +39,35 @@ public class ViewAnimationHostBridge implements RenderNode.AnimationHost { } @Override - public void registerAnimatingRenderNode(RenderNode animator) { - mView.mAttachInfo.mViewRootImpl.registerAnimatingRenderNode(animator); + public void registerAnimatingRenderNode(RenderNode renderNode, Animator animator) { + mView.mAttachInfo.mViewRootImpl.registerAnimatingRenderNode(renderNode); + animator.addListener(this); } @Override public void registerVectorDrawableAnimator(NativeVectorDrawableAnimator animator) { mView.mAttachInfo.mViewRootImpl.registerVectorDrawableAnimator(animator); + animator.setThreadedRendererAnimatorListener(this); } @Override public boolean isAttached() { return mView.mAttachInfo != null; } + + @Override + public void onAnimationStart(@NonNull Animator animation) { + ViewRootImpl viewRoot = mView.getViewRootImpl(); + if (viewRoot != null) { + viewRoot.addThreadedRendererView(mView); + } + } + + @Override + public void onAnimationEnd(@NonNull Animator animation) { + ViewRootImpl viewRoot = mView.getViewRootImpl(); + if (viewRoot != null) { + viewRoot.removeThreadedRendererView(mView); + } + } } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 8e2b7f1d4dd2..139285a44817 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -143,7 +143,7 @@ import android.app.ICompatCameraControlCallback; import android.app.ResourcesManager; import android.app.WindowConfiguration; import android.app.compat.CompatChanges; -import android.app.servertransaction.WindowStateResizeItem; +import android.app.servertransaction.WindowStateTransactionItem; import android.compat.annotation.UnsupportedAppUsage; import android.content.ClipData; import android.content.ClipDescription; @@ -427,6 +427,12 @@ public final class ViewRootImpl implements ViewParent, private static final long NANOS_PER_SEC = 1000000000; + // If the ViewRootImpl has been idle for more than 750ms, clear the preferred + // frame rate category and frame rate. + private static final int IDLE_TIME_MILLIS = 750; + + private static final long NANOS_PER_MILLI = 1_000_000; + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) static final ThreadLocal<HandlerActionQueue> sRunQueues = new ThreadLocal<HandlerActionQueue>(); @@ -659,6 +665,10 @@ public final class ViewRootImpl implements ViewParent, private int mMinusOneFrameIntervalMillis = 0; // VRR interval between the previous and the frame before private int mMinusTwoFrameIntervalMillis = 0; + // VRR has the invalidation idle message been posted? + private boolean mInvalidationIdleMessagePosted = false; + // VRR: List of all Views that are animating with the threaded render + private ArrayList<View> mThreadedRendererViews = new ArrayList(); /** * Update the Choreographer's FrameInfo object with the timing information for the current @@ -1184,6 +1194,8 @@ public final class ViewRootImpl implements ViewParent, toolkitFrameRateVelocityMappingReadOnly(); private static boolean sToolkitEnableInvalidateCheckThreadFlagValue = Flags.enableInvalidateCheckThread(); + private static boolean sSurfaceFlingerBugfixFlagValue = + com.android.graphics.surfaceflinger.flags.Flags.vrrBugfix24q4(); static { sToolkitSetFrameRateReadOnlyFlagValue = toolkitSetFrameRateReadOnly(); @@ -4261,8 +4273,13 @@ public final class ViewRootImpl implements ViewParent, // when the values are applicable. if (mDrawnThisFrame) { mDrawnThisFrame = false; + if (!mInvalidationIdleMessagePosted && sSurfaceFlingerBugfixFlagValue) { + mInvalidationIdleMessagePosted = true; + mHandler.sendEmptyMessageDelayed(MSG_CHECK_INVALIDATION_IDLE, IDLE_TIME_MILLIS); + } setCategoryFromCategoryCounts(); updateInfrequentCount(); + updateFrameRateFromThreadedRendererViews(); setPreferredFrameRate(mPreferredFrameRate); setPreferredFrameRateCategory(mPreferredFrameRateCategory); if (mPreferredFrameRate > 0 @@ -6499,6 +6516,8 @@ public final class ViewRootImpl implements ViewParent, return "MSG_WINDOW_TOUCH_MODE_CHANGED"; case MSG_KEEP_CLEAR_RECTS_CHANGED: return "MSG_KEEP_CLEAR_RECTS_CHANGED"; + case MSG_CHECK_INVALIDATION_IDLE: + return "MSG_CHECK_INVALIDATION_IDLE"; case MSG_REFRESH_POINTER_ICON: return "MSG_REFRESH_POINTER_ICON"; case MSG_TOUCH_BOOST_TIMEOUT: @@ -6759,6 +6778,31 @@ public final class ViewRootImpl implements ViewParent, mNumPausedForSync = 0; scheduleTraversals(); break; + case MSG_CHECK_INVALIDATION_IDLE: { + long delta; + if (mIsTouchBoosting || mIsFrameRateBoosting || mInsetsAnimationRunning) { + delta = 0; + } else { + delta = System.nanoTime() / NANOS_PER_MILLI - mLastUpdateTimeMillis; + } + if (delta >= IDLE_TIME_MILLIS) { + mFrameRateCategoryHighCount = 0; + mFrameRateCategoryHighHintCount = 0; + mFrameRateCategoryNormalCount = 0; + mFrameRateCategoryLowCount = 0; + mPreferredFrameRate = 0; + mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_NO_PREFERENCE; + updateFrameRateFromThreadedRendererViews(); + setPreferredFrameRate(mPreferredFrameRate); + setPreferredFrameRateCategory(mPreferredFrameRateCategory); + mInvalidationIdleMessagePosted = false; + } else { + mInvalidationIdleMessagePosted = true; + mHandler.sendEmptyMessageDelayed(MSG_CHECK_INVALIDATION_IDLE, + IDLE_TIME_MILLIS - delta); + } + break; + } case MSG_TOUCH_BOOST_TIMEOUT: /** * Lower the frame rate after the boosting period (FRAME_RATE_TOUCH_BOOST_TIME). @@ -7273,7 +7317,8 @@ public final class ViewRootImpl implements ViewParent, if (dispatcher.isBackGestureInProgress()) { return FINISH_NOT_HANDLED; } - if (topCallback instanceof OnBackAnimationCallback) { + if (topCallback instanceof OnBackAnimationCallback + && !(topCallback instanceof ImeBackAnimationController)) { final OnBackAnimationCallback animationCallback = (OnBackAnimationCallback) topCallback; switch (keyEvent.getAction()) { @@ -11201,10 +11246,10 @@ public final class ViewRootImpl implements ViewParent, } } - static class W extends IWindow.Stub implements WindowStateResizeItem.ResizeListener { + static class W extends IWindow.Stub implements WindowStateTransactionItem.TransactionListener { private final WeakReference<ViewRootImpl> mViewAncestor; private final IWindowSession mWindowSession; - private boolean mIsFromResizeItem; + private boolean mIsFromTransactionItem; W(ViewRootImpl viewAncestor) { mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor); @@ -11212,8 +11257,8 @@ public final class ViewRootImpl implements ViewParent, } @Override - public void onExecutingWindowStateResizeItem() { - mIsFromResizeItem = true; + public void onExecutingWindowStateTransactionItem() { + mIsFromTransactionItem = true; } @Override @@ -11221,8 +11266,8 @@ public final class ViewRootImpl implements ViewParent, MergedConfiguration mergedConfiguration, InsetsState insetsState, boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId, int syncSeqId, boolean dragResizing, @Nullable ActivityWindowInfo activityWindowInfo) { - final boolean isFromResizeItem = mIsFromResizeItem; - mIsFromResizeItem = false; + final boolean isFromResizeItem = mIsFromTransactionItem; + mIsFromTransactionItem = false; // Although this is a AIDL method, it will only be triggered in local process through // either WindowStateResizeItem or WindowlessWindowManager. final ViewRootImpl viewAncestor = mViewAncestor.get(); @@ -11259,10 +11304,13 @@ public final class ViewRootImpl implements ViewParent, @Override public void insetsControlChanged(InsetsState insetsState, InsetsSourceControl.Array activeControls) { + final boolean isFromInsetsControlChangeItem = mIsFromTransactionItem; + mIsFromTransactionItem = false; final ViewRootImpl viewAncestor = mViewAncestor.get(); if (viewAncestor != null) { viewAncestor.dispatchInsetsControlChanged(insetsState, activeControls.get()); } + // TODO(b/339380439): no need to post if the call is from InsetsControlChangeItem } @Override @@ -12577,6 +12625,24 @@ public final class ViewRootImpl implements ViewParent, } /** + * Views that are animating with the ThreadedRenderer don't use the normal invalidation + * path, so the value won't be updated through performTraversals. This reads the votes + * from those views. + */ + private void updateFrameRateFromThreadedRendererViews() { + ArrayList<View> views = mThreadedRendererViews; + for (int i = views.size() - 1; i >= 0; i--) { + View view = views.get(i); + View.AttachInfo attachInfo = view.mAttachInfo; + if (attachInfo == null || attachInfo.mViewRootImpl != this) { + views.remove(i); + } else { + view.votePreferredFrameRate(); + } + } + } + + /** * Sets the mPreferredFrameRateCategory from the high, high_hint, normal, and low counts. */ private void setCategoryFromCategoryCounts() { @@ -12757,6 +12823,31 @@ public final class ViewRootImpl implements ViewParent, } /** + * Mark a View as having an active ThreadedRenderer animation. This is used for + * RenderNodeAnimators and AnimatedVectorDrawables. When the animation stops, + * {@link #removeThreadedRendererView(View)} must be called. + * @param view The View with the ThreadedRenderer animation that started. + */ + public void addThreadedRendererView(View view) { + if (!mThreadedRendererViews.contains(view)) { + mThreadedRendererViews.add(view); + } + } + + /** + * When a ThreadedRenderer animation ends, the View that is associated with it using + * {@link #addThreadedRendererView(View)} must be removed with a call to this method. + * @param view The View whose ThreadedRender animation has stopped. + */ + public void removeThreadedRendererView(View view) { + mThreadedRendererViews.remove(view); + if (!mInvalidationIdleMessagePosted && sSurfaceFlingerBugfixFlagValue) { + mInvalidationIdleMessagePosted = true; + mHandler.sendEmptyMessageDelayed(MSG_CHECK_INVALIDATION_IDLE, IDLE_TIME_MILLIS); + } + } + + /** * Returns {@link #INTERMITTENT_STATE_INTERMITTENT} when the ViewRootImpl has only been * updated intermittently, {@link #INTERMITTENT_STATE_NOT_INTERMITTENT} when it is * not updated intermittently, and {@link #INTERMITTENT_STATE_IN_TRANSITION} when it @@ -12979,6 +13070,10 @@ public final class ViewRootImpl implements ViewParent, private void removeVrrMessages() { mHandler.removeMessages(MSG_TOUCH_BOOST_TIMEOUT); mHandler.removeMessages(MSG_FRAME_RATE_SETTING); + if (mInvalidationIdleMessagePosted && sSurfaceFlingerBugfixFlagValue) { + mInvalidationIdleMessagePosted = false; + mHandler.removeMessages(MSG_CHECK_INVALIDATION_IDLE); + } } /** @@ -12997,7 +13092,7 @@ public final class ViewRootImpl implements ViewParent, mMinusOneFrameIntervalMillis = timeIntervalMillis; mLastUpdateTimeMillis = currentTimeMillis; - if (timeIntervalMillis + mMinusTwoFrameIntervalMillis + if (mThreadedRendererViews.isEmpty() && timeIntervalMillis + mMinusTwoFrameIntervalMillis >= INFREQUENT_UPDATE_INTERVAL_MILLIS) { int infrequentUpdateCount = mInfrequentUpdateCount; mInfrequentUpdateCount = infrequentUpdateCount == INFREQUENT_UPDATE_COUNTS diff --git a/core/java/android/window/DisplayWindowPolicyController.java b/core/java/android/window/DisplayWindowPolicyController.java index 8d71a8e998bd..9cd2a716e498 100644 --- a/core/java/android/window/DisplayWindowPolicyController.java +++ b/core/java/android/window/DisplayWindowPolicyController.java @@ -23,6 +23,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.WindowConfiguration; +import android.companion.virtualdevice.flags.Flags; import android.content.ComponentName; import android.content.Intent; import android.content.pm.ActivityInfo; @@ -66,6 +67,9 @@ public abstract class DisplayWindowPolicyController { public DisplayWindowPolicyController() { synchronized (mSupportedWindowingModes) { mSupportedWindowingModes.add(WindowConfiguration.WINDOWING_MODE_FULLSCREEN); + if (Flags.virtualDisplayMultiWindowModeSupport()) { + mSupportedWindowingModes.add(WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW); + } } } diff --git a/core/java/android/window/SnapshotDrawerUtils.java b/core/java/android/window/SnapshotDrawerUtils.java index 29bb32e6443f..f928f509bdb6 100644 --- a/core/java/android/window/SnapshotDrawerUtils.java +++ b/core/java/android/window/SnapshotDrawerUtils.java @@ -50,7 +50,6 @@ import android.app.ActivityManager; import android.app.ActivityThread; import android.content.Context; import android.graphics.Canvas; -import android.graphics.Color; import android.graphics.GraphicBuffer; import android.graphics.Paint; import android.graphics.PixelFormat; @@ -68,6 +67,7 @@ import android.view.WindowManager; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.policy.DecorView; +import com.android.window.flags.Flags; /** * Utils class to help draw a snapshot on a surface. @@ -181,7 +181,8 @@ public class SnapshotDrawerUtils { // We consider nearly matched dimensions as there can be rounding errors and the user // won't notice very minute differences from scaling one dimension more than the other - boolean aspectRatioMismatch = !isAspectRatioMatch(mFrame, mSnapshotW, mSnapshotH); + boolean aspectRatioMismatch = !isAspectRatioMatch(mFrame, mSnapshotW, mSnapshotH) + && !Flags.drawSnapshotAspectRatioMatch(); // Keep a reference to it such that it doesn't get destroyed when finalized. SurfaceControl childSurfaceControl = new SurfaceControl.Builder(session) @@ -382,8 +383,8 @@ public class SnapshotDrawerUtils { } final SnapshotSurface drawSurface = new SnapshotSurface( rootSurface, snapshot, lp.getTitle()); - - final WindowManager.LayoutParams attrs = info.topOpaqueWindowLayoutParams; + final WindowManager.LayoutParams attrs = Flags.drawSnapshotAspectRatioMatch() + ? info.mainWindowLayoutParams : info.topOpaqueWindowLayoutParams; final ActivityManager.RunningTaskInfo runningTaskInfo = info.taskInfo; final ActivityManager.TaskDescription taskDescription = getOrCreateTaskDescription(runningTaskInfo); @@ -400,7 +401,8 @@ public class SnapshotDrawerUtils { public static WindowManager.LayoutParams createLayoutParameters(StartingWindowInfo info, CharSequence title, @WindowManager.LayoutParams.WindowType int windowType, int pixelFormat, IBinder token) { - final WindowManager.LayoutParams attrs = info.topOpaqueWindowLayoutParams; + final WindowManager.LayoutParams attrs = Flags.drawSnapshotAspectRatioMatch() + ? info.mainWindowLayoutParams : info.topOpaqueWindowLayoutParams; final WindowManager.LayoutParams mainWindowParams = info.mainWindowLayoutParams; final InsetsState topWindowInsetsState = info.topOpaqueWindowInsetsState; if (attrs == null || mainWindowParams == null || topWindowInsetsState == null) { @@ -527,7 +529,7 @@ public class SnapshotDrawerUtils { void drawStatusBarBackground(Canvas c, @Nullable Rect alreadyDrawnFrame, int statusBarHeight) { - if (statusBarHeight > 0 && Color.alpha(mStatusBarColor) != 0 + if (statusBarHeight > 0 && alpha(mStatusBarColor) != 0 && (alreadyDrawnFrame == null || c.getWidth() > alreadyDrawnFrame.right)) { final int rightInset = (int) (mSystemBarInsets.right * mScale); final int left = alreadyDrawnFrame != null ? alreadyDrawnFrame.right : 0; @@ -541,7 +543,7 @@ public class SnapshotDrawerUtils { getNavigationBarRect(c.getWidth(), c.getHeight(), mSystemBarInsets, navigationBarRect, mScale); final boolean visible = isNavigationBarColorViewVisible(); - if (visible && Color.alpha(mNavigationBarColor) != 0 + if (visible && alpha(mNavigationBarColor) != 0 && !navigationBarRect.isEmpty()) { c.drawRect(navigationBarRect, mNavigationBarPaint); } diff --git a/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig b/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig index 4b2beb903325..983f46c58c4b 100644 --- a/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig +++ b/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig @@ -2,13 +2,6 @@ package: "com.android.window.flags" container: "system" flag { - name: "disable_thin_letterboxing_reachability" - namespace: "large_screen_experiences_app_compat" - description: "Whether reachability is disabled in case of thin letterboxing" - bug: "334077350" -} - -flag { name: "disable_thin_letterboxing_policy" namespace: "large_screen_experiences_app_compat" description: "Whether reachability is disabled in case of thin letterboxing" diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig index f08f5b8fddbe..d6f65f8c9d8b 100644 --- a/core/java/android/window/flags/windowing_frontend.aconfig +++ b/core/java/android/window/flags/windowing_frontend.aconfig @@ -171,4 +171,15 @@ flag { description: "Actively release task snapshot memory" bug: "238206323" is_fixed_read_only: true +} + +flag { + name: "draw_snapshot_aspect_ratio_match" + namespace: "windowing_frontend" + description: "The aspect ratio should always match when drawing snapshot" + bug: "341020277" + is_fixed_read_only: true + metadata { + purpose: PURPOSE_BUGFIX + } }
\ No newline at end of file diff --git a/core/java/android/window/flags/windowing_sdk.aconfig b/core/java/android/window/flags/windowing_sdk.aconfig index 6af3d9e50d75..21aa4800237c 100644 --- a/core/java/android/window/flags/windowing_sdk.aconfig +++ b/core/java/android/window/flags/windowing_sdk.aconfig @@ -147,4 +147,15 @@ flag { metadata { purpose: PURPOSE_BUGFIX } +} + +flag { + namespace: "windowing_sdk" + name: "insets_control_seq" + description: "Add seqId to InsetsControls to ensure the stale update is ignored" + bug: "339380439" + is_fixed_read_only: true + metadata { + purpose: PURPOSE_BUGFIX + } }
\ No newline at end of file diff --git a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java index 33b4e4a7dd0b..75ddb58590a1 100644 --- a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java +++ b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java @@ -103,6 +103,8 @@ public class AccessibilityShortcutController { // The component name for the sub setting of Hearing aids in Accessibility settings public static final ComponentName ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME = new ComponentName("com.android.server.accessibility", "HearingAids"); + public static final ComponentName ACCESSIBILITY_HEARING_AIDS_TILE_COMPONENT_NAME = + new ComponentName("com.android.server.accessibility", "HearingDevicesTile"); public static final ComponentName COLOR_INVERSION_TILE_COMPONENT_NAME = new ComponentName("com.android.server.accessibility", "ColorInversionTile"); diff --git a/core/java/com/android/internal/accessibility/common/ShortcutConstants.java b/core/java/com/android/internal/accessibility/common/ShortcutConstants.java index c08968dabc89..6420620adda9 100644 --- a/core/java/com/android/internal/accessibility/common/ShortcutConstants.java +++ b/core/java/com/android/internal/accessibility/common/ShortcutConstants.java @@ -16,6 +16,8 @@ package com.android.internal.accessibility.common; +import static com.android.internal.accessibility.AccessibilityShortcutController.ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME; +import static com.android.internal.accessibility.AccessibilityShortcutController.ACCESSIBILITY_HEARING_AIDS_TILE_COMPONENT_NAME; import static com.android.internal.accessibility.AccessibilityShortcutController.COLOR_INVERSION_COMPONENT_NAME; import static com.android.internal.accessibility.AccessibilityShortcutController.COLOR_INVERSION_TILE_COMPONENT_NAME; import static com.android.internal.accessibility.AccessibilityShortcutController.DALTONIZER_COMPONENT_NAME; @@ -160,6 +162,8 @@ public final class ShortcutConstants { DALTONIZER_COMPONENT_NAME, DALTONIZER_TILE_COMPONENT_NAME, ONE_HANDED_COMPONENT_NAME, ONE_HANDED_TILE_COMPONENT_NAME, REDUCE_BRIGHT_COLORS_COMPONENT_NAME, REDUCE_BRIGHT_COLORS_TILE_SERVICE_COMPONENT_NAME, - FONT_SIZE_COMPONENT_NAME, FONT_SIZE_TILE_COMPONENT_NAME + FONT_SIZE_COMPONENT_NAME, FONT_SIZE_TILE_COMPONENT_NAME, + ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME, + ACCESSIBILITY_HEARING_AIDS_TILE_COMPONENT_NAME ); } diff --git a/core/java/com/android/internal/policy/ScreenDecorationsUtils.java b/core/java/com/android/internal/policy/ScreenDecorationsUtils.java index ec6283922807..067e5e8813a7 100644 --- a/core/java/com/android/internal/policy/ScreenDecorationsUtils.java +++ b/core/java/com/android/internal/policy/ScreenDecorationsUtils.java @@ -18,6 +18,9 @@ package com.android.internal.policy; import android.content.Context; import android.content.res.Resources; +import android.util.DisplayUtils; +import android.view.Display; +import android.view.DisplayInfo; import android.view.RoundedCorners; import com.android.internal.R; @@ -57,11 +60,31 @@ public class ScreenDecorationsUtils { bottomRadius = defaultRadius; } + // If the physical pixels are scaled, apply it here + float scale = getPhysicalPixelDisplaySizeRatio(context); + if (scale != 1f) { + topRadius = topRadius * scale; + bottomRadius = bottomRadius * scale; + } + // Always use the smallest radius to make sure the rounded corners will // completely cover the display. return Math.min(topRadius, bottomRadius); } + static float getPhysicalPixelDisplaySizeRatio(Context context) { + DisplayInfo displayInfo = new DisplayInfo(); + context.getDisplay().getDisplayInfo(displayInfo); + final Display.Mode maxDisplayMode = + DisplayUtils.getMaximumResolutionDisplayMode(displayInfo.supportedModes); + if (maxDisplayMode == null) { + return 1f; + } + return DisplayUtils.getPhysicalPixelDisplaySizeRatio( + maxDisplayMode.getPhysicalWidth(), maxDisplayMode.getPhysicalHeight(), + displayInfo.getNaturalWidth(), displayInfo.getNaturalHeight()); + } + /** * If live rounded corners are supported on windows. */ diff --git a/core/jni/android_database_SQLiteRawStatement.cpp b/core/jni/android_database_SQLiteRawStatement.cpp index b6b788114d22..8fc13a82e74e 100644 --- a/core/jni/android_database_SQLiteRawStatement.cpp +++ b/core/jni/android_database_SQLiteRawStatement.cpp @@ -41,6 +41,11 @@ */ namespace android { +// A zero-length byte array that can be returned by getColumnBlob(). The theory is that +// zero-length blobs are common enough that it is worth having a single, global instance. The +// object is created in the jni registration function. It is never destroyed. +static jbyteArray emptyArray = nullptr; + // Helper functions. static sqlite3 *db(long statementPtr) { return sqlite3_db_handle(reinterpret_cast<sqlite3_stmt*>(statementPtr)); @@ -226,7 +231,7 @@ static jbyteArray columnBlob(JNIEnv* env, jclass, jlong stmtPtr, jint col) { throwIfInvalidColumn(env, stmtPtr, col); const void* blob = sqlite3_column_blob(stmt(stmtPtr), col); if (blob == nullptr) { - return NULL; + return (sqlite3_column_type(stmt(stmtPtr), col) == SQLITE_NULL) ? NULL : emptyArray; } size_t size = sqlite3_column_bytes(stmt(stmtPtr), col); jbyteArray result = env->NewByteArray(size); @@ -316,8 +321,10 @@ static const JNINativeMethod sStatementMethods[] = int register_android_database_SQLiteRawStatement(JNIEnv *env) { - return RegisterMethodsOrDie(env, "android/database/sqlite/SQLiteRawStatement", - sStatementMethods, NELEM(sStatementMethods)); + RegisterMethodsOrDie(env, "android/database/sqlite/SQLiteRawStatement", + sStatementMethods, NELEM(sStatementMethods)); + emptyArray = MakeGlobalRefOrDie(env, env->NewByteArray(0)); + return 0; } } // namespace android diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 7b9235cdc691..6dbe44b483d2 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -4702,6 +4702,11 @@ <permission android:name="android.permission.REQUEST_UNIQUE_ID_ATTESTATION" android:protectionLevel="signature" /> + <!-- Allows an application to use the RemoteKeyProvisioningService. + @hide --> + <permission android:name="android.permission.BIND_RKP_SERVICE" + android:protectionLevel="signature" /> + <!-- Allows an application to get enabled credential manager providers. @hide --> <permission android:name="android.permission.LIST_ENABLED_CREDENTIAL_PROVIDERS" diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml index b532ad718cec..ca6a384bd96f 100644 --- a/core/res/res/values-af/strings.xml +++ b/core/res/res/values-af/strings.xml @@ -201,10 +201,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Jou werkprofiel is nie meer op hierdie toestel beskikbaar nie"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Te veel wagwoordpogings"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"Administrateur het toestel vir persoonlike gebruik afgestaan"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"Privaat ruimte is verwyder"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"Jou organisasie laat nie privaat ruimtes op hierdie bestuurde toestel toe nie."</string> <string name="network_logging_notification_title" msgid="554983187553845004">"Toestel word bestuur"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"Jou organisasie bestuur hierdie toestel en kan netwerkverkeer monitor. Tik vir besonderhede."</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"Programme kan toegang tot jou ligging kry"</string> @@ -2198,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"D-paneel links"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"D-paneel regs"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"D-paneel middel"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> se onderskrifbalk."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> is in die BEPERK-groep geplaas"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"het \'n prent gestuur"</string> diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml index 060c8cb0cf3c..218b13ae3de7 100644 --- a/core/res/res/values-am/strings.xml +++ b/core/res/res/values-am/strings.xml @@ -201,10 +201,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"የሥራ መገለጫዎ ከዚህ በኋላ በዚህ መሣሪያ ላይ አይገኝም"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"በጣም ብዙ የይለፍ ቃል ሙከራዎች"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"አስተዳዳሪ መሣሪያዎን ለግል ጥቅም ትተውታል"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"የግል ቦታ ተወግዷል"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"ድርጅትዎ የግል ቦታዎችን በዚህ የሚተዳደር መሣሪያ ላይ አይፈቅድም።"</string> <string name="network_logging_notification_title" msgid="554983187553845004">"መሣሪያው የሚተዳደር ነው"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"የእርስዎ ድርጅት ይህን መሣሪያ ያስተዳድራል፣ እና የአውታረ መረብ ትራፊክን ሊከታተል ይችላል። ዝርዝሮችን ለማግኘት መታ ያድርጉ።"</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"መተግበሪያዎች የእርስዎን አካባቢ መድረስ ይችላሉ"</string> @@ -2198,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"ከDpad በስተግራ"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"ከDpad በስተቀኝ"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"የDpad ማዕከል"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"የ<xliff:g id="APP_NAME">%1$s</xliff:g> የሥዕል ገላጭ ጽሁፍ አሞሌ።"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ወደ የRESTRICTED ባልዲ ተከትቷል"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>፦"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"አንድ ምስል ልከዋል"</string> diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml index f59a8cb15506..d0e28b7b243a 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -205,10 +205,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"لم يعد ملفك الشخصي للعمل متاحًا على هذا الجهاز"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"تم إجراء محاولات كثيرة جدًا لإدخال كلمة المرور"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"تنازل المشرف عن الجهاز للاستخدام الشخصي"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"تمت إزالة المساحة الخاصّة"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"لا تسمح مؤسستك بالمساحات الخاصة على هذا الجهاز المُدار."</string> <string name="network_logging_notification_title" msgid="554983187553845004">"تتم إدارة الجهاز"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"تدير مؤسستك هذا الجهاز ويمكنها مراقبة حركة بيانات الشبكة. يمكنك النقر للحصول على تفاصيل."</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"يمكن للتطبيقات الوصول إلى موقعك الجغرافي"</string> @@ -2202,7 +2200,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"زرّ الاتجاه لليسار"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"زرّ الاتجاه لليمين"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"الزرّ المركزي"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"شريط الشرح لتطبيق <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"تم وضع <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> في الحزمة \"محظورة\"."</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"هذا المستخدم أرسل صورة"</string> diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml index c20d5ae00624..42b0af9d4490 100644 --- a/core/res/res/values-as/strings.xml +++ b/core/res/res/values-as/strings.xml @@ -201,10 +201,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"আপোনাৰ কৰ্মস্থানৰ প্ৰ\'ফাইল এই ডিভাইচটোত আৰু উপলব্ধ নহয়"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"বহুতবাৰ ভুলকৈ পাছৱৰ্ড দিয়া হৈছে"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"প্ৰশাসকে ডিভাইচটো ব্যক্তিগত ব্যৱহাৰৰ বাবে বাজেয়প্ত কৰিছে"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"প্ৰাইভেট স্পে’চ আঁতৰোৱা হৈছে"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"আপোনাৰ প্ৰতিষ্ঠানে এই পৰিচালিত ডিভাইচত প্ৰাইভেট স্পে’চৰ অনুমতি নিদিয়ে।"</string> <string name="network_logging_notification_title" msgid="554983187553845004">"পৰিচালিত ডিভাইচ"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"আপোনাৰ প্ৰতিষ্ঠানটোৱে এই ডিভাইচটো পৰিচালনা কৰে আৰু ই নেটৱৰ্কৰ ট্ৰেফিক পৰ্যবেক্ষণ কৰিব পাৰে। সবিশেষ জানিবলৈ টিপক।"</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"এপ্সমূহে আপোনাৰ অৱস্থান এক্সেছ কৰিব পাৰে"</string> @@ -2198,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"ডিপেডৰ বাওঁফালৰ বুটাম"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"ডিপেডৰ সোঁফালৰ বুটাম"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"ডিপেডৰ মাজৰ বুটাম"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>ৰ কেপশ্বন বাৰ।"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>ক সীমাবদ্ধ বাকেটটোত ৰখা হৈছে"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"এখন প্ৰতিচ্ছবি পঠিয়াইছে"</string> @@ -2399,7 +2396,7 @@ <string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"কীব’ৰ্ডৰ লে’আউট <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g> হিচাপে ছেট কৰা হৈছে… সলনি কৰিবলৈ টিপক।"</string> <string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"ভৌতিক কীব’ৰ্ড কনফিগাৰ কৰা হৈছে"</string> <string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"কীব’ৰ্ড চাবলৈ টিপক"</string> - <string name="profile_label_private" msgid="6463418670715290696">"ব্যক্তিগত"</string> + <string name="profile_label_private" msgid="6463418670715290696">"প্ৰাইভেট"</string> <string name="profile_label_clone" msgid="769106052210954285">"ক্ল’ন"</string> <string name="profile_label_work" msgid="3495359133038584618">"কৰ্মস্থান"</string> <string name="profile_label_work_2" msgid="4691533661598632135">"কৰ্মস্থান ২"</string> diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml index 9d4475906fea..5633c06f6b92 100644 --- a/core/res/res/values-az/strings.xml +++ b/core/res/res/values-az/strings.xml @@ -2196,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad Sola"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad Sağa"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad Mərkəzə"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> başlıq paneli."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> MƏHDUDLAŞDIRILMIŞ səbətinə yerləşdirilib"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"şəkil göndərdi"</string> @@ -2397,7 +2396,7 @@ <string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Klaviatura düzəni <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g> kimi ayarlanıb… Dəyişmək üçün toxunun."</string> <string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Fiziki klaviaturalar konfiqurasiya edilib"</string> <string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Klaviaturalara baxmaq üçün toxunun"</string> - <string name="profile_label_private" msgid="6463418670715290696">"Şəxsi"</string> + <string name="profile_label_private" msgid="6463418670715290696">"Məxfi"</string> <string name="profile_label_clone" msgid="769106052210954285">"Klon"</string> <string name="profile_label_work" msgid="3495359133038584618">"İş"</string> <string name="profile_label_work_2" msgid="4691533661598632135">"İş 2"</string> diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml index 140ca4aa3f39..e38706ea866c 100644 --- a/core/res/res/values-b+sr+Latn/strings.xml +++ b/core/res/res/values-b+sr+Latn/strings.xml @@ -202,10 +202,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Poslovni profil više nije dostupan na ovom uređaju"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Previše pokušaja unosa lozinke"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"Administrator je ustupio uređaj za ličnu upotrebu"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"Privatan prostor je uklonjen"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"Organizacija ne dozvoljava privatne prostore na ovom upravljanom uređaju."</string> <string name="network_logging_notification_title" msgid="554983187553845004">"Uređajem se upravlja"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"Organizacija upravlja ovim uređajem i može da nadgleda mrežni saobraćaj. Dodirnite za detalje."</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"Aplikacije mogu da pristupaju vašoj lokaciji"</string> @@ -2199,7 +2197,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"nalevo na D-pad-u"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"nadesno na D-pad-u"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"centar na D-pad-u"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Traka sa naslovima aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Paket <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> je dodat u segment OGRANIČENO"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"je poslao/la sliku"</string> diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml index 116a83621934..25ae5a764360 100644 --- a/core/res/res/values-be/strings.xml +++ b/core/res/res/values-be/strings.xml @@ -203,10 +203,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Ваш працоўны профіль больш не даступны на гэтай прыладзе"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Занадта шмат спроб уводу пароля"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"Адміністратар пераналадзіў прыладу для асабістага выкарыстання"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"Прыватная прастора выдалена"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"Ваша арганізацыя не дазваляе прыватныя прасторы на гэтай прыладзе пад яе кіраваннем."</string> <string name="network_logging_notification_title" msgid="554983187553845004">"Прылада знаходзіцца пад кіраваннем"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"Ваша арганізацыя кіруе гэтай прыладай і можа сачыць за сеткавым трафікам. Дакраніцеся для атрымання дадатковай інфармацыі."</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"Праграмы могуць атрымліваць даныя пра ваша месцазнаходжанне"</string> @@ -2200,7 +2198,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Улева на панэлі кіравання"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Управа на панэлі кіравання"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"У цэнтр на панэлі кіравання"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Панэль субцітраў праграмы \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Пакет \"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>\" дададзены ў АБМЕЖАВАНУЮ групу"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"адпраўлены відарыс"</string> diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml index 086cb63009c1..6b388d8d6e6d 100644 --- a/core/res/res/values-bg/strings.xml +++ b/core/res/res/values-bg/strings.xml @@ -201,10 +201,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Служебният ви потребителски профил вече не е налице на това устройство"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Опитите за паролата са твърде много"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"Администраторът предостави устройствотото за лична употреба"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"Частното пространство бе премахнато"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"Организацията ви не допуска частни пространства на това управлявано устройство."</string> <string name="network_logging_notification_title" msgid="554983187553845004">"Устройството се управлява"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"Организацията ви управлява това устройство и може да наблюдава мрежовия трафик. Докоснете за подробности."</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"Прилож. имат достъп до местоположението ви"</string> @@ -2198,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Контролен пад – ляво"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Контролен пад – дясно"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Контролен пад – център"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Лента за надписи на <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Пакетът <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> е поставен в ОГРАНИЧЕНИЯ контейнер"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"изпратено изображение"</string> diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml index 679cf5737c0c..3f338cce08aa 100644 --- a/core/res/res/values-bn/strings.xml +++ b/core/res/res/values-bn/strings.xml @@ -201,10 +201,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"আপনার কর্মস্থলের প্রোফাইলটি আর এই ডিভাইসে নেই"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"বহুবার ভুল পাসওয়ার্ড দিয়েছেন"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"ব্যক্তিগত কাজের জন্য অ্যাডমিন এই ডিভাইস ব্যবহার করার অনুমতি দেয়নি"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"প্রাইভেট স্পেস সরিয়ে দেওয়া হয়েছে"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"এই ম্যানেজ করা ডিভাইসে আপনার সংস্থা প্রাইভেট স্পেসের অনুমতি দেয় না।"</string> <string name="network_logging_notification_title" msgid="554983187553845004">"ডিভাইসটি পরিচালনা করা হচ্ছে"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"আপনার প্রতিষ্ঠান এই ডিভাইসটি পরিচালনা করে এবং এটির নেটওয়ার্ক ট্রাফিকের উপরে নজর রাখতে পারে। বিশদ বিবরণের জন্য ট্যাপ করুন।,"</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"অ্যাপগুলি আপনার লোকেশন অ্যাক্সেস করতে পারবে"</string> @@ -2198,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"ডিপ্যাড (Dpad)-এর বাঁদিকে"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"ডিপ্যাড (Dpad)-এর ডানদিকে"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"ডিপ্যাড (Dpad)-এর মাঝখানে"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>-এর ক্যাপশন বার।"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> সীমাবদ্ধ গ্রুপে অন্তর্ভুক্ত করা হয়েছে"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"একটি ছবি পাঠানো হয়েছে"</string> @@ -2399,7 +2396,7 @@ <string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"কীবোর্ড লেআউট <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>-এ সেট করা আছে… পালটাতে ট্যাপ করুন।"</string> <string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"ফিজিক্যাল কীবোর্ড কনফিগার করা হয়েছে"</string> <string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"কীবোর্ড দেখতে ট্যাপ করুন"</string> - <string name="profile_label_private" msgid="6463418670715290696">"ব্যক্তিগত"</string> + <string name="profile_label_private" msgid="6463418670715290696">"প্রাইভেট"</string> <string name="profile_label_clone" msgid="769106052210954285">"ক্লোন করুন"</string> <string name="profile_label_work" msgid="3495359133038584618">"অফিস"</string> <string name="profile_label_work_2" msgid="4691533661598632135">"২য় অফিস"</string> diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml index a4d1b46b54b7..0438302d762b 100644 --- a/core/res/res/values-bs/strings.xml +++ b/core/res/res/values-bs/strings.xml @@ -202,10 +202,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Radni profil više nije dostupan na ovom uređaju"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Previše puta ste pokušali otključati uređaj"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"Administrator je ustupio uređaj za ličnu upotrebu"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"Privatni prostor je uklonjen"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"Organizacija ne dozvoljava privatne prostore na ovom uređaju kojim se upravlja."</string> <string name="network_logging_notification_title" msgid="554983187553845004">"Uređajem se upravlja."</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"Vaša organizacija upravlja ovim uređajem i može pratiti mrežni saobraćaj. Dodirnite za detalje."</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"Aplikacije mogu pristupiti vašoj lokaciji"</string> @@ -2199,7 +2197,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Upravljač lijevo"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Upravljač desno"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Upravljač sredina"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Traka za natpis aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Paket <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> je stavljen u odjeljak OGRANIČENO"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"je poslao/la sliku"</string> diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index 3219c566f80e..21f397b0e093 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -202,10 +202,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"El teu perfil de treball ja no està disponible en aquest dispositiu"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Has intentat introduir la contrasenya massa vegades"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"L\'administrador ha cedit el dispositiu per a ús personal"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"S\'ha suprimit l\'espai privat"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"La teva organització no permet espais privats en aquest dispositiu gestionat."</string> <string name="network_logging_notification_title" msgid="554983187553845004">"El dispositiu està gestionat"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"La teva organització gestiona aquest dispositiu i és possible que supervisi el trànsit de xarxa. Toca per obtenir més informació."</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"Les aplicacions poden accedir a la teva ubicació"</string> @@ -2199,7 +2197,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Creu direccional: esquerra"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Creu direccional: dreta"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Creu direccional: centre"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra de títol de l\'aplicació <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> s\'ha transferit al segment RESTRINGIT"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"ha enviat una imatge"</string> diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index 2305f6a64175..4013a034a5c3 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -203,10 +203,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Váš pracovní profil v tomto zařízení již není k dispozici"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Příliš mnoho pokusů o zadání hesla"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"Administrátor zařízení uvolnil k osobnímu používání"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"Soukromý prostor byl odstraněn"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"Vaše organizace na tomto spravovaném zařízení soukromé prostory nepovoluje."</string> <string name="network_logging_notification_title" msgid="554983187553845004">"Zařízení je spravováno"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"Toto zařízení je spravováno vaší organizací, která může sledovat síťový provoz. Podrobnosti zobrazíte klepnutím."</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"Aplikace mají přístup k vaší poloze"</string> @@ -2200,7 +2198,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad doleva"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad doprava"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad střed"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Popisek aplikace <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Balíček <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> byl vložen do sekce OMEZENO"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"posílá obrázek"</string> @@ -2401,9 +2398,9 @@ <string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Rozložení klávesnice je nastaveno na <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… Klepnutím jej změníte."</string> <string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Fyzické klávesnice byly nakonfigurovány"</string> <string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Klepnutím zobrazíte klávesnice"</string> - <string name="profile_label_private" msgid="6463418670715290696">"Soukromé"</string> + <string name="profile_label_private" msgid="6463418670715290696">"Soukromý"</string> <string name="profile_label_clone" msgid="769106052210954285">"Klonovat"</string> - <string name="profile_label_work" msgid="3495359133038584618">"Práce"</string> + <string name="profile_label_work" msgid="3495359133038584618">"Pracovní"</string> <string name="profile_label_work_2" msgid="4691533661598632135">"Práce 2"</string> <string name="profile_label_work_3" msgid="4834572253956798917">"Práce 3"</string> <string name="profile_label_test" msgid="9168641926186071947">"Test"</string> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index dd506350da28..5226d562384c 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -2196,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"D-pad, venstre"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"D-pad, højre"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"D-pad, midten"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Titellinje for <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> er blevet placeret i samlingen BEGRÆNSET"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"sendte et billede"</string> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index af5a20da975f..949150ac18c4 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -201,10 +201,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Dein Arbeitsprofil ist auf diesem Gerät nicht mehr verfügbar"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Zu viele falsche Passworteingaben"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"Administrator hat das Gerät zur persönlichen Nutzung abgegeben"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"Vertrauliches Profil entfernt"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"Deine Organisation erlaubt auf diesem verwalteten Gerät keine vertraulichen Profile."</string> <string name="network_logging_notification_title" msgid="554983187553845004">"Dies ist ein verwaltetes Gerät"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"Deine Organisation verwaltet dieses Gerät und überprüft unter Umständen den Netzwerkverkehr. Tippe hier, um weitere Informationen zu erhalten."</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"Apps können auf deinen Standort zugreifen"</string> @@ -2198,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Steuerkreuz nach links"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Steuerkreuz nach rechts"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Steuerkreuz Mitte"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Untertitelleiste von <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> wurde in den BESCHRÄNKT-Bucket gelegt"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"hat ein Bild gesendet"</string> diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index 31a52c856e36..11dac6c4e16b 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -201,10 +201,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Το προφίλ εργασίας σας δεν είναι πια διαθέσιμο σε αυτήν τη συσκευή"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Πάρα πολλές προσπάθειες εισαγωγής κωδικού πρόσβασης"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"Συσκευή από την οποία αποσύρθηκε ο διαχειριστής για προσωπική χρήση"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"Ο ιδιωτικός χώρος καταργήθηκε"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"Ο οργανισμός σας δεν επιτρέπει ιδιωτικούς χώρους σε αυτή τη διαχειριζόμενη συσκευή."</string> <string name="network_logging_notification_title" msgid="554983187553845004">"Η συσκευή είναι διαχειριζόμενη"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"Ο οργανισμός σας διαχειρίζεται αυτήν τη συσκευή και ενδέχεται να παρακολουθεί την επισκεψιμότητα δικτύου. Πατήστε για λεπτομέρειες."</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"Οι εφαρμογές μπορούν να αποκτήσουν πρόσβαση στην τοποθεσία σας"</string> @@ -2198,14 +2196,13 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad αριστερά"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad δεξιά"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad κέντρο"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Γραμμή υποτίτλων για την εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Το πακέτο <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> τοποθετήθηκε στον κάδο ΠΕΡΙΟΡΙΣΜΕΝΗΣ ΠΡΟΣΒΑΣΗΣ."</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"έστειλε μια εικόνα"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Συνομιλία"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Ομαδική συνομιλία"</string> <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> - <string name="resolver_personal_tab" msgid="2051260504014442073">"Προσωπικό"</string> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Προσωπικός"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Εργασία"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Προσωπική προβολή"</string> <string name="resolver_work_tab_accessibility" msgid="4753168230363802734">"Προβολή εργασίας"</string> @@ -2399,7 +2396,7 @@ <string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Η διάταξη πληκτρολογίου ορίστηκε σε <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… Πατήστε για αλλαγή."</string> <string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Τα φυσικά πληκτρολόγια διαμορφώθηκαν"</string> <string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Πατήστε για να δείτε πληκτρολόγια"</string> - <string name="profile_label_private" msgid="6463418670715290696">"Ιδιωτικό"</string> + <string name="profile_label_private" msgid="6463418670715290696">"Ιδιωτικός"</string> <string name="profile_label_clone" msgid="769106052210954285">"Κλώνος"</string> <string name="profile_label_work" msgid="3495359133038584618">"Εργασία"</string> <string name="profile_label_work_2" msgid="4691533661598632135">"Εργασία 2"</string> diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml index a0511552f9c2..1effe7c8f7d1 100644 --- a/core/res/res/values-en-rAU/strings.xml +++ b/core/res/res/values-en-rAU/strings.xml @@ -2196,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad left"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad right"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad centre"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Caption bar of <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> has been put into the RESTRICTED bucket"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"sent an image"</string> diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml index 8f3f623dcb5d..4abc5816a744 100644 --- a/core/res/res/values-en-rCA/strings.xml +++ b/core/res/res/values-en-rCA/strings.xml @@ -2196,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad Left"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad Right"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad Center"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Caption bar of <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> has been put into the RESTRICTED bucket"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"sent an image"</string> diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml index ff3c20a25a5f..425d88ce49ea 100644 --- a/core/res/res/values-en-rGB/strings.xml +++ b/core/res/res/values-en-rGB/strings.xml @@ -2196,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad left"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad right"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad centre"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Caption bar of <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> has been put into the RESTRICTED bucket"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"sent an image"</string> diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml index daa61abfd79d..56ff14aa994c 100644 --- a/core/res/res/values-en-rIN/strings.xml +++ b/core/res/res/values-en-rIN/strings.xml @@ -2196,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad left"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad right"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad centre"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Caption bar of <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> has been put into the RESTRICTED bucket"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"sent an image"</string> diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml index 98cac20dd061..e599c0355c8b 100644 --- a/core/res/res/values-en-rXC/strings.xml +++ b/core/res/res/values-en-rXC/strings.xml @@ -2196,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad Left"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad Right"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad Center"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Caption bar of <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> has been put into the RESTRICTED bucket"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"sent an image"</string> diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index 98a2c5055805..f5859bf78846 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -202,10 +202,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Tu perfil de trabajo ya no está disponible en este dispositivo"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Demasiados intentos para ingresar la contraseña"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"El administrador no permite hacer un uso personal del dispositivo"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"Se quitó el espacio privado"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"Tu organización no permite espacios privados en este dispositivo administrado."</string> <string name="network_logging_notification_title" msgid="554983187553845004">"Dispositivo administrado"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"Tu organización administra este dispositivo y es posible que controle el tráfico de red. Presiona para obtener más información."</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"Las apps pueden acceder a tu ubicación"</string> @@ -2199,7 +2197,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Pad direccional: izquierda"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Pad direccional: derecha"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Pad direccional: centro"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra de subtítulos de <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Se colocó <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> en el bucket RESTRICTED"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"envió una imagen"</string> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index 2e230422493d..d8b1f59a721d 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -202,10 +202,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Tu perfil de trabajo ya no está disponible en este dispositivo"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Has fallado demasiadas veces al introducir la contraseña"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"El administrador no permite hacer un uso personal del dispositivo"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"Espacio privado eliminado"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"Tu organización no permite espacios privados en este dispositivo gestionado."</string> <string name="network_logging_notification_title" msgid="554983187553845004">"El dispositivo está administrado"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"Tu organización administra este dispositivo y puede supervisar el tráfico de red. Toca la notificación para obtener más información."</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"Las aplicaciones pueden acceder a tu ubicación"</string> @@ -2199,7 +2197,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Cruceta: izquierda"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Cruceta: derecha"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Cruceta: centro"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra de subtítulos de <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> se ha incluido en el grupo de restringidos"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"ha enviado una imagen"</string> diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml index 6f80461fc692..77e665aa87a9 100644 --- a/core/res/res/values-et/strings.xml +++ b/core/res/res/values-et/strings.xml @@ -2196,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Suunaklahvistiku vasaknool"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Suunaklahvistiku paremnool"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Suunaklahvistiku keskmine nupp"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> pealkirjariba."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> on lisatud salve PIIRANGUTEGA"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"saatis kujutise"</string> diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml index 2a544f3410db..9bf2a4d0380e 100644 --- a/core/res/res/values-eu/strings.xml +++ b/core/res/res/values-eu/strings.xml @@ -2196,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Norabide-kontrolagailuko ezkerreko botoia"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Norabide-kontrolagailuko eskuineko botoia"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Norabide-kontrolagailuko erdiko botoia"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioko azpitituluen barra."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Murriztuen edukiontzian ezarri da <xliff:g id="PACKAGE_NAME">%1$s</xliff:g>"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"erabiltzaileak irudi bat bidali du"</string> diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index 96d120398a4d..308260f0019d 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -2196,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"پد کنترل چپ"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"پد کنترل راست"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"پد کنترل وسط"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"نوار شرح <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> در سطل «محدودشده» قرار گرفت"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"تصویری ارسال کرد"</string> diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml index 876094803703..db579f223781 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -2196,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Suuntanäppäimistö: vasen painike"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Suuntanäppäimistö: oikea painike"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Suuntanäppäimistö: keskipainike"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Tekstityspalkki: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> on nyt rajoitettujen ryhmässä"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"lähetti kuvan"</string> diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml index 4aeb86ed55b4..8888005be1d3 100644 --- a/core/res/res/values-fr-rCA/strings.xml +++ b/core/res/res/values-fr-rCA/strings.xml @@ -202,10 +202,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Votre profil professionnel n\'est plus accessible sur cet appareil"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Trop de tentatives d\'entrée du mot de passe"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"L\'administrateur a libéré l\'appareil pour un usage personnel"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"Espace privé retiré"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"Votre organisation n\'autorise pas les espaces privés sur cet appareil géré."</string> <string name="network_logging_notification_title" msgid="554983187553845004">"L\'appareil est géré"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"Votre organisation gère cet appareil et peut surveiller le trafic réseau. Touchez ici pour obtenir plus d\'information."</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"Les applications peuvent accéder à votre position"</string> @@ -2199,7 +2197,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Pavé directionnel – gauche"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Pavé directionnel – droite"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Pavé directionnel – centre"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barre de légende de l\'application <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> a été placé dans le compartiment RESTREINT"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g> :"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"a envoyé une image"</string> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index f3801334fa8c..4c2835d4f1cb 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -202,10 +202,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Votre profil professionnel n\'est plus disponible sur cet appareil"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Trop de tentatives de saisie du mot de passe"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"L\'administrateur a mis l\'appareil à disposition pour un usage personnel"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"Espace privé supprimé"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"Votre organisation n\'autorise pas les espaces privés sur cet appareil géré."</string> <string name="network_logging_notification_title" msgid="554983187553845004">"L\'appareil est géré"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"Votre organisation gère cet appareil et peut surveiller le trafic réseau. Appuyez ici pour obtenir plus d\'informations."</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"Des applications peuvent accéder à votre position"</string> @@ -2199,7 +2197,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Pavé directionnel - Gauche"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Pavé directionnel - Droite"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Pavé directionnel - Centre"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barre de légende de l\'application <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> a été placé dans le bucket RESTRICTED"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g> :"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"a envoyé une image"</string> diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml index 342d76b03589..cb8e8046db81 100644 --- a/core/res/res/values-gl/strings.xml +++ b/core/res/res/values-gl/strings.xml @@ -201,10 +201,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"O teu perfil de traballo xa non está dispoñible neste dispositivo"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Demasiados intentos de introdución do contrasinal"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"O administrador renunciou ao dispositivo para uso persoal"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"Quitouse o espazo privado"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"A túa organización non permite espazos privados neste dispositivo xestionado."</string> <string name="network_logging_notification_title" msgid="554983187553845004">"O dispositivo está xestionado"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"A túa organización xestiona este dispositivo e pode controlar o tráfico de rede. Toca para obter máis detalles."</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"As aplicacións poden acceder á túa localización"</string> @@ -2198,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Cruceta: esquerda"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Cruceta: dereita"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Cruceta: centro"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra de subtítulos de <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> incluíuse no grupo RESTRINXIDO"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"enviouse unha imaxe"</string> diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml index 5aca7d63be70..55032c9301af 100644 --- a/core/res/res/values-gu/strings.xml +++ b/core/res/res/values-gu/strings.xml @@ -201,10 +201,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"આ ઉપકરણ પર તમારી કાર્યાલયની પ્રોફાઇલ હવે ઉપલબ્ધ નથી"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"પાસવર્ડના ઘણા વધુ પ્રયત્નો"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"વ્યવસ્થાપકે ડિવાઇસ વ્યક્તિગત ઉપયોગ માટે આપી દીધું છે"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"ખાનગી સ્પેસ કાઢી નાખી"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"મેનેજ કરેલા ડિવાઇસ પર, તમારી સંસ્થા દ્વારા ખાનગી સ્પેસને મંજૂરી આપવામાં આવતી નથી."</string> <string name="network_logging_notification_title" msgid="554983187553845004">"ડિવાઇસ મેનેજ થયેલ છે"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"તમારી સંસ્થા આ ઉપકરણનું સંચાલન કરે છે અને નેટવર્ક ટ્રાફિફનું નિયમન કરી શકે છે. વિગતો માટે ટૅપ કરો."</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"ઍપ તમારા સ્થાનને ઍક્સેસ કરી શકે છે"</string> @@ -2198,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"ડી-પૅડ ડાબે"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"ડી-પૅડ જમણે"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"ડી-પૅડ મધ્યમાં"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>નું કૅપ્શન બાર."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>ને પ્રતિબંધિત સમૂહમાં મૂકવામાં આવ્યું છે"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"છબી મોકલી"</string> diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml index 3af0279c847d..e47715ab25f2 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/strings.xml @@ -201,10 +201,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"आपकी वर्क प्रोफ़ाइल अब इस डिवाइस पर उपलब्ध नहीं है"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"कई बार गलत पासवर्ड डाला गया"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"एडमिन ने निजी इस्तेमाल के लिए डिवाइस दे दिया है"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"प्राइवेट स्पेस हटाया गया"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"आपका संगठन मैनेज किए जा रहे इस डिवाइस पर प्राइवेट स्पेस रखने की अनुमति नहीं देता है."</string> <string name="network_logging_notification_title" msgid="554983187553845004">"डिवाइस प्रबंधित है"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"आपका संगठन इस डिवाइस का प्रबंधन करता है और वह नेटवर्क ट्रैफ़िक की निगरानी भी कर सकता है. विवरण के लिए टैप करें."</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"ऐप्लिकेशन आपकी जगह की जानकारी ऐक्सेस कर सकते हैं"</string> @@ -2198,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"डी-पैड का बाईं ओर वाला बटन"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"डी-पैड का दाईं ओर वाला बटन"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"डी-पैड का बीच वाला बटन"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> का कैप्शन बार."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> को प्रतिबंधित बकेट में रखा गया है"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"एक इमेज भेजी गई"</string> diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml index 57caeecb6488..0b9b662397f2 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -202,10 +202,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Vaš poslovni profil više nije dostupan na ovom uređaju"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Previše pokušaja unosa zaporke"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"Administrator je ustupio uređaj za osobnu upotrebu"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"Privatni prostor je uklonjen"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"Vaša organizacija ne dopušta privatne prostore na ovom upravljanom uređaju."</string> <string name="network_logging_notification_title" msgid="554983187553845004">"Uređaj je upravljan"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"Vaša organizacija upravlja ovim uređajem i može nadzirati mrežni promet. Dodirnite za pojedinosti."</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"Aplikacije mogu pristupiti vašoj lokaciji"</string> @@ -2199,7 +2197,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Lijevo na plohi za smjerove"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Desno na plohi za smjerove"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"U središtu plohe za smjerove"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Traka naslova aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Paket <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> premješten je u spremnik OGRANIČENO"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"šalje sliku"</string> diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index 8447d798b07e..de6777e8bce7 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -201,10 +201,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Munkaprofilja már nem hozzáférhető ezen az eszközön."</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Túl sok jelszómegadási kísérlet"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"Az adminisztrátor átadta az eszközt személyes használatra"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"Privát terület eltávolítva"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"A szervezete nem engedélyez privát területeket ezen a kezelt eszközön."</string> <string name="network_logging_notification_title" msgid="554983187553845004">"Felügyelt eszköz"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"Ezt az eszközt szervezete kezeli, és lehetséges, hogy a hálózati forgalmat is figyelik. További részletekért koppintson."</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"Az alkalmazások hozzáférhetnek az Ön tartózkodási helyéhez"</string> @@ -2198,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"D-pad – balra"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"D-pad – jobbra"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"D-pad – középre"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazás címsora."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"A következő csomag a KORLÁTOZOTT csoportba került: <xliff:g id="PACKAGE_NAME">%1$s</xliff:g>"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"képet küldött"</string> diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml index e8827942140c..58331c7a1b3b 100644 --- a/core/res/res/values-hy/strings.xml +++ b/core/res/res/values-hy/strings.xml @@ -201,10 +201,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Ձեր աշխատանքային պրոֆիլն այս սարքում այլևս հասանելի չէ"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Գաղտնաբառը մուտքագրելու չափից շատ փորձեր են կատարվել"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"Ադմինիստրատորը տրամադրել է սարքը անձնական օգտագործման համար"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"Մասնավոր տարածքը հեռացվել է"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"Ձեր կազմակերպությունն արգելում է մասնավոր տարածքներն այս կառավարվող սարքում։"</string> <string name="network_logging_notification_title" msgid="554983187553845004">"Սարքը կառավարվում է"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"Ձեր կազմակերպությունը կառավարում է այս սարքը և կարող է վերահսկել ցանցի թրաֆիկը: Հպեք՝ մանրամասները դիտելու համար:"</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"Հավելվածներին հասանելի է ձեր տեղադրությունը"</string> @@ -2198,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad-ի «Ձախ» կոճակ"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad-ի «Աջ» կոճակ"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad-ի «Կենտրոն» կոճակ"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածի ենթագրերի գոտին։"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> փաթեթը գցվեց ՍԱՀՄԱՆԱՓԱԿՎԱԾ զամբյուղի մեջ"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>՝"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"օգտատերը պատկեր է ուղարկել"</string> diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index a075749f333c..eeaf2b6514fa 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -201,10 +201,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Profil kerja tidak tersedia lagi di perangkat ini"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Terlalu banyak kesalahan sandi"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"Admin melepaskan perangkat untuk penggunaan pribadi"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"Ruang privasi dihapus"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"Organisasi Anda tidak mengizinkan adanya ruang privasi di perangkat terkelola ini."</string> <string name="network_logging_notification_title" msgid="554983187553845004">"Perangkat ini ada yang mengelola"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"Organisasi mengelola perangkat ini dan mungkin memantau traffic jaringan. Ketuk untuk melihat detailnya."</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"Aplikasi dapat mengakses lokasi Anda"</string> @@ -2198,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad Kiri"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad Kanan"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad Tengah"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Kolom teks <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> telah dimasukkan ke dalam bucket DIBATASI"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"mengirim gambar"</string> diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml index 8b6f7c7e3969..7e68a06cc9f8 100644 --- a/core/res/res/values-is/strings.xml +++ b/core/res/res/values-is/strings.xml @@ -2196,14 +2196,13 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Vinstrihnappur stýriflatar"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Hægrihnappur stýriflatar"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Miðjuhnappur stýriflatar"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Skjátextastika <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> var sett í flokkinn TAKMARKAÐ"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"sendi mynd"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Samtal"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Hópsamtal"</string> <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> - <string name="resolver_personal_tab" msgid="2051260504014442073">"Persónulegt"</string> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Einkasnið"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Vinna"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Persónulegt yfirlit"</string> <string name="resolver_work_tab_accessibility" msgid="4753168230363802734">"Vinnuyfirlit"</string> @@ -2397,7 +2396,7 @@ <string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Lyklaskipan er stillt á <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… Ýttu til að breyta."</string> <string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Vélbúnaðarlyklaborð eru stillt"</string> <string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Ýttu til að sjá lyklaborð"</string> - <string name="profile_label_private" msgid="6463418670715290696">"Lokað"</string> + <string name="profile_label_private" msgid="6463418670715290696">"Leynirými"</string> <string name="profile_label_clone" msgid="769106052210954285">"Afrit"</string> <string name="profile_label_work" msgid="3495359133038584618">"Vinna"</string> <string name="profile_label_work_2" msgid="4691533661598632135">"Vinna 2"</string> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index abd1c29b1a8d..037e148cd60a 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -2199,7 +2199,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"D-pad - Sinistra"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"D-pad - Destra"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"D-pad - Centro"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra del titolo di <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> è stato inserito nel bucket RESTRICTED"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"ha inviato un\'immagine"</string> diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index 0c70e911ffa0..a1e72da42cae 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -202,10 +202,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"פרופיל העבודה שלך אינו זמין עוד במכשיר הזה"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"בוצעו ניסיונות רבים מדי להזנת סיסמה"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"מנהל המערכת ביטל את האפשרות לשימוש במכשיר לצרכים אישיים"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"המרחב הפרטי הוסר"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"הארגון שלך לא מאפשר שימוש במרחבים פרטיים במכשיר המנוהל הזה."</string> <string name="network_logging_notification_title" msgid="554983187553845004">"המכשיר מנוהל"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"הארגון שלך מנהל את המכשיר הזה והוא עשוי לנטר את התנועה ברשת. יש להקיש לקבלת פרטים."</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"לאפליקציות יש הרשאת גישה למיקום שלך"</string> @@ -2199,7 +2197,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"לחצן שמאלי ב-Dpad"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"לחצן ימני ב-Dpad"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"לחצן אמצעי ב-Dpad"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"סרגל כיתוב של <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> התווספה לקטגוריה \'מוגבל\'"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"נשלחה תמונה"</string> @@ -2400,7 +2397,7 @@ <string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"פריסת המקלדת מוגדרת ל<xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… אפשר להקיש כדי לשנות את ההגדרה הזו."</string> <string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"הוגדרו מקלדות פיזיות"</string> <string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"יש להקיש כדי להציג את המקלדות"</string> - <string name="profile_label_private" msgid="6463418670715290696">"פרופיל פרטי"</string> + <string name="profile_label_private" msgid="6463418670715290696">"פרטי"</string> <string name="profile_label_clone" msgid="769106052210954285">"שכפול"</string> <string name="profile_label_work" msgid="3495359133038584618">"פרופיל עבודה"</string> <string name="profile_label_work_2" msgid="4691533661598632135">"פרופיל עבודה 2"</string> diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index 4704e380993a..04e47a782e12 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -201,10 +201,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"お使いの仕事用プロファイルはこのデバイスで使用できなくなりました"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"パスワード入力回数が上限に達しました"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"管理者により、デバイスの個人使用が許可されました"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"プライベート スペースの削除"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"この管理対象デバイス上のプライベート スペースは組織で許可されていません。"</string> <string name="network_logging_notification_title" msgid="554983187553845004">"管理対象のデバイス"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"このデバイスは組織によって管理され、ネットワーク トラフィックが監視される場合があります。詳しくはタップしてください。"</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"アプリに位置情報へのアクセスを許可しました"</string> @@ -2198,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"D-pad: 左"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"D-pad: 右"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"D-pad: 中央"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> のキャプション バーです。"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> は RESTRICTED バケットに移動しました。"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"画像を送信しました"</string> diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml index e0a507ebc35c..4f87855446d6 100644 --- a/core/res/res/values-ka/strings.xml +++ b/core/res/res/values-ka/strings.xml @@ -201,10 +201,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"თქვენი სამსახურის პროფილი აღარ არის ხელმისაწვდომი ამ მოწყობილობაზე"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"დაფიქსირდა პაროლის შეყვანის ზედმეტად ბევრი მცდელობა"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"ადმინისტრატორმა გაათავისუფლა მოწყობილობა პირადი გამოყენებისთვის"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"კერძო სივრცე ამოშლილია"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"თქვენი ორგანიზაცია არ უშვებს ამ მართულ მოწყობილობაზე პირად სივრცეებს."</string> <string name="network_logging_notification_title" msgid="554983187553845004">"მოწყობილობა მართულია"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"ამ მოწყობილობას თქვენი ორგანიზაცია მართავს და მას ქსელის ტრაფიკის მონიტორინგი შეუძლია. შეეხეთ დამატებითი დეტალებისთვის."</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"აპებს შეუძლია თქვენს მდებარეობაზე წვდომა"</string> @@ -2198,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad მარცხნივ"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad მარჯვნივ"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad ცენტრი"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ის სუბტიტრების ზოლი."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> მოთავსდა კალათაში „შეზღუდული“"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"გაიგზავნა სურათი"</string> diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml index 04c99a2ae6ad..f36d9fca2a35 100644 --- a/core/res/res/values-kk/strings.xml +++ b/core/res/res/values-kk/strings.xml @@ -201,10 +201,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Жұмыс профиліңіз осы құрылғыда енді қолжетімді емес"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Құпия сөз көп рет қате енгізілді"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"Әкімші құрылғыны жеке пайдалануға ұсынды."</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"Құпия кеңістік өшірілді"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"Ұйымыңыз басқаратын құрылғыда құпия кеңістік мүмкіндіктерін пайдалануға рұқсат етілмейді."</string> <string name="network_logging_notification_title" msgid="554983187553845004">"Құрылғы басқарылады"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"Ұйымыңыз осы құрылғыны басқарады және желі трафигін бақылауы мүмкін. Мәліметтер алу үшін түртіңіз."</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"Қолданбалар геодерегіңізді пайдалана алады"</string> @@ -2198,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Сол жақ Dpad түймесі"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Оң жақ Dpad түймесі"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Ортаңғы Dpad түймесі"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасының жазу жолағы."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ШЕКТЕЛГЕН себетке салынды."</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"сурет жіберілді"</string> @@ -2399,7 +2396,7 @@ <string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Пернетақта схемасы \"<xliff:g id="LAYOUT_1">%1$s</xliff:g>\", \"<xliff:g id="LAYOUT_2">%2$s</xliff:g>\", \"<xliff:g id="LAYOUT_3">%3$s</xliff:g>\" деп орнатылды… Өзгерту үшін түртіңіз."</string> <string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Физикалық пернетақталар конфигурацияланды"</string> <string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Пернетақталарды көру үшін түртіңіз."</string> - <string name="profile_label_private" msgid="6463418670715290696">"Жеке"</string> + <string name="profile_label_private" msgid="6463418670715290696">"Құпия"</string> <string name="profile_label_clone" msgid="769106052210954285">"Клон"</string> <string name="profile_label_work" msgid="3495359133038584618">"Жұмыс"</string> <string name="profile_label_work_2" msgid="4691533661598632135">"Жұмыс 2"</string> diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml index 527745c1bb90..195eb133c872 100644 --- a/core/res/res/values-km/strings.xml +++ b/core/res/res/values-km/strings.xml @@ -201,10 +201,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"កម្រងព័ត៌មានការងាររបស់អ្នកលែងមាននៅលើឧបករណ៍នេះទៀតហើយ"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"ការព្យាយាមបញ្ចូលពាក្យសម្ងាត់ច្រើនដងពេកហើយ"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"អ្នកគ្រប់គ្រងបានបោះបង់ឧបករណ៍ចោលដោយសារការប្រើប្រាស់ផ្ទាល់ខ្លួន"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"លំហឯកជនត្រូវបានដកចេញ"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"ស្ថាប័នរបស់អ្នកមិនអនុញ្ញាតលំហឯកជននៅលើឧបករណ៍ដែលស្ថិតក្រោមការគ្រប់គ្រងនេះទេ។"</string> <string name="network_logging_notification_title" msgid="554983187553845004">"ឧបករណ៍ស្ថិតក្រោមការគ្រប់គ្រង"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"ស្ថាប័នរបស់អ្នកគ្រប់គ្រងឧបករណ៍នេះ ហើយអាចនឹងតាមដានចរាចរណ៍បណ្តាញ។ ចុចដើម្បីទទួលបានព័ត៌មានលម្អិត។"</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"កម្មវិធីអាចចូលប្រើទីតាំងរបស់អ្នកបាន"</string> @@ -2198,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad ឆ្វេង"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad ស្ដាំ"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad កណ្ដាល"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"របារពណ៌នាអំពី <xliff:g id="APP_NAME">%1$s</xliff:g>។"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ត្រូវបានដាក់ទៅក្នុងធុងដែលបានដាក់កំហិត"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>៖"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"បានផ្ញើរូបភាព"</string> diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml index ade6f76e5647..073e44885f6c 100644 --- a/core/res/res/values-kn/strings.xml +++ b/core/res/res/values-kn/strings.xml @@ -201,10 +201,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"ನಿಮ್ಮ ಉದ್ಯೋಗ ಪ್ರೊಫೈಲ್ ಈ ಸಾಧನದಲ್ಲಿ ಈಗ ಲಭ್ಯವಿಲ್ಲ"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"ಹಲವಾರು ಪಾಸ್ವರ್ಡ್ ಪ್ರಯತ್ನಗಳು"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"ವೈಯಕ್ತಿಕ ಬಳಕೆಗಾಗಿ ನಿರ್ವಾಹಕರು ತೊರೆದ ಸಾಧನ"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"ಪ್ರೈವೆಟ್ ಸ್ಪೇಸ್ ಅನ್ನು ತೆಗೆದುಹಾಕಲಾಗಿದೆ"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"ಈ ನಿರ್ವಹಿಸಲಾದ ಸಾಧನದಲ್ಲಿ ಪ್ರೈವೆಟ್ ಸ್ಪೇಸ್ಗಳನ್ನು ನಿಮ್ಮ ಸಂಸ್ಥೆಯು ಅನುಮತಿಸುವುದಿಲ್ಲ."</string> <string name="network_logging_notification_title" msgid="554983187553845004">"ಸಾಧನವನ್ನು ನಿರ್ವಹಿಸಲಾಗುತ್ತಿದೆ"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"ನಿಮ್ಮ ಸಂಸ್ಥೆಯು ಈ ಸಾಧನವನ್ನು ನಿರ್ವಹಿಸುತ್ತದೆ ಮತ್ತು ಅದು ನೆಟ್ವರ್ಕ್ ಟ್ರಾಫಿಕ್ ಮೇಲೆ ಗಮನವಿರಿಸಬಹುದು. ವಿವರಗಳಿಗಾಗಿ ಟ್ಯಾಪ್ ಮಾಡಿ."</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"ಆ್ಯಪ್ಗಳು ನಿಮ್ಮ ಸ್ಥಳವನ್ನು ಪ್ರವೇಶಿಸಬಹುದು"</string> @@ -2198,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad ನ ಎಡಭಾಗದ ಬಟನ್"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad ನ ಬಲಭಾಗದ ಬಟನ್"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad ನ ಮಧ್ಯದ ಬಟನ್"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಆ್ಯಪ್ನ ಶೀರ್ಷಿಕೆಯ ಪಟ್ಟಿ."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ಅನ್ನು ನಿರ್ಬಂಧಿತ ಬಕೆಟ್ಗೆ ಹಾಕಲಾಗಿದೆ"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"ಚಿತ್ರವನ್ನು ಕಳುಹಿಸಲಾಗಿದೆ"</string> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index c60482f12d03..bbe8aef4bc70 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -2196,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"방향 패드 왼쪽"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"방향 패드 오른쪽"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"방향 패드 가운데"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>의 자막 표시줄입니다."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> 항목이 RESTRICTED 버킷으로 이동함"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"이미지 보냄"</string> diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml index c23e49a781f1..9686a141d528 100644 --- a/core/res/res/values-ky/strings.xml +++ b/core/res/res/values-ky/strings.xml @@ -2196,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad\'дын сол баскычы"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad\'дын оң баскычы"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad\'дын ортоңку баскычы"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосунун маалымат тилкеси."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ЧЕКТЕЛГЕН чакага коюлган"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"сүрөт жөнөттү"</string> diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml index 12f59b7fb8a6..b6bd4b2dec51 100644 --- a/core/res/res/values-lo/strings.xml +++ b/core/res/res/values-lo/strings.xml @@ -2196,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad ຊ້າຍ"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad ຂວາ"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad ກາງ"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"ແຖບຄຳບັນຍາຍຂອງ <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ຖືກວາງໄວ້ໃນກະຕ່າ \"ຈຳກັດ\" ແລ້ວ"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"ສົ່ງຮູບແລ້ວ"</string> diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml index c4e228c34fc4..2b4f370ffc45 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -203,10 +203,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Darbo profilis nebepasiekiamas šiame įrenginyje"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Per daug slaptažodžio bandymų"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"Administratorius atmetė prašymą įrenginį naudoti asmeniniais tikslais"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"Privati erdvė pašalinta"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"Jūsų organizacija neleidžia naudoti privačių erdvių šiame tvarkomame įrenginyje."</string> <string name="network_logging_notification_title" msgid="554983187553845004">"Įrenginys yra tvarkomas"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"Šį įrenginį tvarko organizacija ir gali stebėti tinklo srautą. Palieskite, kad gautumėte daugiau informacijos."</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"Programos gali pasiekti jūsų vietovę"</string> @@ -2200,7 +2198,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Valdymo pultas – kairėn"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Valdymo pultas – dešinėn"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Valdymo pultas – centras"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Programos „<xliff:g id="APP_NAME">%1$s</xliff:g>“ antraštės juosta."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"„<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>“ įkeltas į grupę APRIBOTA"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"išsiuntė vaizdą"</string> diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml index c70abadc1ba7..3669f041f877 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -202,10 +202,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Jūsu darba profils šai ierīcē vairs nav pieejams."</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Veikts pārāk daudz paroles ievadīšanas mēģinājumu."</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"Administrators atteicās no tādas ierīces pārvaldības, ko var izmantot personiskām vajadzībām"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"Privātā telpa ir noņemta"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"Jūsu organizācija neatļauj izmantot privātās telpas šajā pārvaldītajā ierīcē."</string> <string name="network_logging_notification_title" msgid="554983187553845004">"Ierīce tiek pārvaldīta"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"Jūsu organizācija pārvalda šo ierīci un var uzraudzīt tīkla datplūsmu. Pieskarieties, lai saņemtu detalizētu informāciju."</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"Lietotne var piekļūt jūsu atrašanās vietas datiem"</string> @@ -2199,14 +2197,13 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Virzienu slēdzis — pa kreisi"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Virzienu slēdzis — pa labi"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Virzienu slēdzis — centrs"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Lietotnes <xliff:g id="APP_NAME">%1$s</xliff:g> subtitru josla."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Pakotne “<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>” ir ievietota ierobežotā kopā."</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"nosūtīts attēls"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Saruna"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Grupas saruna"</string> <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> - <string name="resolver_personal_tab" msgid="2051260504014442073">"Privātais profils"</string> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Personīgais"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Darba profils"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Personisks skats"</string> <string name="resolver_work_tab_accessibility" msgid="4753168230363802734">"Darba skats"</string> diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml index b3b2d73c3264..8902619d341d 100644 --- a/core/res/res/values-mk/strings.xml +++ b/core/res/res/values-mk/strings.xml @@ -201,10 +201,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Вашиот работен профил веќе не е достапен на уредов"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Премногу обиди за внесување лозинка"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"Уред откажан од администраторот за лична употреба"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"„Приватниот простор“ е отстранет"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"Вашата организација не дозволува „Приватен простор“ на управуваниов уред."</string> <string name="network_logging_notification_title" msgid="554983187553845004">"Некој управува со уредот"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"Вашата организација управува со уредов и можно е да го следи сообраќајот на мрежата. Допрете за детали."</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"Апликациите може да пристапуваат до вашата локација"</string> @@ -2198,14 +2196,13 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Навигациско копче за налево"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Навигациско копче за надесно"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Навигациско копче за средина"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Насловна лента на <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> е ставен во корпата ОГРАНИЧЕНИ"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"испрати слика"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Разговор"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Групен разговор"</string> <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> - <string name="resolver_personal_tab" msgid="2051260504014442073">"Лични"</string> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Лично"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"За работа"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Личен приказ"</string> <string name="resolver_work_tab_accessibility" msgid="4753168230363802734">"Работен приказ"</string> diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml index 97ce202718ac..005d7cb5da4f 100644 --- a/core/res/res/values-ml/strings.xml +++ b/core/res/res/values-ml/strings.xml @@ -201,10 +201,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"ഈ ഉപകരണത്തിൽ തുടർന്നങ്ങോട്ട് നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈൽ ലഭ്യമല്ല"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"വളരെയധികം പാസ്വേഡ് ശ്രമങ്ങൾ"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"വ്യക്തിപരമായ ഉപയോഗത്തിനായി, ഉപകരണത്തിന്റെ ഔദ്യോഗിക ഉപയോഗം അഡ്മിൻ അവസാനിപ്പിച്ചു"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"സ്വകാര്യ സ്പേസ് നീക്കം ചെയ്തു"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"മാനേജ് ചെയ്യപ്പെടുന്ന ഈ ഉപകരണത്തിൽ നിങ്ങളുടെ സ്ഥാപനം സ്വകാര്യ സ്പേസുകൾ അനുവദിക്കുന്നില്ല."</string> <string name="network_logging_notification_title" msgid="554983187553845004">"ഉപകരണം മാനേജുചെയ്യുന്നുണ്ട്"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"നിങ്ങളുടെ സ്ഥാപനമാണ് ഈ ഉപകരണം മാനേജുചെയ്യുന്നത്, നെറ്റ്വർക്ക് ട്രാഫിക്ക് നിരീക്ഷിക്കുകയും ചെയ്തേക്കാം, വിശദാംശങ്ങൾ അറിയാൻ ടാപ്പുചെയ്യുക."</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"ആപ്പുകൾക്ക് നിങ്ങളുടെ ലൊക്കേഷൻ ആക്സസ് ചെയ്യാനാകും"</string> @@ -2198,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad ലെഫ്റ്റ്"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad റൈറ്റ്"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad സെന്റർ"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> എന്നതിന്റെ അടിക്കുറിപ്പ് ബാർ."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> നിയന്ത്രിത ബക്കറ്റിലേക്ക് നീക്കി"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"ചിത്രം അയച്ചു"</string> diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml index 2d630acef2a7..ddbeb35cdf31 100644 --- a/core/res/res/values-mn/strings.xml +++ b/core/res/res/values-mn/strings.xml @@ -2196,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad зүүн"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad баруун"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad гол"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>-н гарчгийн талбар."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>-г ХЯЗГААРЛАСАН сагс руу орууллаа"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"зураг илгээсэн"</string> diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml index a6e3e6637977..77a58aff3157 100644 --- a/core/res/res/values-mr/strings.xml +++ b/core/res/res/values-mr/strings.xml @@ -201,10 +201,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"तुमचे कार्य प्रोफाइल आता या डिव्हाइसवर उपलब्ध नाही"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"बर्याचदा पासवर्ड टाकण्याचा प्रयत्न केला"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"वैयक्तिक वापरासाठी ॲडमिनने नियंत्रण सोडलेले डिव्हाइस"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"खाजगी स्पेस काढून टाकली आहे"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"तुमची संस्था या व्यवस्थापित केलेल्या डिव्हाइसवर खाजगी स्पेसना अनुमती देत नाही."</string> <string name="network_logging_notification_title" msgid="554983187553845004">"डिव्हाइस व्यवस्थापित केले आहे"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"तुमची संस्था हे डिव्हाइस व्यवस्थापित करते आणि नेटवर्क रहदारीचे निरीक्षण करू शकते. तपशीलांसाठी टॅप करा."</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"ॲप्स तुमचे स्थान अॅक्सेस करू शकतात"</string> @@ -2198,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad डावीकडील"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad चे उजवीकडील"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad चे मधले"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> चा शीर्षक बार."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> हे प्रतिबंधित बादलीमध्ये ठेवण्यात आले आहे"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"इमेज पाठवली आहे"</string> diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml index 4e4189fd7b2b..96691f60b151 100644 --- a/core/res/res/values-ms/strings.xml +++ b/core/res/res/values-ms/strings.xml @@ -201,10 +201,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Profil kerja anda tidak lagi tersedia pada peranti ini"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Terlalu banyak percubaan kata laluan"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"Pentadbir melepaskan peranti untuk kegunaan peribadi"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"Ruang privasi dialih keluar"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"Organisasi anda tidak membenarkan ruang privasi pada peranti terurus ini."</string> <string name="network_logging_notification_title" msgid="554983187553845004">"Peranti ini diurus"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"Organisasi anda mengurus peranti ini dan mungkin memantau trafik rangkaian. Ketik untuk mendapatkan butiran."</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"Apl boleh mengakses lokasi anda"</string> @@ -2198,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad Kiri"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad Kanan"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad Tengah"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Bar kapsyen <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> telah diletakkan dalam baldi TERHAD"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"menghantar imej"</string> @@ -2407,7 +2404,7 @@ <string name="profile_label_test" msgid="9168641926186071947">"Ujian"</string> <string name="profile_label_communal" msgid="8743921499944800427">"Umum"</string> <string name="accessibility_label_managed_profile" msgid="3366526886209832641">"Profil kerja"</string> - <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Ruang privasi"</string> + <string name="accessibility_label_private_profile" msgid="1436459319135548969">"Ruang persendirian"</string> <string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string> <string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Umum"</string> <string name="redacted_notification_message" msgid="1520587845842228816">"Kandungan pemberitahuan yang sensitif disembunyikan"</string> diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml index fa449ca59a6f..c1b782236a65 100644 --- a/core/res/res/values-my/strings.xml +++ b/core/res/res/values-my/strings.xml @@ -2196,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad ဘယ်"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad ညာ"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad အလယ်"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>၏ ခေါင်းစီး ဘား။"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ကို တားမြစ်ထားသော သိမ်းဆည်းမှုအတွင်းသို့ ထည့်ပြီးပါပြီ"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>-"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"ပုံပို့ထားသည်"</string> diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index a07639bddaff..23f675e73f78 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -201,10 +201,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Jobbprofilen din er ikke lenger tilgjengelig på denne enheten"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"For mange passordforsøk"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"Administratoren overførte enheten til personlig bruk"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"Det private området er fjernet"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"Organisasjonen din tillater ikke private områder på denne administrerte enheten."</string> <string name="network_logging_notification_title" msgid="554983187553845004">"Enheten administreres"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"Organisasjonen din kontrollerer denne enheten og kan overvåke nettverkstrafikk. Trykk for å få mer informasjon."</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"Apper har tilgang til posisjonen din"</string> @@ -2198,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Venstre på styrepilene"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Høyre på styrepilene"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Midt på styrepilene"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Tekstingsfelt i <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> er blitt plassert i TILGANGSBEGRENSET-toppmappen"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"har sendt et bilde"</string> diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml index 284b3886c51f..99dd0e4c2c9f 100644 --- a/core/res/res/values-ne/strings.xml +++ b/core/res/res/values-ne/strings.xml @@ -2196,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad को बायाँको बटन"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad को दायाँको बटन"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad को बिचको बटन"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> को क्याप्सन बार।"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> लाई प्रतिबन्धित बाल्टीमा राखियो"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"छवि पठाइयो"</string> diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index 0c55e6bfa77d..0b2c507b644f 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -2196,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"D-pad links"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"D-pad rechts"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"D-pad midden"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Ondertitelingsbalk van <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> is in de bucket RESTRICTED geplaatst"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"heeft een afbeelding gestuurd"</string> diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml index d38d824cd190..f3cd70e83db1 100644 --- a/core/res/res/values-or/strings.xml +++ b/core/res/res/values-or/strings.xml @@ -201,10 +201,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"ଏହି ଡିଭାଇସରେ ଆପଣଙ୍କ ୱର୍କ ପ୍ରୋଫାଇଲ୍ ଆଉ ଉପଲବ୍ଧ ନାହିଁ"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"ବହୁତ ଥର ଭୁଲ ପାସ୍ୱର୍ଡ ଲେଖିଛନ୍ତି"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"ବ୍ୟକ୍ତିଗତ ବ୍ୟବହାର ପାଇଁ ଆଡ୍ମିନ୍ ଡିଭାଇସ୍କୁ ଅଲଗା କରିଛନ୍ତି"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"ପ୍ରାଇଭେଟ ସ୍ପେସ କାଢ଼ି ଦିଆଯାଇଛି"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"ଆପଣଙ୍କ ସଂସ୍ଥା ଏହି ପରିଚାଳିତ ଡିଭାଇସରେ ପ୍ରାଇଭେଟ ସ୍ପେସକୁ ଅନୁମତି ଦିଏ ନାହିଁ।"</string> <string name="network_logging_notification_title" msgid="554983187553845004">"ଡିଭାଇସକୁ ପରିଚାଳନା କରାଯାଉଛି"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"ଆପଣଙ୍କ ସଂସ୍ଥା ଏହି ଡିଭାଇସକୁ ପରିଚାଳନା କରନ୍ତି ଏବଂ ନେଟୱର୍କ ଟ୍ରାଫିକ୍ ନୀରିକ୍ଷଣ କରନ୍ତି। ବିବରଣୀ ପାଇଁ ଟାପ୍ କରନ୍ତୁ।"</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"ଆପଗୁଡ଼ିକ ଆପଣଙ୍କ ଲୋକେସନକୁ ଆକ୍ସେସ୍ କରିପାରିବ"</string> @@ -2198,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad ବାମ"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad ଡାହାଣ"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad କେନ୍ଦ୍ର"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>ର କ୍ୟାପ୍ସନ୍ ବାର୍।"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>କୁ ପ୍ରତିବନ୍ଧିତ ବକେଟରେ ରଖାଯାଇଛି"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"ଏକ ଛବି ପଠାଯାଇଛି"</string> diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml index 61e184609419..60d8737405da 100644 --- a/core/res/res/values-pa/strings.xml +++ b/core/res/res/values-pa/strings.xml @@ -201,10 +201,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"ਤੁਹਾਡਾ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਹੁਣ ਇਸ ਡੀਵਾਈਸ \'ਤੇ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"ਕਈ ਵਾਰ ਗਲਤ ਪਾਸਵਰਡ ਦਾਖਲ ਕੀਤਾ ਗਿਆ"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"ਪ੍ਰਸ਼ਾਸਕ ਨੇ ਨਿੱਜੀ ਵਰਤੋਂ ਲਈ ਡੀਵਾਈਸ ਤਿਆਗਿਆ"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"ਪ੍ਰਾਈਵੇਟ ਸਪੇਸ ਨੂੰ ਹਟਾਇਆ ਗਿਆ"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"ਤੁਹਾਡੀ ਸੰਸਥਾ ਇਸ ਪ੍ਰਬੰਧਿਤ ਕੀਤੇ ਡੀਵਾਈਸ \'ਤੇ ਪ੍ਰਾਈਵੇਟ ਸਪੇਸਾਂ ਦੀ ਆਗਿਆ ਨਹੀਂ ਦਿੰਦੀ।"</string> <string name="network_logging_notification_title" msgid="554983187553845004">"ਡੀਵਾਈਸ ਪ੍ਰਬੰਧਨ ਅਧੀਨ ਹੈ"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"ਤੁਹਾਡਾ ਸੰਗਠਨ ਇਸ ਡੀਵਾਈਸ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰਦਾ ਹੈ ਅਤੇ ਨੈੱਟਵਰਕ ਟਰੈਫਿਕ ਦੀ ਨਿਗਰਾਨੀ ਕਰ ਸਕਦਾ ਹੈ। ਵੇਰਵਿਆਂ ਲਈ ਟੈਪ ਕਰੋ।"</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"ਐਪਾਂ ਤੁਹਾਡੇ ਟਿਕਾਣੇ ਤੱਕ ਪਹੁੰਚ ਕਰ ਸਕਦੀਆਂ ਹਨ"</string> @@ -2198,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad ਦਾ ਖੱਬੇ ਪਾਸੇ ਵਾਲਾ ਬਟਨ"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad ਦਾ ਸੱਜੇ ਪਾਸੇ ਵਾਲਾ ਬਟਨ"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad ਦਾ ਵਿਚਕਾਰਲਾ ਬਟਨ"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਦੀ ਸੁਰਖੀ ਪੱਟੀ।"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ਨੂੰ ਪ੍ਰਤਿਬੰਧਿਤ ਖਾਨੇ ਵਿੱਚ ਪਾਇਆ ਗਿਆ ਹੈ"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"ਚਿੱਤਰ ਭੇਜਿਆ ਗਿਆ"</string> diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index fc098743c9d0..ec5fee76d73d 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -203,10 +203,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Twój profil służbowy nie jest już dostępny na tym urządzeniu"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Zbyt wiele prób podania hasła"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"Administrator odstąpił urządzenie do użytku osobistego"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"Przestrzeń prywatna została usunięta"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"Twoja organizacja nie zezwala na przestrzenie prywatne na tym urządzeniu zarządzanym."</string> <string name="network_logging_notification_title" msgid="554983187553845004">"Urządzenie jest zarządzane"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"Twoja organizacja zarządza tym urządzeniem i może monitorować ruch w sieci. Kliknij, by dowiedzieć się więcej."</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"Aplikacje mogą mieć dostęp do Twojej lokalizacji"</string> @@ -2200,7 +2198,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad – w lewo"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad – w prawo"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad – środek"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Pasek napisów w aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Umieszczono pakiet <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> w zasobniku danych RESTRICTED"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"wysłano obraz"</string> diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml index 2f666a64812c..7067a89b2621 100644 --- a/core/res/res/values-pt-rBR/strings.xml +++ b/core/res/res/values-pt-rBR/strings.xml @@ -2197,7 +2197,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Botão direcional: para a esquerda"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Botão direcional: para a direita"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Botão direcional: centro"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra de legendas do app <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> foi colocado no intervalo \"RESTRITO\""</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"enviou uma imagem"</string> diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index 9c9fb8d0999c..6632f85b30fd 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -2197,7 +2197,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Teclado direcional: para a esquerda"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Teclado direcional: para a direita"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Teclado direcional: centrar"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra de legendas da app <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> foi colocado no contentor RESTRITO."</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"enviou uma imagem"</string> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index 2f666a64812c..7067a89b2621 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -2197,7 +2197,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Botão direcional: para a esquerda"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Botão direcional: para a direita"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Botão direcional: centro"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra de legendas do app <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> foi colocado no intervalo \"RESTRITO\""</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"enviou uma imagem"</string> diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index 76d69d2e64d9..bf82cd8cb5b7 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -202,10 +202,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Profilul de serviciu nu mai este disponibil pe acest dispozitiv"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Prea multe încercări de introducere a parolei"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"Administratorul a retras dispozitivul pentru uz personal"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"Spațiul privat a fost eliminat"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"Organizația ta nu permite spațiile private pe acest dispozitiv gestionat."</string> <string name="network_logging_notification_title" msgid="554983187553845004">"Dispozitivul este gestionat"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"Organizația ta gestionează acest dispozitiv și poate monitoriza traficul în rețea. Atinge pentru mai multe detalii."</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"Aplicațiile îți pot accesa locația"</string> @@ -2199,7 +2197,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad stânga"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad dreapta"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad centru"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Bară cu legenda pentru <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> a fost adăugat la grupul RESTRICȚIONATE"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"a trimis o imagine"</string> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index b21a13c5b359..c1900a86487a 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -203,10 +203,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Ваш рабочий профиль больше не доступен на этом устройстве"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Слишком много попыток ввести пароль."</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"Администратор освободил устройство для личного использования"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"Частное пространство удалено"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"Ваша организация запрещает использовать частное пространство на этом управляемом устройстве."</string> <string name="network_logging_notification_title" msgid="554983187553845004">"Это управляемое устройство"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"Ваша организация управляет этим устройством и может отслеживать сетевой трафик. Подробнее…"</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"У приложений есть доступ к вашим геоданным"</string> @@ -2200,14 +2198,13 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"D-pad – влево"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"D-pad – вправо"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"D-pad – по центру"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Строка субтитров в приложении \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Приложение \"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>\" помещено в категорию с ограниченным доступом."</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"Отправлено изображение"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Чат"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Групповой чат"</string> <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> - <string name="resolver_personal_tab" msgid="2051260504014442073">"Личное"</string> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Личный"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Рабочее"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Просмотр личных данных"</string> <string name="resolver_work_tab_accessibility" msgid="4753168230363802734">"Просмотр рабочих данных"</string> diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml index 11e8d0e5109c..f216ce2da9fe 100644 --- a/core/res/res/values-si/strings.xml +++ b/core/res/res/values-si/strings.xml @@ -201,10 +201,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"ඔබේ කාර්යාල පැතිකඩ මෙම උපාංගය මත තවදුරටත් ලබා ගැනීමට නොහැකිය"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"මුරපද උත්සාහ කිරීම් ඉතා වැඩි ගණනකි"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"පරිපාලක පුද්ගලික භාවිතය සඳහා උපාංගය අත්හැර දමන ලදී"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"පුද්ගලික ඉඩ ඉවත් කරන ලදි"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"ඔබේ සංවිධානය මෙම කළමනා කෙරෙන උපාංගය මත පුද්ගලික ඉඩවලට ඉඩ නොදෙයි."</string> <string name="network_logging_notification_title" msgid="554983187553845004">"උපාංගය කළමනාකරණය කෙරේ"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"ඔබගේ ආයතනය මෙම උපාංගය කළමනාකරණය කරන අතර එය ජාල තදබදය නිරීක්ෂණය කළ හැක. විස්තර සඳහා තට්ටු කරන්න."</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"යෙදුම්වලට ඔබේ ස්ථානයට ප්රවේශ විය හැකිය"</string> @@ -2198,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad වම"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad දකුණ"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad මැද"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> හි සිරස්තල තීරුව."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> අවහිර කළ බාල්දියට දමා ඇත"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"රූපයක් එව්වා"</string> diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index 39fee349b781..9c2a87537a4b 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -203,10 +203,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Váš pracovný profil už v tomto zariadení nie je k dispozícii"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Príliš veľa pokusov o zadanie hesla"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"Správca uvoľnil toto zariadenie na osobné používanie"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"Súkromný priestor bol odstránený"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"Vaša organizácia nepovoľuje súkromné priestory v tomto spravovanom zariadení."</string> <string name="network_logging_notification_title" msgid="554983187553845004">"Zariadenie je spravované"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"Vaša organizácia spravuje toto zariadenie a môže sledovať sieťovú premávku. Klepnutím zobrazíte podrobnosti."</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"Aplikácie majú prístup k vašej polohe"</string> @@ -2200,7 +2198,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Stlačiť tlačidlo doľava krížového ovládača"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Stlačiť tlačidlo doprava krížového ovládača"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Stlačiť stredné tlačidlo krížového ovládača"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Popis aplikácie <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Balík <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> bol vložený do kontajnera OBMEDZENÉ"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"odoslal(a) obrázok"</string> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index ee37cb8879da..b3530e716b2f 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -2198,7 +2198,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Smerni gumb levo"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Smerni gumb desno"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Smerni gumb sredina"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Vrstica s podnapisi aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Paket <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> je bil dodan v segment OMEJENO"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"je poslal(-a) sliko"</string> diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml index 1d097155889a..5f9a6425e208 100644 --- a/core/res/res/values-sq/strings.xml +++ b/core/res/res/values-sq/strings.xml @@ -2198,7 +2198,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Majtas në bllokun e drejtimit"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Djathtas në bllokun e drejtimit"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Qendra e bllokut të drejtimit"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Shiriti i nëntitullit të <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> është vendosur në grupin E KUFIZUAR"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"dërgoi një imazh"</string> @@ -2399,7 +2398,7 @@ <string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Struktura e tastierës u caktua në: <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… Trokit për ta ndryshuar."</string> <string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Tastierat fizike u konfiguruan"</string> <string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Trokit për të parë tastierat"</string> - <string name="profile_label_private" msgid="6463418670715290696">"Privat"</string> + <string name="profile_label_private" msgid="6463418670715290696">"Private"</string> <string name="profile_label_clone" msgid="769106052210954285">"Klon"</string> <string name="profile_label_work" msgid="3495359133038584618">"Puna"</string> <string name="profile_label_work_2" msgid="4691533661598632135">"Puna 2"</string> diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml index a610344f6cb0..301fe244bbf1 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -202,10 +202,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Пословни профил више није доступан на овом уређају"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Превише покушаја уноса лозинке"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"Администратор је уступио уређај за личну употребу"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"Приватан простор је уклоњен"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"Организација не дозвољава приватне просторе на овом управљаном уређају."</string> <string name="network_logging_notification_title" msgid="554983187553845004">"Уређајем се управља"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"Организација управља овим уређајем и може да надгледа мрежни саобраћај. Додирните за детаље."</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"Апликације могу да приступају вашој локацији"</string> @@ -2199,7 +2197,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"налево на D-pad-у"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"надесно на D-pad-у"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"центар на D-pad-у"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Трака са насловима апликације <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Пакет <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> је додат у сегмент ОГРАНИЧЕНО"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"је послао/ла слику"</string> diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index 9cc174c9ef63..b3c2063a6df7 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -201,10 +201,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Jobbprofilen är inte längre tillgänglig på enheten"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"För många försök med lösenord"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"Administratören tillåter inte längre privat bruk av enheten"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"Privat område har tagits bort"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"Din organisation tillåter inte privata områden på den här hanterade enheten."</string> <string name="network_logging_notification_title" msgid="554983187553845004">"Enheten hanteras"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"Organisationen hanterar den här enheten och kan övervaka nätverkstrafiken. Tryck om du vill veta mer."</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"Appar har åtkomst till din plats"</string> @@ -2198,14 +2196,13 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Styrkors, vänster"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Styrkors, höger"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Styrkors, mitten"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Textningsfält för <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> har placerats i hinken RESTRICTED"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"har skickat en bild"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Konversation"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Gruppkonversation"</string> <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> - <string name="resolver_personal_tab" msgid="2051260504014442073">"Privat"</string> + <string name="resolver_personal_tab" msgid="2051260504014442073">"Personlig"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Jobb"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Personlig vy"</string> <string name="resolver_work_tab_accessibility" msgid="4753168230363802734">"Jobbvy"</string> diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index d1bd775e44cb..f15796e5241b 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -201,10 +201,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Wasifu wako wa kazini haupatikani tena kwenye kifaa hiki"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Umejaribu kuweka nenosiri mara nyingi mno"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"Msimamizi aliacha kutumia kifaa kwa matumizi ya binafsi"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"Sehemu ya faragha imeondolewa"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"Shirika lako haliruhusu sehemu za faragha kwenye kifaa hiki kinachodhibitiwa."</string> <string name="network_logging_notification_title" msgid="554983187553845004">"Kifaa kinadhibitiwa"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"Shirika lako linadhibiti kifaa hiki na huenda likafuatilia shughuli kwenye mtandao. Gusa ili upate maelezo zaidi."</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"Programu zinaweza kutambua mahali ulipo"</string> @@ -2198,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Kitufe cha kushoto cha Dpad"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Kitufe cha kulia cha Dpad"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Kitufe cha katikati cha Dpad"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Upau wa manukuu wa <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> kimewekwa katika kikundi KILICHODHIBITIWA"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"alituma picha"</string> diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml index 947903373da9..f615965b721b 100644 --- a/core/res/res/values-ta/strings.xml +++ b/core/res/res/values-ta/strings.xml @@ -201,10 +201,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"இந்தச் சாதனத்தில் இனி பணிக் கணக்கு கிடைக்காது"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"கடவுச்சொல்லை அதிக முறை தவறாக முயற்சித்துவிட்டீர்கள்"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"நிர்வாகியால் தனிப்பட்ட உபயோகத்திற்காக ஒதுக்கப்பட்ட சாதனம்"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"ரகசிய இடம் அகற்றப்பட்டது"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"இந்த நிர்வகிக்கப்படும் சாதனத்தில் ரகசிய இடங்களை உங்கள் நிறுவனம் அனுமதிப்பதில்லை."</string> <string name="network_logging_notification_title" msgid="554983187553845004">"சாதனம் நிர்வகிக்கப்படுகிறது"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"உங்கள் நிறுவனம் இந்தச் சாதனத்தை நிர்வகிக்கும், அத்துடன் அது நெட்வொர்க் ட்ராஃபிக்கைக் கண்காணிக்கலாம். விவரங்களுக்கு, தட்டவும்."</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"ஆப்ஸ் உங்கள் இருப்பிடத்தை அணுக முடியும்"</string> @@ -2198,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"இடது திசை காட்டும் பட்டன்"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"வலது திசை காட்டும் பட்டன்"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"மையப் பகுதியைக் காட்டும் பட்டன்"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸின் தலைப்புப் பட்டி."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> என்பதை வரம்பிடப்பட்ட பக்கெட்திற்குள் சேர்க்கப்பட்டது"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"படம் அனுப்பப்பட்டது"</string> diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml index 05b23d5064f0..a84f6eb13d7e 100644 --- a/core/res/res/values-te/strings.xml +++ b/core/res/res/values-te/strings.xml @@ -201,10 +201,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"ఈ పరికరంలో మీ కార్యాలయ ప్రొఫైల్ ఇప్పుడు అందుబాటులో లేదు"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"చాలా ఎక్కువ పాస్వర్డ్ ప్రయత్నాలు చేశారు"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"వ్యక్తిగత వినియోగం కోసం నిర్వాహకులు పరికరాన్ని తీసి వేశారు"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"ప్రైవేట్ స్పేస్ తీసివేయబడింది"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"మీ సంస్థ ఈ మేనేజ్ చేసే పరికరంలో ప్రైవేట్ స్పేస్లను అనుమతించదు."</string> <string name="network_logging_notification_title" msgid="554983187553845004">"పరికరం నిర్వహించబడింది"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"మీ సంస్థ ఈ పరికరాన్ని నిర్వహిస్తుంది మరియు నెట్వర్క్ ట్రాఫిక్ని పర్యవేక్షించవచ్చు. వివరాల కోసం నొక్కండి."</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"యాప్లు మీ లొకేషన్ను యాక్సెస్ చేయగలవు"</string> @@ -2198,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad ఎడమవైపున"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad కుడివైపున"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"DPad మధ్యన"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> క్యాప్షన్ బార్."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> పరిమితం చేయబడిన బకెట్లో ఉంచబడింది"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"ఇమేజ్ను పంపారు"</string> diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml index aa9d77d1e66f..e34b526ba940 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/strings.xml @@ -201,10 +201,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"โปรไฟล์งานของคุณไม่สามารถใช้ในอุปกรณ์นี้อีกต่อไป"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"พยายามป้อนรหัสผ่านหลายครั้งเกินไป"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"ผู้ดูแลระบบปล่อยอุปกรณ์ให้คุณใช้งานส่วนตัว"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"นำพื้นที่ส่วนตัวออกแล้ว"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"องค์กรของคุณไม่อนุญาตให้มีพื้นที่ส่วนตัวในอุปกรณ์ที่มีการจัดการเครื่องนี้"</string> <string name="network_logging_notification_title" msgid="554983187553845004">"อุปกรณ์มีการจัดการ"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"องค์กรของคุณจัดการอุปกรณ์นี้และอาจตรวจสอบการจราจรของข้อมูลในเครือข่าย แตะเพื่อดูรายละเอียด"</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"แอปจะเข้าถึงตำแหน่งของคุณได้"</string> @@ -2198,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad ซ้าย"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad ขวา"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad กึ่งกลาง"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"แถบคำบรรยาย <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"ใส่ <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ในที่เก็บข้อมูลที่ถูกจำกัดแล้ว"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"ส่งรูปภาพ"</string> diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml index 6b4be2977e79..4288460e6e97 100644 --- a/core/res/res/values-tl/strings.xml +++ b/core/res/res/values-tl/strings.xml @@ -2196,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad Left"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad Right"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad Center"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Caption bar ng <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Inilagay ang <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> sa PINAGHIHIGPITANG bucket"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"nagpadala ng larawan"</string> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index 96780a0de553..906ccbc2ddc7 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -201,10 +201,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"İş profiliniz arık bu cihazda kullanılamıyor"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Çok fazla şifre denemesi yapıldı"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"Yönetici, cihazı kişisel kullanım için serbest bıraktı"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"Özel alan kaldırıldı"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"Kuruluşunuz bu yönetilen cihazda özel alan kullanılmasına izin vermiyor."</string> <string name="network_logging_notification_title" msgid="554983187553845004">"Cihaz yönetiliyor"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"Kuruluşunuz bu cihazı yönetmekte olup ağ trafiğini izleyebilir. Ayrıntılar için dokunun."</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"Uygulamalar konumunuza erişebilir"</string> @@ -2198,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad Sol"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad Sağ"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad Orta"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> uygulamasının başlık çubuğu."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> KISITLANMIŞ gruba yerleştirildi"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"bir resim gönderildi"</string> @@ -2399,7 +2396,7 @@ <string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Klavye düzeni <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g> olarak ayarlandı… Değiştirmek için dokunun."</string> <string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Fiziksel klavyeler yapılandırıldı"</string> <string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Klavyeleri görüntülemek için dokunun"</string> - <string name="profile_label_private" msgid="6463418670715290696">"Gizli"</string> + <string name="profile_label_private" msgid="6463418670715290696">"Özel"</string> <string name="profile_label_clone" msgid="769106052210954285">"Klon"</string> <string name="profile_label_work" msgid="3495359133038584618">"İş"</string> <string name="profile_label_work_2" msgid="4691533661598632135">"İş 2"</string> diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml index a64c9904089a..cc9df2e09efc 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -203,10 +203,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Робочий профіль більше не доступний на цьому пристрої"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Забагато спроб ввести пароль"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"Адміністратор не дозволив використовувати пристрій для особистих потреб"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"Приватний простір видалено"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"Ваша організація не дозволяє мати приватні простори на цьому керованому пристрої."</string> <string name="network_logging_notification_title" msgid="554983187553845004">"Пристрій контролюється"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"Адміністратор вашої організації контролює цей пристрій і відстежує мережевий трафік. Торкніться, щоб дізнатися більше."</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"Додаток має доступ до геоданих"</string> @@ -2200,7 +2198,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Кнопка \"вліво\" панелі керування"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Кнопка \"вправо\" панелі керування"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Центральна кнопка панелі керування"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Смуга із субтитрами для додатка <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Пакет \"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>\" додано в сегмент з обмеженнями"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"надіслано зображення"</string> diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml index 0436022cd1b3..c0be641c84c7 100644 --- a/core/res/res/values-ur/strings.xml +++ b/core/res/res/values-ur/strings.xml @@ -201,10 +201,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"آپ کا دفتری پروفائل اس آلہ پر مزید دستیاب نہیں ہے"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"پاس ورڈ کی بہت ساری کوششیں"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"منتظم نے ذاتی استعمال کے لیے آلہ کو دستبردار کیا ہے"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"پرائیویٹ اسپیس کو ہٹا دیا گیا"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"آپ کی تنظیم اس زیر انتظام آلے پر پرائیویٹ اسپیسز کو اجازت نہیں دیتی ہے۔"</string> <string name="network_logging_notification_title" msgid="554983187553845004">"آلہ زیر انتظام ہے"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"آپ کی تنظیم اس آلے کا نظم کرتی ہے اور وہ نیٹ ورک ٹریفک کی نگرانی کر سکتی ہے۔ تفاصیل کیلئے تھپتھپائیں۔"</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"ایپس آپ کے مقام تک رسائی حاصل کر سکتی ہیں"</string> @@ -2198,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad بائیں کریں"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad دائیں کریں"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad سینٹر"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> کی کیپشن بار۔"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> کو پابند کردہ بکٹ میں رکھ دیا گیا ہے"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"ایک تصویر بھیجی"</string> diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml index e5a45da93e83..517176b33a02 100644 --- a/core/res/res/values-uz/strings.xml +++ b/core/res/res/values-uz/strings.xml @@ -2196,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad – chapga"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad – oʻngga"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad – markazga"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> taglavhalar paneli."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> cheklangan turkumga joylandi"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"rasm yuborildi"</string> diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml index 6047ea7dee23..e6db9dd4c680 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -2196,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Chuyển sang trái bằng bàn phím di chuyển"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Chuyển sang phải bằng bàn phím di chuyển"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Căn giữa bằng bàn phím di chuyển"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Thanh phụ đề của <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Đã đưa <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> vào bộ chứa BỊ HẠN CHẾ"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"đã gửi hình ảnh"</string> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index 2503bf60f51b..4b0494004dd7 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -201,10 +201,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"您的工作资料已不在此设备上"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"密码尝试次数过多"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"管理员已将该设备开放给个人使用"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"私密空间已移除"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"贵组织不允许在此受管设备上使用私密空间。"</string> <string name="network_logging_notification_title" msgid="554983187553845004">"设备为受管理设备"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"贵单位会管理该设备,且可能会监控网络流量。点按即可了解详情。"</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"应用可以访问您的位置信息"</string> @@ -2198,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"向左方向键"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"向右方向键"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"方向键中心"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>的标题栏。"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> 已被放入受限存储分区"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"发送了一张图片"</string> diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml index 71131460e656..1aa9c72c8cb9 100644 --- a/core/res/res/values-zh-rHK/strings.xml +++ b/core/res/res/values-zh-rHK/strings.xml @@ -2196,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"十字鍵向左鍵"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"十字鍵向右鍵"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"十字鍵中心鍵"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」的說明列。"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> 已納入受限制的儲存區"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"已傳送圖片"</string> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index 94a5d11e7710..1c83ee6d7465 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -2196,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Dpad 向左移"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Dpad 向右移"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad 置中"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」的說明文字列。"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"已將「<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>」移入受限制的值區"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"傳送了一張圖片"</string> diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml index bbf844e6de95..23754425047b 100644 --- a/core/res/res/values-zu/strings.xml +++ b/core/res/res/values-zu/strings.xml @@ -201,10 +201,8 @@ <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Iphrofayela yakho yomsebenzi ayisatholakali kule divayisi"</string> <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Imizamo yamaphasiwedi eminingi kakhulu"</string> <string name="device_ownership_relinquished" msgid="4080886992183195724">"Umphathi udedela idivayisi ngokusetshenziswa komuntu siqu"</string> - <!-- no translation found for private_space_deleted_by_admin (1484365588862066939) --> - <skip /> - <!-- no translation found for private_space_deleted_by_admin_details (7007781735201818689) --> - <skip /> + <string name="private_space_deleted_by_admin" msgid="1484365588862066939">"Indawo engasese isusiwe"</string> + <string name="private_space_deleted_by_admin_details" msgid="7007781735201818689">"Inhlangano yakho ayivumeli izindawo zangasese kule divayisi ephethwe."</string> <string name="network_logging_notification_title" msgid="554983187553845004">"Idivayisi iphethwe"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"Inhlangano yakho iphethe le divayisi futhi kungenzeka ingaqaphi ithrafikhi yenethiwekhi. Thephela imininingwane."</string> <string name="location_changed_notification_title" msgid="3620158742816699316">"Izinhlelo zokusebenza zingakwazi ukufinyelela endaweni yakho"</string> @@ -2198,7 +2196,6 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Ngakwesokunxele se-Dpad"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Ngakwesokudla se-Dpad"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Isikhungo se-Dpad"</string> - <string name="accessibility_freeform_caption" msgid="8377519323496290122">"Ibha yamazwibela we-<xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"I-<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ifakwe kubhakede LOKUKHAWULELWE"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_single_line_image_placeholder" msgid="6983271082911936900">"uthumele isithombe"</string> diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml index 04f6f5214e74..dcda5d8669a4 100644 --- a/core/res/res/values/config_telephony.xml +++ b/core/res/res/values/config_telephony.xml @@ -403,4 +403,10 @@ <integer name="config_wait_for_datagram_sending_response_for_last_message_timeout_millis">60000</integer> <java-symbol type="integer" name="config_wait_for_datagram_sending_response_for_last_message_timeout_millis" /> + <!-- Boolean indicating whether Telephony should force PhoneGlobals creation + regardless of FEATURE_TELEPHONY presence. + --> + <bool name="config_force_phone_globals_creation">false</bool> + <java-symbol type="bool" name="config_force_phone_globals_creation" /> + </resources> diff --git a/core/tests/coretests/src/android/database/sqlite/SQLiteRawStatementTest.java b/core/tests/coretests/src/android/database/sqlite/SQLiteRawStatementTest.java index 548b8ec3f6de..8071d3dff619 100644 --- a/core/tests/coretests/src/android/database/sqlite/SQLiteRawStatementTest.java +++ b/core/tests/coretests/src/android/database/sqlite/SQLiteRawStatementTest.java @@ -19,6 +19,7 @@ package android.database.sqlite; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -507,6 +508,12 @@ public class SQLiteRawStatementTest { s.bindInt(1, 3); s.step(); s.reset(); + // Bind a zero-length blob + s.clearBindings(); + s.bindInt(1, 4); + s.bindBlob(2, new byte[0]); + s.step(); + s.reset(); } mDatabase.setTransactionSuccessful(); } finally { @@ -545,6 +552,17 @@ public class SQLiteRawStatementTest { for (int i = 0; i < c.length; i++) c[i] = 0; s.bindInt(1, 3); assertTrue(s.step()); + assertNull(s.getColumnBlob(0)); + assertEquals(0, s.readColumnBlob(0, c, 0, c.length, 0)); + for (int i = 0; i < c.length; i++) assertEquals(0, c[i]); + s.reset(); + + // Fetch the zero-length blob + s.bindInt(1, 4); + assertTrue(s.step()); + byte[] r = s.getColumnBlob(0); + assertNotNull(r); + assertEquals(0, r.length); assertEquals(0, s.readColumnBlob(0, c, 0, c.length, 0)); for (int i = 0; i < c.length; i++) assertEquals(0, c[i]); s.reset(); @@ -572,6 +590,83 @@ public class SQLiteRawStatementTest { } @Test + public void testText() { + mDatabase.beginTransaction(); + try { + final String query = "CREATE TABLE t1 (i int, b text)"; + try (SQLiteRawStatement s = mDatabase.createRawStatement(query)) { + assertFalse(s.step()); + } + mDatabase.setTransactionSuccessful(); + } finally { + mDatabase.endTransaction(); + } + + // Insert data into the table. + mDatabase.beginTransaction(); + try { + final String query = "INSERT INTO t1 (i, b) VALUES (?1, ?2)"; + try (SQLiteRawStatement s = mDatabase.createRawStatement(query)) { + // Bind a string + s.bindInt(1, 1); + s.bindText(2, "text"); + s.step(); + s.reset(); + s.clearBindings(); + + // Bind a zero-length string + s.bindInt(1, 2); + s.bindText(2, ""); + s.step(); + s.reset(); + s.clearBindings(); + + // Bind a null string + s.clearBindings(); + s.bindInt(1, 3); + s.step(); + s.reset(); + s.clearBindings(); + } + mDatabase.setTransactionSuccessful(); + } finally { + mDatabase.endTransaction(); + } + + // Read back data and verify it against the reference copy. + mDatabase.beginTransactionReadOnly(); + try { + final String query = "SELECT (b) FROM t1 WHERE i = ?1"; + try (SQLiteRawStatement s = mDatabase.createRawStatement(query)) { + // Fetch the entire reference array. + s.bindInt(1, 1); + assertTrue(s.step()); + assertEquals(SQLiteRawStatement.SQLITE_DATA_TYPE_TEXT, s.getColumnType(0)); + + String a = s.getColumnText(0); + assertNotNull(a); + assertEquals(a, "text"); + s.reset(); + + s.bindInt(1, 2); + assertTrue(s.step()); + String b = s.getColumnText(0); + assertNotNull(b); + assertEquals(b, ""); + s.reset(); + + s.bindInt(1, 3); + assertTrue(s.step()); + String c = s.getColumnText(0); + assertNull(c); + s.reset(); + } + } finally { + mDatabase.endTransaction(); + } + } + + @Test public void testParameterMetadata() { createComplexDatabase(); diff --git a/core/tests/coretests/src/android/view/ViewFrameRateTest.java b/core/tests/coretests/src/android/view/ViewFrameRateTest.java index 0b1b40c8ba8b..07446e7617aa 100644 --- a/core/tests/coretests/src/android/view/ViewFrameRateTest.java +++ b/core/tests/coretests/src/android/view/ViewFrameRateTest.java @@ -41,11 +41,13 @@ import android.app.Instrumentation; import android.os.Handler; import android.os.Looper; import android.os.SystemClock; +import android.platform.test.annotations.LargeTest; import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.CheckFlagsRule; import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.util.DisplayMetrics; import android.widget.FrameLayout; +import android.widget.ProgressBar; import androidx.test.annotation.UiThreadTest; import androidx.test.filters.SmallTest; @@ -623,6 +625,162 @@ public class ViewFrameRateTest { assertEquals(FRAME_RATE_CATEGORY_HIGH_HINT, mViewRoot.getLastPreferredFrameRateCategory()); } + @LargeTest + @Test + @RequiresFlagsEnabled({FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY, + FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY, + com.android.graphics.surfaceflinger.flags.Flags.FLAG_VRR_BUGFIX_24Q4 + }) + public void idleDetected() throws Throwable { + waitForFrameRateCategoryToSettle(); + mActivityRule.runOnUiThread(() -> { + mMovingView.setRequestedFrameRate(View.REQUESTED_FRAME_RATE_CATEGORY_HIGH); + mMovingView.setFrameContentVelocity(Float.MAX_VALUE); + mMovingView.invalidate(); + runAfterDraw(() -> assertEquals(FRAME_RATE_CATEGORY_HIGH, + mViewRoot.getLastPreferredFrameRateCategory())); + }); + waitForAfterDraw(); + + // Wait for idle timeout + Thread.sleep(1000); + assertEquals(0f, mViewRoot.getLastPreferredFrameRate()); + assertEquals(FRAME_RATE_CATEGORY_NO_PREFERENCE, + mViewRoot.getLastPreferredFrameRateCategory()); + } + + @LargeTest + @Test + @RequiresFlagsEnabled({FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY, + FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY, + com.android.graphics.surfaceflinger.flags.Flags.FLAG_VRR_BUGFIX_24Q4 + }) + public void vectorDrawableFrameRate() throws Throwable { + final ProgressBar[] progressBars = new ProgressBar[3]; + final ViewGroup[] parents = new ViewGroup[1]; + mActivityRule.runOnUiThread(() -> { + ViewGroup parent = (ViewGroup) mMovingView.getParent(); + parents[0] = parent; + ProgressBar progressBar1 = new ProgressBar(mActivity); + parent.addView(progressBar1); + progressBar1.setRequestedFrameRate(View.REQUESTED_FRAME_RATE_CATEGORY_LOW); + progressBar1.setIndeterminate(true); + progressBars[0] = progressBar1; + + ProgressBar progressBar2 = new ProgressBar(mActivity); + parent.addView(progressBar2); + progressBar2.setRequestedFrameRate(View.REQUESTED_FRAME_RATE_CATEGORY_NORMAL); + progressBar2.setIndeterminate(true); + progressBars[1] = progressBar2; + + ProgressBar progressBar3 = new ProgressBar(mActivity); + parent.addView(progressBar3); + progressBar3.setRequestedFrameRate(45f); + progressBar3.setIndeterminate(true); + progressBars[2] = progressBar3; + }); + waitForFrameRateCategoryToSettle(); + + // Wait for idle timeout + Thread.sleep(1000); + assertEquals(45f, mViewRoot.getLastPreferredFrameRate()); + assertEquals(FRAME_RATE_CATEGORY_NORMAL, mViewRoot.getLastPreferredFrameRateCategory()); + + // Removing the vector drawable with NORMAL should drop the category to LOW + mActivityRule.runOnUiThread(() -> parents[0].removeView(progressBars[1])); + Thread.sleep(1000); + assertEquals(45f, mViewRoot.getLastPreferredFrameRate()); + assertEquals(FRAME_RATE_CATEGORY_LOW, + mViewRoot.getLastPreferredFrameRateCategory()); + // Removing the one voting for frame rate should leave only the category + mActivityRule.runOnUiThread(() -> parents[0].removeView(progressBars[2])); + Thread.sleep(1000); + assertEquals(0f, mViewRoot.getLastPreferredFrameRate()); + assertEquals(FRAME_RATE_CATEGORY_LOW, + mViewRoot.getLastPreferredFrameRateCategory()); + // Removing the last one should leave it with no preference + mActivityRule.runOnUiThread(() -> parents[0].removeView(progressBars[0])); + Thread.sleep(1000); + assertEquals(0f, mViewRoot.getLastPreferredFrameRate()); + assertEquals(FRAME_RATE_CATEGORY_NO_PREFERENCE, + mViewRoot.getLastPreferredFrameRateCategory()); + } + + @LargeTest + @Test + @RequiresFlagsEnabled({FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY, + FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY, + com.android.graphics.surfaceflinger.flags.Flags.FLAG_VRR_BUGFIX_24Q4 + }) + public void renderNodeAnimatorFrameRateCanceled() throws Throwable { + mMovingView.setRequestedFrameRate(View.REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE); + waitForFrameRateCategoryToSettle(); + + RenderNodeAnimator[] renderNodeAnimator = new RenderNodeAnimator[1]; + renderNodeAnimator[0] = new RenderNodeAnimator(RenderNodeAnimator.ALPHA, 0f); + renderNodeAnimator[0].setDuration(100000); + + mActivityRule.runOnUiThread(() -> { + renderNodeAnimator[0].setTarget(mMovingView); + renderNodeAnimator[0].start(); + mMovingView.setRequestedFrameRate(View.REQUESTED_FRAME_RATE_CATEGORY_LOW); + runAfterDraw(() -> { + assertEquals(0f, mViewRoot.getLastPreferredFrameRate()); + assertEquals(FRAME_RATE_CATEGORY_LOW, + mViewRoot.getLastPreferredFrameRateCategory()); + }); + }); + waitForAfterDraw(); + + mActivityRule.runOnUiThread(() -> { + renderNodeAnimator[0].cancel(); + }); + + // Wait for idle timeout + Thread.sleep(1000); + assertEquals(0f, mViewRoot.getLastPreferredFrameRate()); + assertEquals(FRAME_RATE_CATEGORY_NO_PREFERENCE, + mViewRoot.getLastPreferredFrameRateCategory()); + } + + @LargeTest + @Test + @RequiresFlagsEnabled({FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY, + FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY, + com.android.graphics.surfaceflinger.flags.Flags.FLAG_VRR_BUGFIX_24Q4 + }) + public void renderNodeAnimatorFrameRateRemoved() throws Throwable { + mMovingView.setRequestedFrameRate(View.REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE); + waitForFrameRateCategoryToSettle(); + + RenderNodeAnimator[] renderNodeAnimator = new RenderNodeAnimator[1]; + renderNodeAnimator[0] = new RenderNodeAnimator(RenderNodeAnimator.ALPHA, 0f); + renderNodeAnimator[0].setDuration(100000); + + mActivityRule.runOnUiThread(() -> { + renderNodeAnimator[0].setTarget(mMovingView); + renderNodeAnimator[0].start(); + mMovingView.setRequestedFrameRate(View.REQUESTED_FRAME_RATE_CATEGORY_LOW); + runAfterDraw(() -> { + assertEquals(0f, mViewRoot.getLastPreferredFrameRate()); + assertEquals(FRAME_RATE_CATEGORY_LOW, + mViewRoot.getLastPreferredFrameRateCategory()); + }); + }); + waitForAfterDraw(); + + mActivityRule.runOnUiThread(() -> { + ViewGroup parent = (ViewGroup) mMovingView.getParent(); + assert parent != null; + parent.removeView(mMovingView); + }); + + Thread.sleep(1000); + assertEquals(0f, mViewRoot.getLastPreferredFrameRate()); + assertEquals(FRAME_RATE_CATEGORY_NO_PREFERENCE, + mViewRoot.getLastPreferredFrameRateCategory()); + } + private void runAfterDraw(@NonNull Runnable runnable) { Handler handler = new Handler(Looper.getMainLooper()); mAfterDrawLatch = new CountDownLatch(1); diff --git a/data/etc/preinstalled-packages-platform.xml b/data/etc/preinstalled-packages-platform.xml index f9fb84d2b31d..782327713fdc 100644 --- a/data/etc/preinstalled-packages-platform.xml +++ b/data/etc/preinstalled-packages-platform.xml @@ -134,19 +134,4 @@ to pre-existing users, but cannot uninstall pre-existing system packages from pr <install-in-user-type package="com.android.avatarpicker"> <install-in user-type="FULL" /> </install-in-user-type> - - <!-- AiLabs Warp app pre-installed in hardware/google/pixel/common/pixel-common-device.mk --> - <install-in-user-type package="com.google.android.apps.warp"> - <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> - <do-not-install-in user-type="android.os.usertype.profile.PRIVATE" /> - </install-in-user-type> - - <!-- Google Home app pre-installed on tangor devices in vendor/google/products/tangor_common.mk - --> - <install-in-user-type package="com.google.android.apps.chromecast.app"> - <install-in user-type="FULL" /> - <install-in user-type="PROFILE" /> - <do-not-install-in user-type="android.os.usertype.profile.PRIVATE" /> - </install-in-user-type> </config> diff --git a/graphics/java/android/graphics/RenderNode.java b/graphics/java/android/graphics/RenderNode.java index 0650b7817729..211f74a47bdd 100644 --- a/graphics/java/android/graphics/RenderNode.java +++ b/graphics/java/android/graphics/RenderNode.java @@ -16,6 +16,7 @@ package android.graphics; +import android.animation.Animator; import android.annotation.BytesLong; import android.annotation.ColorInt; import android.annotation.FloatRange; @@ -1639,7 +1640,7 @@ public final class RenderNode { */ public interface AnimationHost { /** @hide */ - void registerAnimatingRenderNode(RenderNode animator); + void registerAnimatingRenderNode(RenderNode renderNode, Animator animator); /** @hide */ void registerVectorDrawableAnimator(NativeVectorDrawableAnimator animator); @@ -1654,7 +1655,7 @@ public final class RenderNode { throw new IllegalStateException("Cannot start this animator on a detached view!"); } nAddAnimator(mNativeRenderNode, animator.getNativeAnimator()); - mAnimationHost.registerAnimatingRenderNode(this); + mAnimationHost.registerAnimatingRenderNode(this, animator); } /** @hide */ diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java index 55f205bb14a6..d4bb461c284e 100644 --- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java +++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java @@ -1266,6 +1266,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { private final IntArray mPendingAnimationActions = new IntArray(); private final AnimatedVectorDrawable mDrawable; private long mTotalDuration; + private AnimatorListener mThreadedRendererAnimatorListener; VectorDrawableAnimatorRT(AnimatedVectorDrawable drawable) { mDrawable = drawable; @@ -1689,6 +1690,9 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { if (mListener != null) { mListener.onAnimationStart(null); } + if (mThreadedRendererAnimatorListener != null) { + mThreadedRendererAnimatorListener.onAnimationStart(null); + } } // This should only be called after animator has been added to the RenderNode target. @@ -1717,6 +1721,9 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { if (mListener != null) { mListener.onAnimationStart(null); } + if (mThreadedRendererAnimatorListener != null) { + mThreadedRendererAnimatorListener.onAnimationStart(null); + } } @Override @@ -1725,6 +1732,11 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { } @Override + public void setThreadedRendererAnimatorListener(AnimatorListener animatorListener) { + mThreadedRendererAnimatorListener = animatorListener; + } + + @Override public boolean canReverse() { return mIsReversible; } @@ -1788,6 +1800,9 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { if (mListener != null) { mListener.onAnimationEnd(null); } + if (mThreadedRendererAnimatorListener != null) { + mThreadedRendererAnimatorListener.onAnimationEnd(null); + } } // onFinished: should be called from native diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/DividerPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/DividerPresenter.java index 29936cc2cac3..6b957114c00b 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/DividerPresenter.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/DividerPresenter.java @@ -514,7 +514,12 @@ class DividerPresenter implements View.OnTouchListener { mProperties.mDividerAttributes, mProperties.mIsVerticalSplit, calculateMinPosition(), calculateMaxPosition()); mRenderer.setDividerPosition(mDividerPosition); - switch (event.getAction()) { + + // Convert to use screen-based coordinates to prevent lost track of motion events + // while moving divider bar and calculating dragging velocity. + event.setLocation(event.getRawX(), event.getRawY()); + final int action = event.getAction() & MotionEvent.ACTION_MASK; + switch (action) { case MotionEvent.ACTION_DOWN: onStartDragging(event); break; @@ -713,9 +718,9 @@ class DividerPresenter implements View.OnTouchListener { return snap(dividerPosition, possiblePositions); } if (velocity < 0) { - return 0; + return minPosition; } else { - return fullyExpandedPosition; + return maxPosition; } } diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java index 9aa12aa824df..f78e2b5170fc 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java @@ -1322,7 +1322,9 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen mPresenter.expandTaskFragment(wct, container); } else { // Put activity into a new expanded container. - final TaskFragmentContainer newContainer = newContainer(activity, getTaskId(activity)); + final TaskFragmentContainer newContainer = + new TaskFragmentContainer.Builder(this, getTaskId(activity), activity) + .setPendingAppearedActivity(activity).build(); mPresenter.expandActivity(wct, newContainer.getTaskFragmentToken(), activity); } } @@ -1738,9 +1740,13 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen // Can't find any activity in the Task that we can use as the owner activity. return null; } - final TaskFragmentContainer container = newContainer(null /* pendingAppearedActivity */, - intent, activityInTask, taskId, null /* pairedPrimaryContainer*/, overlayTag, - launchOptions, associateLaunchingActivity); + final TaskFragmentContainer container = + new TaskFragmentContainer.Builder(this, taskId, activityInTask) + .setPendingAppearedIntent(intent) + .setOverlayTag(overlayTag) + .setLaunchOptions(launchOptions) + .setAssociatedActivity(associateLaunchingActivity ? activityInTask : null) + .build(); final IBinder taskFragmentToken = container.getTaskFragmentToken(); // Note that taskContainer will not exist before calling #newContainer if the container // is the first embedded TF in the task. @@ -1818,74 +1824,6 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen return null; } - @GuardedBy("mLock") - TaskFragmentContainer newContainer(@NonNull Activity pendingAppearedActivity, int taskId) { - return newContainer(pendingAppearedActivity, pendingAppearedActivity, taskId); - } - - @GuardedBy("mLock") - TaskFragmentContainer newContainer(@NonNull Activity pendingAppearedActivity, - @NonNull Activity activityInTask, int taskId) { - return newContainer(pendingAppearedActivity, null /* pendingAppearedIntent */, - activityInTask, taskId, null /* pairedPrimaryContainer */, null /* tag */, - null /* launchOptions */, false /* associateLaunchingActivity */); - } - - @GuardedBy("mLock") - TaskFragmentContainer newContainer(@NonNull Intent pendingAppearedIntent, - @NonNull Activity activityInTask, int taskId) { - return newContainer(null /* pendingAppearedActivity */, pendingAppearedIntent, - activityInTask, taskId, null /* pairedPrimaryContainer */, null /* tag */, - null /* launchOptions */, false /* associateLaunchingActivity */); - } - - @GuardedBy("mLock") - TaskFragmentContainer newContainer(@NonNull Intent pendingAppearedIntent, - @NonNull Activity activityInTask, int taskId, - @NonNull TaskFragmentContainer pairedPrimaryContainer) { - return newContainer(null /* pendingAppearedActivity */, pendingAppearedIntent, - activityInTask, taskId, pairedPrimaryContainer, null /* tag */, - null /* launchOptions */, false /* associateLaunchingActivity */); - } - - /** - * Creates and registers a new organized container with an optional activity that will be - * re-parented to it in a WCT. - * - * @param pendingAppearedActivity the activity that will be reparented to the TaskFragment. - * @param pendingAppearedIntent the Intent that will be started in the TaskFragment. - * @param activityInTask activity in the same Task so that we can get the Task bounds - * if needed. - * @param taskId parent Task of the new TaskFragment. - * @param pairedContainer the paired primary {@link TaskFragmentContainer}. When it is - * set, the new container will be added right above it. - * @param overlayTag The tag for the new created overlay container. It must be - * needed if {@code isOverlay} is {@code true}. Otherwise, - * it should be {@code null}. - * @param launchOptions The launch options bundle to create a container. Must be - * specified for overlay container. - * @param associateLaunchingActivity {@code true} to indicate this overlay container - * should associate with launching activity. - */ - @GuardedBy("mLock") - TaskFragmentContainer newContainer(@Nullable Activity pendingAppearedActivity, - @Nullable Intent pendingAppearedIntent, @NonNull Activity activityInTask, int taskId, - @Nullable TaskFragmentContainer pairedContainer, @Nullable String overlayTag, - @Nullable Bundle launchOptions, boolean associateLaunchingActivity) { - if (activityInTask == null) { - throw new IllegalArgumentException("activityInTask must not be null,"); - } - if (!mTaskContainers.contains(taskId)) { - mTaskContainers.put(taskId, new TaskContainer(taskId, activityInTask)); - mDividerPresenters.put(taskId, new DividerPresenter(taskId, this, mExecutor)); - } - final TaskContainer taskContainer = mTaskContainers.get(taskId); - final TaskFragmentContainer container = new TaskFragmentContainer(pendingAppearedActivity, - pendingAppearedIntent, taskContainer, this, pairedContainer, overlayTag, - launchOptions, associateLaunchingActivity ? activityInTask : null); - return container; - } - /** * Creates and registers a new split with the provided containers and configuration. Finishes * existing secondary containers if found for the given primary container. @@ -2581,6 +2519,12 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen return mTaskContainers.get(taskId); } + @GuardedBy("mLock") + void addTaskContainer(int taskId, TaskContainer taskContainer) { + mTaskContainers.put(taskId, taskContainer); + mDividerPresenters.put(taskId, new DividerPresenter(taskId, this, mExecutor)); + } + Handler getHandler() { return mHandler; } diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java index 1cb410e90a76..eade86e50659 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java @@ -186,8 +186,9 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { // Create new empty task fragment final int taskId = primaryContainer.getTaskId(); - final TaskFragmentContainer secondaryContainer = mController.newContainer( - secondaryIntent, primaryActivity, taskId); + final TaskFragmentContainer secondaryContainer = + new TaskFragmentContainer.Builder(mController, taskId, primaryActivity) + .setPendingAppearedIntent(secondaryIntent).build(); final Rect secondaryRelBounds = getRelBoundsForPosition(POSITION_END, taskProperties, splitAttributes); final int windowingMode = mController.getTaskContainer(taskId) @@ -261,7 +262,8 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { TaskFragmentContainer container = mController.getContainerWithActivity(activity); final int taskId = container != null ? container.getTaskId() : activity.getTaskId(); if (container == null || container == containerToAvoid) { - container = mController.newContainer(activity, taskId); + container = new TaskFragmentContainer.Builder(mController, taskId, activity) + .setPendingAppearedActivity(activity).build(); final int windowingMode = mController.getTaskContainer(taskId) .getWindowingModeForTaskFragment(relBounds); final IBinder reparentActivityToken = activity.getActivityToken(); @@ -304,15 +306,19 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { TaskFragmentContainer primaryContainer = mController.getContainerWithActivity( launchingActivity); if (primaryContainer == null) { - primaryContainer = mController.newContainer(launchingActivity, - launchingActivity.getTaskId()); + primaryContainer = new TaskFragmentContainer.Builder(mController, + launchingActivity.getTaskId(), launchingActivity) + .setPendingAppearedActivity(launchingActivity).build(); } final int taskId = primaryContainer.getTaskId(); - final TaskFragmentContainer secondaryContainer = mController.newContainer(activityIntent, - launchingActivity, taskId, - // Pass in the primary container to make sure it is added right above the primary. - primaryContainer); + final TaskFragmentContainer secondaryContainer = + new TaskFragmentContainer.Builder(mController, taskId, launchingActivity) + .setPendingAppearedIntent(activityIntent) + // Pass in the primary container to make sure it is added right above the + // primary. + .setPairedPrimaryContainer(primaryContainer) + .build(); final TaskContainer taskContainer = mController.getTaskContainer(taskId); final int windowingMode = taskContainer.getWindowingModeForTaskFragment( primaryRelBounds); diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java index d0b6a01bb51e..7173b0c95230 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java @@ -195,20 +195,6 @@ class TaskFragmentContainer { private boolean mLastDimOnTask; /** - * @see #TaskFragmentContainer(Activity, Intent, TaskContainer, SplitController, - * TaskFragmentContainer, String, Bundle, Activity) - */ - TaskFragmentContainer(@Nullable Activity pendingAppearedActivity, - @Nullable Intent pendingAppearedIntent, - @NonNull TaskContainer taskContainer, - @NonNull SplitController controller, - @Nullable TaskFragmentContainer pairedPrimaryContainer) { - this(pendingAppearedActivity, pendingAppearedIntent, taskContainer, - controller, pairedPrimaryContainer, null /* overlayTag */, - null /* launchOptions */, null /* associatedActivity */); - } - - /** * Creates a container with an existing activity that will be re-parented to it in a window * container transaction. * @param pairedPrimaryContainer when it is set, the new container will be add right above it @@ -218,7 +204,7 @@ class TaskFragmentContainer { * @param associatedActivity the associated activity of the overlay container. Must be * {@code null} for a non-overlay container. */ - TaskFragmentContainer(@Nullable Activity pendingAppearedActivity, + private TaskFragmentContainer(@Nullable Activity pendingAppearedActivity, @Nullable Intent pendingAppearedIntent, @NonNull TaskContainer taskContainer, @NonNull SplitController controller, @Nullable TaskFragmentContainer pairedPrimaryContainer, @Nullable String overlayTag, @@ -232,12 +218,6 @@ class TaskFragmentContainer { mToken = new Binder("TaskFragmentContainer"); mTaskContainer = taskContainer; mOverlayTag = overlayTag; - if (overlayTag != null) { - Objects.requireNonNull(launchOptions); - } else if (associatedActivity != null) { - throw new IllegalArgumentException("Associated activity must be null for " - + "non-overlay activity."); - } mAssociatedActivityToken = associatedActivity != null ? associatedActivity.getActivityToken() : null; @@ -1116,6 +1096,117 @@ class TaskFragmentContainer { return sb.append("]").toString(); } + static final class Builder { + @NonNull + private final SplitController mSplitController; + + // The parent Task id of the new TaskFragment. + private final int mTaskId; + + // The activity in the same Task so that we can get the Task bounds if needed. + @NonNull + private final Activity mActivityInTask; + + // The activity that will be reparented to the TaskFragment. + @Nullable + private Activity mPendingAppearedActivity; + + // The Intent that will be started in the TaskFragment. + @Nullable + private Intent mPendingAppearedIntent; + + // The paired primary {@link TaskFragmentContainer}. When it is set, the new container + // will be added right above it. + @Nullable + private TaskFragmentContainer mPairedPrimaryContainer; + + // The launch options bundle to create a container. Must be specified for overlay container. + @Nullable + private Bundle mLaunchOptions; + + // The tag for the new created overlay container. This is required when creating an + // overlay container. + @Nullable + private String mOverlayTag; + + // The associated activity of the overlay container. Must be {@code null} for a + // non-overlay container. + @Nullable + private Activity mAssociatedActivity; + + Builder(@NonNull SplitController splitController, int taskId, + @Nullable Activity activityInTask) { + if (taskId <= 0) { + throw new IllegalArgumentException("taskId is invalid, " + taskId); + } + + mSplitController = splitController; + mTaskId = taskId; + mActivityInTask = activityInTask; + } + + @NonNull + Builder setPendingAppearedActivity(@Nullable Activity pendingAppearedActivity) { + mPendingAppearedActivity = pendingAppearedActivity; + return this; + } + + @NonNull + Builder setPendingAppearedIntent(@Nullable Intent pendingAppearedIntent) { + mPendingAppearedIntent = pendingAppearedIntent; + return this; + } + + @NonNull + Builder setPairedPrimaryContainer(@Nullable TaskFragmentContainer pairedPrimaryContainer) { + mPairedPrimaryContainer = pairedPrimaryContainer; + return this; + } + + @NonNull + Builder setLaunchOptions(@Nullable Bundle launchOptions) { + mLaunchOptions = launchOptions; + return this; + } + + @NonNull + Builder setOverlayTag(@Nullable String overlayTag) { + mOverlayTag = overlayTag; + return this; + } + + @NonNull + Builder setAssociatedActivity(@Nullable Activity associatedActivity) { + mAssociatedActivity = associatedActivity; + return this; + } + + @NonNull + TaskFragmentContainer build() { + if (mOverlayTag != null) { + Objects.requireNonNull(mLaunchOptions); + } else if (mAssociatedActivity != null) { + throw new IllegalArgumentException("Associated activity must be null for " + + "non-overlay activity."); + } + + TaskContainer taskContainer = mSplitController.getTaskContainer(mTaskId); + if (taskContainer == null && mActivityInTask == null) { + throw new IllegalArgumentException("mActivityInTask must be set."); + } + + if (taskContainer == null) { + // Adding a TaskContainer if no existed one. + taskContainer = new TaskContainer(mTaskId, mActivityInTask); + mSplitController.addTaskContainer(mTaskId, taskContainer); + } + + return new TaskFragmentContainer(mPendingAppearedActivity, mPendingAppearedIntent, + taskContainer, mSplitController, mPairedPrimaryContainer, mOverlayTag, + mLaunchOptions, mAssociatedActivity); + } + } + static class OverlayContainerRestoreParams { /** The token of the overlay container */ @NonNull diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/DividerPresenterTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/DividerPresenterTest.java index 746607c8094c..20626c79714e 100644 --- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/DividerPresenterTest.java +++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/DividerPresenterTest.java @@ -720,7 +720,7 @@ public class DividerPresenterTest { // Divider position is greater than minPosition and the velocity is enough for fling assertEquals( - 0, // Closed position + 30, // minPosition DividerPresenter.dividerPositionWithDraggingToFullscreenAllowed( 50 /* dividerPosition */, 30 /* minPosition */, @@ -731,7 +731,7 @@ public class DividerPresenterTest { // Divider position is less than maxPosition and the velocity is enough for fling assertEquals( - 1200, // Fully expanded position + 900, // maxPosition DividerPresenter.dividerPositionWithDraggingToFullscreenAllowed( 800 /* dividerPosition */, 30 /* minPosition */, diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/EmbeddingTestUtils.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/EmbeddingTestUtils.java index a069ac7256d6..d649c6d57137 100644 --- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/EmbeddingTestUtils.java +++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/EmbeddingTestUtils.java @@ -248,4 +248,17 @@ public class EmbeddingTestUtils { return new SplitPlaceholderRule.Builder(placeholderIntent, activityPredicate, intentPredicate, windowMetricsPredicate); } + + @NonNull + static TaskFragmentContainer createTfContainer( + @NonNull SplitController splitController, @NonNull Activity activity) { + return createTfContainer(splitController, TASK_ID, activity); + } + + @NonNull + static TaskFragmentContainer createTfContainer( + @NonNull SplitController splitController, int taskId, @NonNull Activity activity) { + return new TaskFragmentContainer.Builder(splitController, taskId, activity) + .setPendingAppearedActivity(activity).build(); + } } diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java index 76e6a0ff2c21..7b473b04548c 100644 --- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java +++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java @@ -25,6 +25,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; @@ -105,8 +106,11 @@ public class JetpackTaskFragmentOrganizerTest { @Test public void testExpandTaskFragment() { final TaskContainer taskContainer = createTestTaskContainer(); - final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */, - new Intent(), taskContainer, mSplitController, null /* pairedPrimaryContainer */); + doReturn(taskContainer).when(mSplitController).getTaskContainer(anyInt()); + final TaskFragmentContainer container = new TaskFragmentContainer.Builder(mSplitController, + taskContainer.getTaskId(), null /* activityInTask */) + .setPendingAppearedIntent(new Intent()) + .build(); final TaskFragmentInfo info = createMockInfo(container); mOrganizer.mFragmentInfos.put(container.getTaskFragmentToken(), info); container.setInfo(mTransaction, info); diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java index 86b7e88a0c1a..0972d40f33e3 100644 --- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java +++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java @@ -29,6 +29,7 @@ import static androidx.window.extensions.embedding.EmbeddingTestUtils.createMock import static androidx.window.extensions.embedding.EmbeddingTestUtils.createSplitPairRuleBuilder; import static androidx.window.extensions.embedding.EmbeddingTestUtils.createSplitPlaceholderRuleBuilder; import static androidx.window.extensions.embedding.EmbeddingTestUtils.createSplitRule; +import static androidx.window.extensions.embedding.EmbeddingTestUtils.createTfContainer; import static androidx.window.extensions.embedding.SplitPresenter.sanitizeBounds; import static androidx.window.extensions.embedding.WindowAttributes.DIM_AREA_ON_TASK; @@ -530,8 +531,8 @@ public class OverlayPresentationTest { @Test public void testUpdateActivityStackAttributes_nullContainer_earlyReturn() { - final TaskFragmentContainer container = mSplitController.newContainer(mActivity, - mActivity.getTaskId()); + final TaskFragmentContainer container = createTfContainer(mSplitController, + mActivity.getTaskId(), mActivity); mSplitController.updateActivityStackAttributes( ActivityStack.Token.createFromBinder(container.getTaskFragmentToken()), new ActivityStackAttributes.Builder().build()); @@ -837,8 +838,9 @@ public class OverlayPresentationTest { final Intent intent = new Intent(); final IBinder fillTaskActivityToken = new Binder(); final IBinder lastOverlayToken = new Binder(); - final TaskFragmentContainer overlayContainer = mSplitController.newContainer(intent, - mActivity, TASK_ID); + final TaskFragmentContainer overlayContainer = + new TaskFragmentContainer.Builder(mSplitController, TASK_ID, mActivity) + .setPendingAppearedIntent(intent).build(); final TaskFragmentContainer.OverlayContainerRestoreParams params = mock( TaskFragmentContainer.OverlayContainerRestoreParams.class); doReturn(params).when(mSplitController).getOverlayContainerRestoreParams(any(), any()); @@ -884,8 +886,8 @@ public class OverlayPresentationTest { @NonNull private TaskFragmentContainer createMockTaskFragmentContainer( @NonNull Activity activity, boolean isVisible) { - final TaskFragmentContainer container = mSplitController.newContainer(activity, - activity.getTaskId()); + final TaskFragmentContainer container = createTfContainer(mSplitController, + activity.getTaskId(), activity); setupTaskFragmentInfo(container, activity, isVisible); return container; } @@ -918,10 +920,13 @@ public class OverlayPresentationTest { @Nullable Activity launchingActivity) { final Activity activity = launchingActivity != null ? launchingActivity : createMockActivity(); - TaskFragmentContainer overlayContainer = mSplitController.newContainer( - null /* pendingAppearedActivity */, mIntent, activity, taskId, - null /* pairedPrimaryContainer */, tag, Bundle.EMPTY, - associateLaunchingActivity); + TaskFragmentContainer overlayContainer = + new TaskFragmentContainer.Builder(mSplitController, taskId, activity) + .setPendingAppearedIntent(mIntent) + .setOverlayTag(tag) + .setLaunchOptions(Bundle.EMPTY) + .setAssociatedActivity(associateLaunchingActivity ? activity : null) + .build(); setupTaskFragmentInfo(overlayContainer, createMockActivity(), isVisible); return overlayContainer; } diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java index 35353dbe36be..640b1fced455 100644 --- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java +++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java @@ -41,6 +41,7 @@ import static androidx.window.extensions.embedding.EmbeddingTestUtils.createSpli import static androidx.window.extensions.embedding.EmbeddingTestUtils.createSplitPlaceholderRuleBuilder; import static androidx.window.extensions.embedding.EmbeddingTestUtils.createSplitRule; import static androidx.window.extensions.embedding.EmbeddingTestUtils.createTestTaskContainer; +import static androidx.window.extensions.embedding.EmbeddingTestUtils.createTfContainer; import static androidx.window.extensions.embedding.EmbeddingTestUtils.getSplitBounds; import static androidx.window.extensions.embedding.SplitRule.FINISH_ALWAYS; @@ -59,7 +60,6 @@ import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.clearInvocations; @@ -198,7 +198,7 @@ public class SplitControllerTest { @Test public void testOnTaskFragmentVanished() { - final TaskFragmentContainer tf = mSplitController.newContainer(mActivity, TASK_ID); + final TaskFragmentContainer tf = createTfContainer(mSplitController, mActivity); doReturn(tf.getTaskFragmentToken()).when(mInfo).getFragmentToken(); // The TaskFragment has been removed in the server, we only need to cleanup the reference. @@ -213,7 +213,7 @@ public class SplitControllerTest { public void testOnTaskFragmentAppearEmptyTimeout() { // Setup to make sure a transaction record is started. mTransactionManager.startNewTransaction(); - final TaskFragmentContainer tf = mSplitController.newContainer(mActivity, TASK_ID); + final TaskFragmentContainer tf = createTfContainer(mSplitController, mActivity); doCallRealMethod().when(mSplitController).onTaskFragmentAppearEmptyTimeout(any(), any()); mSplitController.onTaskFragmentAppearEmptyTimeout(mTransaction, tf); @@ -224,7 +224,7 @@ public class SplitControllerTest { @Test public void testOnActivityDestroyed() { doReturn(new Binder()).when(mActivity).getActivityToken(); - final TaskFragmentContainer tf = mSplitController.newContainer(mActivity, TASK_ID); + final TaskFragmentContainer tf = createTfContainer(mSplitController, mActivity); assertTrue(tf.hasActivity(mActivity.getActivityToken())); @@ -245,12 +245,9 @@ public class SplitControllerTest { public void testNewContainer() { // Must pass in a valid activity. assertThrows(IllegalArgumentException.class, () -> - mSplitController.newContainer(null /* activity */, TASK_ID)); - assertThrows(IllegalArgumentException.class, () -> - mSplitController.newContainer(mActivity, null /* launchingActivity */, TASK_ID)); + createTfContainer(mSplitController, null /* activity */)); - final TaskFragmentContainer tf = mSplitController.newContainer(mActivity, mActivity, - TASK_ID); + final TaskFragmentContainer tf = createTfContainer(mSplitController, mActivity); final TaskContainer taskContainer = mSplitController.getTaskContainer(TASK_ID); assertNotNull(tf); @@ -263,7 +260,7 @@ public class SplitControllerTest { public void testUpdateContainer() { // Make SplitController#launchPlaceholderIfNecessary(TaskFragmentContainer) return true // and verify if shouldContainerBeExpanded() not called. - final TaskFragmentContainer tf = mSplitController.newContainer(mActivity, TASK_ID); + final TaskFragmentContainer tf = createTfContainer(mSplitController, mActivity); spyOn(tf); doReturn(mActivity).when(tf).getTopNonFinishingActivity(); doReturn(true).when(tf).isEmpty(); @@ -369,8 +366,12 @@ public class SplitControllerTest { public void testOnStartActivityResultError() { final Intent intent = new Intent(); final TaskContainer taskContainer = createTestTaskContainer(); - final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */, - intent, taskContainer, mSplitController, null /* pairedPrimaryContainer */); + final int taskId = taskContainer.getTaskId(); + mSplitController.addTaskContainer(taskId, taskContainer); + final TaskFragmentContainer container = new TaskFragmentContainer.Builder(mSplitController, + taskId, null /* activityInTask */) + .setPendingAppearedIntent(intent) + .build(); final SplitController.ActivityStartMonitor monitor = mSplitController.getActivityStartMonitor(); @@ -410,7 +411,8 @@ public class SplitControllerTest { @Test public void testOnActivityReparentedToTask_diffProcess() { // Create an empty TaskFragment to initialize for the Task. - mSplitController.newContainer(new Intent(), mActivity, TASK_ID); + new TaskFragmentContainer.Builder(mSplitController, TASK_ID, mActivity) + .setPendingAppearedIntent(new Intent()).build(); final IBinder activityToken = new Binder(); final Intent intent = new Intent(); @@ -595,8 +597,9 @@ public class SplitControllerTest { verify(mTransaction, never()).reparentActivityToTaskFragment(any(), any()); // Place in the top container if there is no other rule matched. - final TaskFragmentContainer topContainer = mSplitController - .newContainer(new Intent(), mActivity, TASK_ID); + final TaskFragmentContainer topContainer = + new TaskFragmentContainer.Builder(mSplitController, TASK_ID, mActivity) + .setPendingAppearedIntent(new Intent()).build(); mSplitController.placeActivityInTopContainer(mTransaction, mActivity); verify(mTransaction).reparentActivityToTaskFragment(topContainer.getTaskFragmentToken(), @@ -604,7 +607,7 @@ public class SplitControllerTest { // Not reparent if activity is in a TaskFragment. clearInvocations(mTransaction); - mSplitController.newContainer(mActivity, TASK_ID); + createTfContainer(mSplitController, mActivity); mSplitController.placeActivityInTopContainer(mTransaction, mActivity); verify(mTransaction, never()).reparentActivityToTaskFragment(any(), any()); @@ -616,8 +619,7 @@ public class SplitControllerTest { false /* isOnReparent */); assertFalse(result); - verify(mSplitController, never()).newContainer(any(), any(), any(), anyInt(), any(), - anyString(), any(), anyBoolean()); + verify(mSplitController, never()).addTaskContainer(anyInt(), any()); } @Test @@ -632,7 +634,6 @@ public class SplitControllerTest { assertTrue(result); assertNotNull(container); - verify(mSplitController).newContainer(mActivity, TASK_ID); verify(mSplitPresenter).expandActivity(mTransaction, container.getTaskFragmentToken(), mActivity); } @@ -642,7 +643,7 @@ public class SplitControllerTest { setupExpandRule(mActivity); // When the activity is not in any TaskFragment, create a new expanded TaskFragment for it. - final TaskFragmentContainer container = mSplitController.newContainer(mActivity, TASK_ID); + final TaskFragmentContainer container = createTfContainer(mSplitController, mActivity); final boolean result = mSplitController.resolveActivityToContainer(mTransaction, mActivity, false /* isOnReparent */); @@ -692,8 +693,8 @@ public class SplitControllerTest { // Don't launch placeholder if the activity is not in the topmost active TaskFragment. final Activity activity = createMockActivity(); - mSplitController.newContainer(mActivity, TASK_ID); - mSplitController.newContainer(activity, TASK_ID); + createTfContainer(mSplitController, mActivity); + createTfContainer(mSplitController, activity); final boolean result = mSplitController.resolveActivityToContainer(mTransaction, mActivity, false /* isOnReparent */); @@ -711,7 +712,7 @@ public class SplitControllerTest { (SplitPlaceholderRule) mSplitController.getSplitRules().get(0); // Launch placeholder if the activity is in the topmost expanded TaskFragment. - mSplitController.newContainer(mActivity, TASK_ID); + createTfContainer(mSplitController, mActivity); final boolean result = mSplitController.resolveActivityToContainer(mTransaction, mActivity, false /* isOnReparent */); @@ -763,10 +764,11 @@ public class SplitControllerTest { final SplitPairRule splitRule = (SplitPairRule) mSplitController.getSplitRules().get(0); // Activity is already in primary split, no need to create new split. - final TaskFragmentContainer primaryContainer = mSplitController.newContainer(mActivity, - TASK_ID); - final TaskFragmentContainer secondaryContainer = mSplitController.newContainer( - secondaryIntent, mActivity, TASK_ID); + final TaskFragmentContainer primaryContainer = + createTfContainer(mSplitController, mActivity); + final TaskFragmentContainer secondaryContainer = + new TaskFragmentContainer.Builder(mSplitController, TASK_ID, mActivity) + .setPendingAppearedIntent(secondaryIntent).build(); mSplitController.registerSplit( mTransaction, primaryContainer, @@ -779,8 +781,6 @@ public class SplitControllerTest { false /* isOnReparent */); assertTrue(result); - verify(mSplitController, never()).newContainer(any(), any(), any(), anyInt(), any(), - anyString(), any(), anyBoolean()); verify(mSplitController, never()).registerSplit(any(), any(), any(), any(), any(), any()); } @@ -792,10 +792,11 @@ public class SplitControllerTest { // The new launched activity is in primary split, but there is no rule for it to split with // the secondary, so return false. - final TaskFragmentContainer primaryContainer = mSplitController.newContainer(mActivity, - TASK_ID); - final TaskFragmentContainer secondaryContainer = mSplitController.newContainer( - secondaryIntent, mActivity, TASK_ID); + final TaskFragmentContainer primaryContainer = + createTfContainer(mSplitController, mActivity); + final TaskFragmentContainer secondaryContainer = + new TaskFragmentContainer.Builder(mSplitController, TASK_ID, mActivity) + .setPendingAppearedIntent(secondaryIntent).build(); mSplitController.registerSplit( mTransaction, primaryContainer, @@ -822,8 +823,6 @@ public class SplitControllerTest { false /* isOnReparent */); assertTrue(result); - verify(mSplitController, never()).newContainer(any(), any(), any(), anyInt(), any(), - anyString(), any(), anyBoolean()); verify(mSplitController, never()).registerSplit(any(), any(), any(), any(), any(), any()); } @@ -852,10 +851,10 @@ public class SplitControllerTest { doReturn(PLACEHOLDER_INTENT).when(mActivity).getIntent(); // Activity is a placeholder. - final TaskFragmentContainer primaryContainer = mSplitController.newContainer( - primaryActivity, TASK_ID); - final TaskFragmentContainer secondaryContainer = mSplitController.newContainer(mActivity, - TASK_ID); + final TaskFragmentContainer primaryContainer = + createTfContainer(mSplitController, primaryActivity); + final TaskFragmentContainer secondaryContainer = + createTfContainer(mSplitController, mActivity); mSplitController.registerSplit( mTransaction, primaryContainer, @@ -874,8 +873,7 @@ public class SplitControllerTest { final Activity activityBelow = createMockActivity(); setupSplitRule(activityBelow, mActivity); - final TaskFragmentContainer container = mSplitController.newContainer(activityBelow, - TASK_ID); + final TaskFragmentContainer container = createTfContainer(mSplitController, activityBelow); container.addPendingAppearedActivity(mActivity); final boolean result = mSplitController.resolveActivityToContainer(mTransaction, mActivity, false /* isOnReparent */); @@ -890,8 +888,7 @@ public class SplitControllerTest { setupSplitRule(mActivity, activityBelow); // Disallow to split as primary. - final TaskFragmentContainer container = mSplitController.newContainer(activityBelow, - TASK_ID); + final TaskFragmentContainer container = createTfContainer(mSplitController, activityBelow); container.addPendingAppearedActivity(mActivity); boolean result = mSplitController.resolveActivityToContainer(mTransaction, mActivity, false /* isOnReparent */); @@ -961,8 +958,7 @@ public class SplitControllerTest { doReturn(createActivityInfoWithMinDimensions()).when(mActivity).getActivityInfo(); - final TaskFragmentContainer container = mSplitController.newContainer(activityBelow, - TASK_ID); + final TaskFragmentContainer container = createTfContainer(mSplitController, activityBelow); container.addPendingAppearedActivity(mActivity); // Allow to split as primary. @@ -980,8 +976,7 @@ public class SplitControllerTest { doReturn(createActivityInfoWithMinDimensions()).when(mActivity).getActivityInfo(); - final TaskFragmentContainer container = mSplitController.newContainer(activityBelow, - TASK_ID); + final TaskFragmentContainer container = createTfContainer(mSplitController, activityBelow); container.addPendingAppearedActivity(mActivity); boolean result = mSplitController.resolveActivityToContainer(mTransaction, mActivity, @@ -1044,8 +1039,8 @@ public class SplitControllerTest { public void testResolveActivityToContainer_skipIfNonTopOrPinned() { final TaskFragmentContainer container = createMockTaskFragmentContainer(mActivity); final Activity pinnedActivity = createMockActivity(); - final TaskFragmentContainer topContainer = mSplitController.newContainer(pinnedActivity, - TASK_ID); + final TaskFragmentContainer topContainer = + createTfContainer(mSplitController, pinnedActivity); final TaskContainer taskContainer = container.getTaskContainer(); spyOn(taskContainer); doReturn(container).when(taskContainer).getTopNonFinishingTaskFragmentContainer(false); @@ -1351,7 +1346,7 @@ public class SplitControllerTest { // Launch placeholder for activity in top TaskFragment. setupPlaceholderRule(mActivity); mTransactionManager.startNewTransaction(); - final TaskFragmentContainer container = mSplitController.newContainer(mActivity, TASK_ID); + final TaskFragmentContainer container = createTfContainer(mSplitController, mActivity); mSplitController.launchPlaceholderIfNecessary(mTransaction, mActivity, true /* isOnCreated */); @@ -1365,9 +1360,10 @@ public class SplitControllerTest { // Do not launch placeholder for invisible activity below the top TaskFragment. setupPlaceholderRule(mActivity); mTransactionManager.startNewTransaction(); - final TaskFragmentContainer bottomTf = mSplitController.newContainer(mActivity, TASK_ID); - final TaskFragmentContainer topTf = mSplitController.newContainer(new Intent(), mActivity, - TASK_ID); + final TaskFragmentContainer bottomTf = createTfContainer(mSplitController, mActivity); + final TaskFragmentContainer topTf = + new TaskFragmentContainer.Builder(mSplitController, TASK_ID, mActivity) + .setPendingAppearedIntent(new Intent()).build(); bottomTf.setInfo(mTransaction, createMockTaskFragmentInfo(bottomTf, mActivity, false /* isVisible */)); topTf.setInfo(mTransaction, createMockTaskFragmentInfo(topTf, createMockActivity())); @@ -1383,9 +1379,10 @@ public class SplitControllerTest { // Launch placeholder for visible activity below the top TaskFragment. setupPlaceholderRule(mActivity); mTransactionManager.startNewTransaction(); - final TaskFragmentContainer bottomTf = mSplitController.newContainer(mActivity, TASK_ID); - final TaskFragmentContainer topTf = mSplitController.newContainer(new Intent(), mActivity, - TASK_ID); + final TaskFragmentContainer bottomTf = createTfContainer(mSplitController, mActivity); + final TaskFragmentContainer topTf = + new TaskFragmentContainer.Builder(mSplitController, TASK_ID, mActivity) + .setPendingAppearedIntent(new Intent()).build(); bottomTf.setInfo(mTransaction, createMockTaskFragmentInfo(bottomTf, mActivity, true /* isVisible */)); topTf.setInfo(mTransaction, createMockTaskFragmentInfo(topTf, createMockActivity())); @@ -1412,7 +1409,7 @@ public class SplitControllerTest { @Test public void testFinishActivityStacks_finishSingleActivityStack() { - TaskFragmentContainer tf = mSplitController.newContainer(mActivity, TASK_ID); + TaskFragmentContainer tf = createTfContainer(mSplitController, mActivity); tf.setInfo(mTransaction, createMockTaskFragmentInfo(tf, mActivity)); final TaskContainer taskContainer = mSplitController.mTaskContainers.get(TASK_ID); @@ -1426,8 +1423,8 @@ public class SplitControllerTest { @Test public void testFinishActivityStacks_finishActivityStacksInOrder() { - TaskFragmentContainer bottomTf = mSplitController.newContainer(mActivity, TASK_ID); - TaskFragmentContainer topTf = mSplitController.newContainer(mActivity, TASK_ID); + TaskFragmentContainer bottomTf = createTfContainer(mSplitController, mActivity); + TaskFragmentContainer topTf = createTfContainer(mSplitController, mActivity); bottomTf.setInfo(mTransaction, createMockTaskFragmentInfo(bottomTf, mActivity)); topTf.setInfo(mTransaction, createMockTaskFragmentInfo(topTf, createMockActivity())); @@ -1687,8 +1684,8 @@ public class SplitControllerTest { /** Creates a mock TaskFragment that has been registered and appeared in the organizer. */ private TaskFragmentContainer createMockTaskFragmentContainer(@NonNull Activity activity) { - final TaskFragmentContainer container = mSplitController.newContainer(activity, - activity.getTaskId()); + final TaskFragmentContainer container = createTfContainer(mSplitController, + activity.getTaskId(), activity); setupTaskFragmentInfo(container, activity); return container; } diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java index 3fbce9ec31a5..816e2dae1e5b 100644 --- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java +++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java @@ -31,6 +31,7 @@ import static androidx.window.extensions.embedding.EmbeddingTestUtils.createActi import static androidx.window.extensions.embedding.EmbeddingTestUtils.createMockTaskFragmentInfo; import static androidx.window.extensions.embedding.EmbeddingTestUtils.createSplitPairRuleBuilder; import static androidx.window.extensions.embedding.EmbeddingTestUtils.createSplitRule; +import static androidx.window.extensions.embedding.EmbeddingTestUtils.createTfContainer; import static androidx.window.extensions.embedding.EmbeddingTestUtils.createWindowLayoutInfo; import static androidx.window.extensions.embedding.EmbeddingTestUtils.getSplitBounds; import static androidx.window.extensions.embedding.SplitPresenter.EXPAND_CONTAINERS_ATTRIBUTES; @@ -139,7 +140,7 @@ public class SplitPresenterTest { @Test public void testCreateTaskFragment() { - final TaskFragmentContainer container = mController.newContainer(mActivity, TASK_ID); + final TaskFragmentContainer container = createTfContainer(mController, mActivity); mPresenter.createTaskFragment(mTransaction, container.getTaskFragmentToken(), mActivity.getActivityToken(), TASK_BOUNDS, WINDOWING_MODE_MULTI_WINDOW); @@ -150,7 +151,7 @@ public class SplitPresenterTest { @Test public void testResizeTaskFragment() { - final TaskFragmentContainer container = mController.newContainer(mActivity, TASK_ID); + final TaskFragmentContainer container = createTfContainer(mController, mActivity); mPresenter.mFragmentInfos.put(container.getTaskFragmentToken(), mTaskFragmentInfo); mPresenter.resizeTaskFragment(mTransaction, container.getTaskFragmentToken(), TASK_BOUNDS); @@ -166,7 +167,7 @@ public class SplitPresenterTest { @Test public void testUpdateWindowingMode() { - final TaskFragmentContainer container = mController.newContainer(mActivity, TASK_ID); + final TaskFragmentContainer container = createTfContainer(mController, mActivity); mPresenter.mFragmentInfos.put(container.getTaskFragmentToken(), mTaskFragmentInfo); mPresenter.updateWindowingMode(mTransaction, container.getTaskFragmentToken(), WINDOWING_MODE_MULTI_WINDOW); @@ -184,8 +185,8 @@ public class SplitPresenterTest { @Test public void testSetAdjacentTaskFragments() { - final TaskFragmentContainer container0 = mController.newContainer(mActivity, TASK_ID); - final TaskFragmentContainer container1 = mController.newContainer(mActivity, TASK_ID); + final TaskFragmentContainer container0 = createTfContainer(mController, mActivity); + final TaskFragmentContainer container1 = createTfContainer(mController, mActivity); mPresenter.setAdjacentTaskFragments(mTransaction, container0.getTaskFragmentToken(), container1.getTaskFragmentToken(), null /* adjacentParams */); @@ -202,8 +203,8 @@ public class SplitPresenterTest { @Test public void testClearAdjacentTaskFragments() { - final TaskFragmentContainer container0 = mController.newContainer(mActivity, TASK_ID); - final TaskFragmentContainer container1 = mController.newContainer(mActivity, TASK_ID); + final TaskFragmentContainer container0 = createTfContainer(mController, mActivity); + final TaskFragmentContainer container1 = createTfContainer(mController, mActivity); // No request to clear as it is not set by default. mPresenter.clearAdjacentTaskFragments(mTransaction, container0.getTaskFragmentToken()); @@ -224,8 +225,8 @@ public class SplitPresenterTest { @Test public void testSetCompanionTaskFragment() { - final TaskFragmentContainer container0 = mController.newContainer(mActivity, TASK_ID); - final TaskFragmentContainer container1 = mController.newContainer(mActivity, TASK_ID); + final TaskFragmentContainer container0 = createTfContainer(mController, mActivity); + final TaskFragmentContainer container1 = createTfContainer(mController, mActivity); mPresenter.setCompanionTaskFragment(mTransaction, container0.getTaskFragmentToken(), container1.getTaskFragmentToken()); @@ -242,7 +243,7 @@ public class SplitPresenterTest { @Test public void testSetTaskFragmentDimOnTask() { - final TaskFragmentContainer container = mController.newContainer(mActivity, TASK_ID); + final TaskFragmentContainer container = createTfContainer(mController, mActivity); mPresenter.setTaskFragmentDimOnTask(mTransaction, container.getTaskFragmentToken(), true); verify(mTransaction).addTaskFragmentOperation(eq(container.getTaskFragmentToken()), any()); @@ -255,7 +256,7 @@ public class SplitPresenterTest { @Test public void testUpdateAnimationParams() { - final TaskFragmentContainer container = mController.newContainer(mActivity, TASK_ID); + final TaskFragmentContainer container = createTfContainer(mController, mActivity); // Verify the default. assertTrue(container.areLastRequestedAnimationParamsEqual( @@ -287,7 +288,7 @@ public class SplitPresenterTest { @Test public void testSetTaskFragmentPinned() { - final TaskFragmentContainer container = mController.newContainer(mActivity, TASK_ID); + final TaskFragmentContainer container = createTfContainer(mController, mActivity); // Verify the default. assertFalse(container.isPinned()); @@ -667,8 +668,8 @@ public class SplitPresenterTest { public void testExpandSplitContainerIfNeeded() { Activity secondaryActivity = createMockActivity(); SplitRule splitRule = createSplitRule(mActivity, secondaryActivity); - TaskFragmentContainer primaryTf = mController.newContainer(mActivity, TASK_ID); - TaskFragmentContainer secondaryTf = mController.newContainer(secondaryActivity, TASK_ID); + TaskFragmentContainer primaryTf = createTfContainer(mController, mActivity); + TaskFragmentContainer secondaryTf = createTfContainer(mController, secondaryActivity); SplitContainer splitContainer = new SplitContainer(primaryTf, secondaryActivity, secondaryTf, splitRule, SPLIT_ATTRIBUTES); @@ -710,8 +711,8 @@ public class SplitPresenterTest { @Test public void testCreateNewSplitContainer_secondaryAbovePrimary() { final Activity secondaryActivity = createMockActivity(); - final TaskFragmentContainer bottomTf = mController.newContainer(secondaryActivity, TASK_ID); - final TaskFragmentContainer primaryTf = mController.newContainer(mActivity, TASK_ID); + final TaskFragmentContainer bottomTf = createTfContainer(mController, secondaryActivity); + final TaskFragmentContainer primaryTf = createTfContainer(mController, mActivity); final SplitPairRule rule = createSplitPairRuleBuilder(pair -> pair.first == mActivity && pair.second == secondaryActivity, pair -> false, metrics -> true) diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java index 8913b22115e9..284723279b80 100644 --- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java +++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java @@ -29,6 +29,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; @@ -57,6 +58,9 @@ import java.util.List; * Build/Install/Run: * atest WMJetpackUnitTests:TaskContainerTest */ + +// Suppress GuardedBy warning on unit tests +@SuppressWarnings("GuardedBy") @Presubmit @SmallTest @RunWith(AndroidJUnit4.class) @@ -126,8 +130,11 @@ public class TaskContainerTest { assertTrue(taskContainer.isEmpty()); - final TaskFragmentContainer tf = new TaskFragmentContainer(null /* activity */, - new Intent(), taskContainer, mController, null /* pairedPrimaryContainer */); + doReturn(taskContainer).when(mController).getTaskContainer(anyInt()); + final TaskFragmentContainer tf = new TaskFragmentContainer.Builder(mController, + taskContainer.getTaskId(), null /* activityInTask */) + .setPendingAppearedIntent(new Intent()) + .build(); assertFalse(taskContainer.isEmpty()); @@ -142,12 +149,17 @@ public class TaskContainerTest { final TaskContainer taskContainer = createTestTaskContainer(); assertNull(taskContainer.getTopNonFinishingTaskFragmentContainer()); - final TaskFragmentContainer tf0 = new TaskFragmentContainer(null /* activity */, - new Intent(), taskContainer, mController, null /* pairedPrimaryContainer */); + doReturn(taskContainer).when(mController).getTaskContainer(anyInt()); + final TaskFragmentContainer tf0 = new TaskFragmentContainer.Builder(mController, + taskContainer.getTaskId(), null /* activityInTask */) + .setPendingAppearedIntent(new Intent()) + .build(); assertEquals(tf0, taskContainer.getTopNonFinishingTaskFragmentContainer()); - final TaskFragmentContainer tf1 = new TaskFragmentContainer(null /* activity */, - new Intent(), taskContainer, mController, null /* pairedPrimaryContainer */); + final TaskFragmentContainer tf1 = new TaskFragmentContainer.Builder(mController, + taskContainer.getTaskId(), null /* activityInTask */) + .setPendingAppearedIntent(new Intent()) + .build(); assertEquals(tf1, taskContainer.getTopNonFinishingTaskFragmentContainer()); } diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java index 44ab2c458e39..7fab371cb790 100644 --- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java +++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java @@ -100,24 +100,27 @@ public class TaskFragmentContainerTest { @Test public void testNewContainer() { final TaskContainer taskContainer = createTestTaskContainer(); + mController.addTaskContainer(taskContainer.getTaskId(), taskContainer); // One of the activity and the intent must be non-null assertThrows(IllegalArgumentException.class, - () -> new TaskFragmentContainer(null, null, taskContainer, mController, - null /* pairedPrimaryContainer */)); + () -> new TaskFragmentContainer.Builder(mController, taskContainer.getTaskId(), + null /* activityInTask */).build()); // One of the activity and the intent must be null. assertThrows(IllegalArgumentException.class, - () -> new TaskFragmentContainer(mActivity, mIntent, taskContainer, mController, - null /* pairedPrimaryContainer */)); + () -> new TaskFragmentContainer.Builder(mController, taskContainer.getTaskId(), + null /* activityInTask */) + .setPendingAppearedActivity(createMockActivity()) + .setPendingAppearedIntent(mIntent) + .build()); } @Test public void testFinish() { final TaskContainer taskContainer = createTestTaskContainer(); - final TaskFragmentContainer container = new TaskFragmentContainer(mActivity, - null /* pendingAppearedIntent */, taskContainer, mController, - null /* pairedPrimaryContainer */); + final TaskFragmentContainer container = createTaskFragmentContainer(taskContainer, + mActivity, null /* pendingAppearedIntent */); doReturn(container).when(mController).getContainerWithActivity(mActivity); // Only remove the activity, but not clear the reference until appeared. @@ -148,15 +151,13 @@ public class TaskFragmentContainerTest { @Test public void testFinish_notFinishActivityThatIsReparenting() { final TaskContainer taskContainer = createTestTaskContainer(); - final TaskFragmentContainer container0 = new TaskFragmentContainer(mActivity, - null /* pendingAppearedIntent */, taskContainer, mController, - null /* pairedPrimaryContainer */); + final TaskFragmentContainer container0 = createTaskFragmentContainer(taskContainer, + mActivity, null /* pendingAppearedIntent */); final TaskFragmentInfo info = createMockTaskFragmentInfo(container0, mActivity); container0.setInfo(mTransaction, info); // Request to reparent the activity to a new TaskFragment. - final TaskFragmentContainer container1 = new TaskFragmentContainer(mActivity, - null /* pendingAppearedIntent */, taskContainer, mController, - null /* pairedPrimaryContainer */); + final TaskFragmentContainer container1 = createTaskFragmentContainer(taskContainer, + mActivity, null /* pendingAppearedIntent */); doReturn(container1).when(mController).getContainerWithActivity(mActivity); // The activity is requested to be reparented, so don't finish it. @@ -171,15 +172,13 @@ public class TaskFragmentContainerTest { public void testFinish_alwaysFinishPlaceholder() { // Register container1 as a placeholder final TaskContainer taskContainer = createTestTaskContainer(); - final TaskFragmentContainer container0 = new TaskFragmentContainer(mActivity, - null /* pendingAppearedIntent */, taskContainer, mController, - null /* pairedPrimaryContainer */); + final TaskFragmentContainer container0 = createTaskFragmentContainer(taskContainer, + mActivity, null /* pendingAppearedIntent */); final TaskFragmentInfo info0 = createMockTaskFragmentInfo(container0, mActivity); container0.setInfo(mTransaction, info0); final Activity placeholderActivity = createMockActivity(); - final TaskFragmentContainer container1 = new TaskFragmentContainer(placeholderActivity, - null /* pendingAppearedIntent */, taskContainer, mController, - null /* pairedPrimaryContainer */); + final TaskFragmentContainer container1 = createTaskFragmentContainer(taskContainer, + placeholderActivity, null /* pendingAppearedIntent */); final TaskFragmentInfo info1 = createMockTaskFragmentInfo(container1, placeholderActivity); container1.setInfo(mTransaction, info1); final SplitAttributes splitAttributes = new SplitAttributes.Builder().build(); @@ -207,9 +206,8 @@ public class TaskFragmentContainerTest { public void testSetInfo() { final TaskContainer taskContainer = createTestTaskContainer(); // Pending activity should be cleared when it has appeared on server side. - final TaskFragmentContainer pendingActivityContainer = new TaskFragmentContainer(mActivity, - null /* pendingAppearedIntent */, taskContainer, mController, - null /* pairedPrimaryContainer */); + final TaskFragmentContainer pendingActivityContainer = createTaskFragmentContainer( + taskContainer, mActivity, null /* pendingAppearedIntent */); assertTrue(pendingActivityContainer.mPendingAppearedActivities.contains( mActivity.getActivityToken())); @@ -221,9 +219,8 @@ public class TaskFragmentContainerTest { assertTrue(pendingActivityContainer.mPendingAppearedActivities.isEmpty()); // Pending intent should be cleared when the container becomes non-empty. - final TaskFragmentContainer pendingIntentContainer = new TaskFragmentContainer( - null /* pendingAppearedActivity */, mIntent, taskContainer, mController, - null /* pairedPrimaryContainer */); + final TaskFragmentContainer pendingIntentContainer = createTaskFragmentContainer( + taskContainer, null /* pendingAppearedActivity */, mIntent); assertEquals(mIntent, pendingIntentContainer.getPendingAppearedIntent()); @@ -237,8 +234,8 @@ public class TaskFragmentContainerTest { @Test public void testIsWaitingActivityAppear() { final TaskContainer taskContainer = createTestTaskContainer(); - final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */, - mIntent, taskContainer, mController, null /* pairedPrimaryContainer */); + final TaskFragmentContainer container = createTaskFragmentContainer( + taskContainer, null /* pendingAppearedActivity */, mIntent); assertTrue(container.isWaitingActivityAppear()); @@ -259,8 +256,8 @@ public class TaskFragmentContainerTest { public void testAppearEmptyTimeout() { doNothing().when(mController).onTaskFragmentAppearEmptyTimeout(any(), any()); final TaskContainer taskContainer = createTestTaskContainer(); - final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */, - mIntent, taskContainer, mController, null /* pairedPrimaryContainer */); + final TaskFragmentContainer container = createTaskFragmentContainer( + taskContainer, null /* pendingAppearedActivity */, mIntent); assertNull(container.mAppearEmptyTimeout); @@ -299,8 +296,8 @@ public class TaskFragmentContainerTest { @Test public void testCollectNonFinishingActivities() { final TaskContainer taskContainer = createTestTaskContainer(); - final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */, - mIntent, taskContainer, mController, null /* pairedPrimaryContainer */); + final TaskFragmentContainer container = createTaskFragmentContainer( + taskContainer, null /* pendingAppearedActivity */, mIntent); List<Activity> activities = container.collectNonFinishingActivities(); assertTrue(activities.isEmpty()); @@ -327,8 +324,8 @@ public class TaskFragmentContainerTest { @Test public void testCollectNonFinishingActivities_checkIfStable() { final TaskContainer taskContainer = createTestTaskContainer(); - final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */, - mIntent, taskContainer, mController, null /* pairedPrimaryContainer */); + final TaskFragmentContainer container = createTaskFragmentContainer( + taskContainer, null /* pendingAppearedActivity */, mIntent); // In case mInfo is null, collectNonFinishingActivities(true) should return null. List<Activity> activities = @@ -353,8 +350,8 @@ public class TaskFragmentContainerTest { @Test public void testAddPendingActivity() { final TaskContainer taskContainer = createTestTaskContainer(); - final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */, - mIntent, taskContainer, mController, null /* pairedPrimaryContainer */); + final TaskFragmentContainer container = createTaskFragmentContainer( + taskContainer, null /* pendingAppearedActivity */, mIntent); container.addPendingAppearedActivity(mActivity); assertEquals(1, container.collectNonFinishingActivities().size()); @@ -367,10 +364,10 @@ public class TaskFragmentContainerTest { @Test public void testIsAbove() { final TaskContainer taskContainer = createTestTaskContainer(); - final TaskFragmentContainer container0 = new TaskFragmentContainer(null /* activity */, - mIntent, taskContainer, mController, null /* pairedPrimaryContainer */); - final TaskFragmentContainer container1 = new TaskFragmentContainer(null /* activity */, - mIntent, taskContainer, mController, null /* pairedPrimaryContainer */); + final TaskFragmentContainer container0 = createTaskFragmentContainer( + taskContainer, null /* pendingAppearedActivity */, mIntent); + final TaskFragmentContainer container1 = createTaskFragmentContainer( + taskContainer, null /* pendingAppearedActivity */, mIntent); assertTrue(container1.isAbove(container0)); assertFalse(container0.isAbove(container1)); @@ -379,8 +376,8 @@ public class TaskFragmentContainerTest { @Test public void testGetBottomMostActivity() { final TaskContainer taskContainer = createTestTaskContainer(); - final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */, - mIntent, taskContainer, mController, null /* pairedPrimaryContainer */); + final TaskFragmentContainer container = createTaskFragmentContainer( + taskContainer, null /* pendingAppearedActivity */, mIntent); container.addPendingAppearedActivity(mActivity); assertEquals(mActivity, container.getBottomMostActivity()); @@ -396,8 +393,8 @@ public class TaskFragmentContainerTest { @Test public void testOnActivityDestroyed() { final TaskContainer taskContainer = createTestTaskContainer(mController); - final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */, - mIntent, taskContainer, mController, null /* pairedPrimaryContainer */); + final TaskFragmentContainer container = createTaskFragmentContainer( + taskContainer, null /* pendingAppearedActivity */, mIntent); container.addPendingAppearedActivity(mActivity); final List<IBinder> activities = new ArrayList<>(); activities.add(mActivity.getActivityToken()); @@ -416,8 +413,8 @@ public class TaskFragmentContainerTest { public void testIsInIntermediateState() { // True if no info set. final TaskContainer taskContainer = createTestTaskContainer(); - final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */, - mIntent, taskContainer, mController, null /* pairedPrimaryContainer */); + final TaskFragmentContainer container = createTaskFragmentContainer( + taskContainer, null /* pendingAppearedActivity */, mIntent); spyOn(taskContainer); doReturn(true).when(taskContainer).isVisible(); @@ -479,8 +476,8 @@ public class TaskFragmentContainerTest { @Test public void testHasAppearedActivity() { final TaskContainer taskContainer = createTestTaskContainer(); - final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */, - mIntent, taskContainer, mController, null /* pairedPrimaryContainer */); + final TaskFragmentContainer container = createTaskFragmentContainer( + taskContainer, null /* pendingAppearedActivity */, mIntent); container.addPendingAppearedActivity(mActivity); assertFalse(container.hasAppearedActivity(mActivity.getActivityToken())); @@ -496,8 +493,8 @@ public class TaskFragmentContainerTest { @Test public void testHasPendingAppearedActivity() { final TaskContainer taskContainer = createTestTaskContainer(); - final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */, - mIntent, taskContainer, mController, null /* pairedPrimaryContainer */); + final TaskFragmentContainer container = createTaskFragmentContainer( + taskContainer, null /* pendingAppearedActivity */, mIntent); container.addPendingAppearedActivity(mActivity); assertTrue(container.hasPendingAppearedActivity(mActivity.getActivityToken())); @@ -513,10 +510,10 @@ public class TaskFragmentContainerTest { @Test public void testHasActivity() { final TaskContainer taskContainer = createTestTaskContainer(mController); - final TaskFragmentContainer container1 = new TaskFragmentContainer(null /* activity */, - mIntent, taskContainer, mController, null /* pairedPrimaryContainer */); - final TaskFragmentContainer container2 = new TaskFragmentContainer(null /* activity */, - mIntent, taskContainer, mController, null /* pairedPrimaryContainer */); + final TaskFragmentContainer container1 = createTaskFragmentContainer( + taskContainer, null /* pendingAppearedActivity */, mIntent); + final TaskFragmentContainer container2 = createTaskFragmentContainer( + taskContainer, null /* pendingAppearedActivity */, mIntent); // Activity is pending appeared on container2. container2.addPendingAppearedActivity(mActivity); @@ -550,17 +547,19 @@ public class TaskFragmentContainerTest { @Test public void testNewContainerWithPairedPrimaryContainer() { final TaskContainer taskContainer = createTestTaskContainer(); - final TaskFragmentContainer tf0 = new TaskFragmentContainer( - null /* pendingAppearedActivity */, new Intent(), taskContainer, mController, - null /* pairedPrimaryTaskFragment */); - final TaskFragmentContainer tf1 = new TaskFragmentContainer( - null /* pendingAppearedActivity */, new Intent(), taskContainer, mController, - null /* pairedPrimaryTaskFragment */); + mController.addTaskContainer(taskContainer.getTaskId(), taskContainer); + final TaskFragmentContainer tf0 = createTaskFragmentContainer( + taskContainer, null /* pendingAppearedActivity */, new Intent()); + final TaskFragmentContainer tf1 = createTaskFragmentContainer( + taskContainer, null /* pendingAppearedActivity */, new Intent()); // When tf2 is created with using tf0 as pairedPrimaryContainer, tf2 should be inserted // right above tf0. - final TaskFragmentContainer tf2 = new TaskFragmentContainer( - null /* pendingAppearedActivity */, new Intent(), taskContainer, mController, tf0); + final TaskFragmentContainer tf2 = new TaskFragmentContainer.Builder(mController, + taskContainer.getTaskId(), null /* activityInTask */) + .setPendingAppearedIntent(new Intent()) + .setPairedPrimaryContainer(tf0) + .build(); assertEquals(0, taskContainer.indexOf(tf0)); assertEquals(1, taskContainer.indexOf(tf2)); assertEquals(2, taskContainer.indexOf(tf1)); @@ -569,18 +568,15 @@ public class TaskFragmentContainerTest { @Test public void testNewContainerWithPairedPendingAppearedActivity() { final TaskContainer taskContainer = createTestTaskContainer(); - final TaskFragmentContainer tf0 = new TaskFragmentContainer( - createMockActivity(), null /* pendingAppearedIntent */, taskContainer, mController, - null /* pairedPrimaryTaskFragment */); - final TaskFragmentContainer tf1 = new TaskFragmentContainer( - null /* pendingAppearedActivity */, new Intent(), taskContainer, mController, - null /* pairedPrimaryTaskFragment */); + final TaskFragmentContainer tf0 = createTaskFragmentContainer(taskContainer, + createMockActivity(), null /* pendingAppearedIntent */); + final TaskFragmentContainer tf1 = createTaskFragmentContainer(taskContainer, + null /* pendingAppearedActivity */, new Intent()); // When tf2 is created with pendingAppearedActivity, tf2 should be inserted below any // TaskFragment without any Activity. - final TaskFragmentContainer tf2 = new TaskFragmentContainer( - createMockActivity(), null /* pendingAppearedIntent */, taskContainer, mController, - null /* pairedPrimaryTaskFragment */); + final TaskFragmentContainer tf2 = createTaskFragmentContainer(taskContainer, + createMockActivity(), null /* pendingAppearedIntent */); assertEquals(0, taskContainer.indexOf(tf0)); assertEquals(1, taskContainer.indexOf(tf2)); assertEquals(2, taskContainer.indexOf(tf1)); @@ -589,9 +585,8 @@ public class TaskFragmentContainerTest { @Test public void testIsVisible() { final TaskContainer taskContainer = createTestTaskContainer(); - final TaskFragmentContainer container = new TaskFragmentContainer( - null /* pendingAppearedActivity */, new Intent(), taskContainer, mController, - null /* pairedPrimaryTaskFragment */); + final TaskFragmentContainer container = createTaskFragmentContainer(taskContainer, + null /* pendingAppearedActivity */, new Intent()); // Not visible when there is not appeared. assertFalse(container.isVisible()); @@ -617,4 +612,14 @@ public class TaskFragmentContainerTest { doReturn(activity).when(mController).getActivity(activityToken); return activity; } + + private TaskFragmentContainer createTaskFragmentContainer(TaskContainer taskContainer, + Activity pendingAppearedActivity, Intent pendingAppearedIntent) { + final int taskId = taskContainer.getTaskId(); + mController.addTaskContainer(taskId, taskContainer); + return new TaskFragmentContainer.Builder(mController, taskId, pendingAppearedActivity) + .setPendingAppearedActivity(pendingAppearedActivity) + .setPendingAppearedIntent(pendingAppearedIntent) + .build(); + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java index f2095b130989..3ded7d246499 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java @@ -175,6 +175,7 @@ public class ShellTaskOrganizer extends TaskOrganizer implements .setName("home_task_overlay_container") .setContainerLayer() .setHidden(false) + .setCallsite("ShellTaskOrganizer.mHomeTaskOverlayContainer") .build(); /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java index fb0a1ab3062e..12bbd51b968d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java @@ -522,14 +522,16 @@ public abstract class WMShellModule { RecentsTransitionHandler recentsTransitionHandler, MultiInstanceHelper multiInstanceHelper, @ShellMainThread ShellExecutor mainExecutor, - Optional<DesktopTasksLimiter> desktopTasksLimiter) { + Optional<DesktopTasksLimiter> desktopTasksLimiter, + Optional<RecentTasksController> recentTasksController) { return new DesktopTasksController(context, shellInit, shellCommandHandler, shellController, displayController, shellTaskOrganizer, syncQueue, rootTaskDisplayAreaOrganizer, dragAndDropController, transitions, enterDesktopTransitionHandler, exitDesktopTransitionHandler, toggleResizeDesktopTaskTransitionHandler, dragToDesktopTransitionHandler, desktopModeTaskRepository, desktopModeLoggerTransitionObserver, launchAdjacentController, - recentsTransitionHandler, multiInstanceHelper, mainExecutor, desktopTasksLimiter); + recentsTransitionHandler, multiInstanceHelper, + mainExecutor, desktopTasksLimiter, recentTasksController.orElse(null)); } @WMSingleton diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java index 38db1ebdc47b..ed0d2b87b03f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java @@ -223,6 +223,7 @@ public class DesktopModeVisualIndicator { mLeash = builder .setName("Desktop Mode Visual Indicator") .setContainerLayer() + .setCallsite("DesktopModeVisualIndicator.createView") .build(); t.show(mLeash); final WindowManager.LayoutParams lp = diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt index 6e45397411d7..ef384c74cb5e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt @@ -70,6 +70,7 @@ import com.android.wm.shell.desktopmode.DesktopModeTaskRepository.VisibleTasksLi import com.android.wm.shell.desktopmode.DragToDesktopTransitionHandler.DragToDesktopStateListener import com.android.wm.shell.draganddrop.DragAndDropController import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE +import com.android.wm.shell.recents.RecentTasksController import com.android.wm.shell.recents.RecentsTransitionHandler import com.android.wm.shell.recents.RecentsTransitionStateListener import com.android.wm.shell.shared.DesktopModeStatus @@ -118,6 +119,7 @@ class DesktopTasksController( private val multiInstanceHelper: MultiInstanceHelper, @ShellMainThread private val mainExecutor: ShellExecutor, private val desktopTasksLimiter: Optional<DesktopTasksLimiter>, + private val recentTasksController: RecentTasksController? ) : RemoteCallable<DesktopTasksController>, Transitions.TransitionHandler, @@ -293,24 +295,49 @@ class DesktopTasksController( taskId: Int, wct: WindowContainerTransaction = WindowContainerTransaction() ): Boolean { - shellTaskOrganizer.getRunningTaskInfo(taskId)?.let { task -> moveToDesktop(task, wct) } - ?: return false + shellTaskOrganizer.getRunningTaskInfo(taskId)?.let { + moveToDesktop(it, wct) + } ?: moveToDesktopFromNonRunningTask(taskId, wct) return true } - /** Move a task to desktop */ + private fun moveToDesktopFromNonRunningTask( + taskId: Int, + wct: WindowContainerTransaction + ): Boolean { + recentTasksController?.findTaskInBackground(taskId)?.let { + KtProtoLog.v( + WM_SHELL_DESKTOP_MODE, + "DesktopTasksController: moveToDesktopFromNonRunningTask taskId=%d", + taskId + ) + // TODO(342378842): Instead of using default display, support multiple displays + val taskToMinimize = + bringDesktopAppsToFrontBeforeShowingNewTask(DEFAULT_DISPLAY, wct, taskId) + addMoveToDesktopChangesNonRunningTask(wct, taskId) + // TODO(343149901): Add DPI changes for task launch + val transition = enterDesktopTaskTransitionHandler.moveToDesktop(wct) + addPendingMinimizeTransition(transition, taskToMinimize) + return true + } ?: return false + } + + private fun addMoveToDesktopChangesNonRunningTask( + wct: WindowContainerTransaction, + taskId: Int + ) { + val options = ActivityOptions.makeBasic() + options.launchWindowingMode = WINDOWING_MODE_FREEFORM + wct.startTask(taskId, options.toBundle()) + } + + /** + * Move a task to desktop + */ fun moveToDesktop( task: RunningTaskInfo, wct: WindowContainerTransaction = WindowContainerTransaction() ) { - if (!DesktopModeStatus.canEnterDesktopMode(context)) { - KtProtoLog.w( - WM_SHELL_DESKTOP_MODE, - "DesktopTasksController: Cannot enter desktop, " + - "display does not meet minimum size requirements" - ) - return - } if (Flags.enableDesktopWindowingModalsPolicy() && isSingleTopActivityTranslucent(task)) { KtProtoLog.w( WM_SHELL_DESKTOP_MODE, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java index c7f693d8de50..6fcea1fe5560 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java @@ -675,6 +675,7 @@ public class PipTransition extends PipTransitionController { .setContainerLayer() .setHidden(false) .setParent(root.getLeash()) + .setCallsite("PipTransition.startExitAnimation") .build(); startTransaction.reparent(activitySurface, pipLeash); // Put the activity at local position with offset in case it is letterboxed. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTransition.java index c2f4d72a1ddf..ca0d61f8fc9b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTransition.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTransition.java @@ -233,6 +233,7 @@ public class TvPipTransition extends PipTransitionController { .setContainerLayer() .setHidden(false) .setParent(root.getLeash()) + .setCallsite("TvPipTransition.startAnimation") .build(); startTransaction.reparent(activitySurface, pipLeash); // Put the activity at local position with offset in case it is letterboxed. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java index d8f2c02b5399..863202d5e1c3 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java @@ -446,6 +446,25 @@ public class RecentTasksController implements TaskStackListenerCallback, return null; } + /** + * Find the background task that match the given taskId. + */ + @Nullable + public ActivityManager.RecentTaskInfo findTaskInBackground(int taskId) { + List<ActivityManager.RecentTaskInfo> tasks = mActivityTaskManager.getRecentTasks( + Integer.MAX_VALUE, ActivityManager.RECENT_IGNORE_UNAVAILABLE, + ActivityManager.getCurrentUser()); + for (int i = 0; i < tasks.size(); i++) { + final ActivityManager.RecentTaskInfo task = tasks.get(i); + if (task.isVisible) { + continue; + } + if (taskId == task.taskId) { + return task; + } + } + return null; + } public void dump(@NonNull PrintWriter pw, String prefix) { final String innerPrefix = prefix + " "; pw.println(prefix + TAG); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java index 1be85d05c16e..ad4f02d13cc6 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java @@ -280,6 +280,7 @@ public class TransitionAnimationHelper { .setParent(rootLeash) .setColorLayer() .setOpaque(true) + .setCallsite("TransitionAnimationHelper.addBackgroundToTransition") .build(); startTransaction .setLayer(animationBackgroundSurface, Integer.MIN_VALUE) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java index 5379ca6cd51d..badce6e93d67 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java @@ -132,6 +132,7 @@ class DragResizeInputListener implements AutoCloseable { .setName("TaskInputSink of " + decorationSurface) .setContainerLayer() .setParent(mDecorationSurface) + .setCallsite("DragResizeInputListener.constructor") .build(); mSurfaceControlTransactionSupplier.get() .setLayer(mInputSinkSurface, WindowDecoration.INPUT_SINK_Z_ORDER) 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 2cbe47212c63..0dc512835d65 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 @@ -268,6 +268,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> .setName("Decor container of Task=" + mTaskInfo.taskId) .setContainerLayer() .setParent(mTaskSurface) + .setCallsite("WindowDecoration.relayout_1") .build(); startT.setTrustedOverlay(mDecorationContainerSurface, true) @@ -285,6 +286,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> .setName("Caption container of Task=" + mTaskInfo.taskId) .setContainerLayer() .setParent(mDecorationContainerSurface) + .setCallsite("WindowDecoration.relayout_2") .build(); } @@ -575,6 +577,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> .setName(namePrefix + " of Task=" + mTaskInfo.taskId) .setContainerLayer() .setParent(mDecorationContainerSurface) + .setCallsite("WindowDecoration.addWindow") .build(); View v = LayoutInflater.from(mDecorWindowContext).inflate(layoutId, null); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt index ac67bd1fedd8..cf6cea2b34a7 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt @@ -16,6 +16,7 @@ package com.android.wm.shell.desktopmode +import android.app.ActivityManager.RecentTaskInfo import android.app.ActivityManager.RunningTaskInfo import android.app.WindowConfiguration.ACTIVITY_TYPE_HOME import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD @@ -47,13 +48,16 @@ import android.view.WindowManager.TRANSIT_OPEN import android.view.WindowManager.TRANSIT_TO_BACK import android.view.WindowManager.TRANSIT_TO_FRONT import android.window.DisplayAreaInfo +import android.window.IWindowContainerToken import android.window.RemoteTransition import android.window.TransitionRequestInfo import android.window.WindowContainerToken import android.window.WindowContainerTransaction +import android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_LAUNCH_TASK import android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_PENDING_INTENT import android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REMOVE_TASK import android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER +import android.window.WindowContainerTransaction.HierarchyOp.LAUNCH_KEY_TASK_ID import androidx.test.filters.SmallTest import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession @@ -78,6 +82,7 @@ import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFulls import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createHomeTask import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createSplitScreenTask import com.android.wm.shell.draganddrop.DragAndDropController +import com.android.wm.shell.recents.RecentTasksController import com.android.wm.shell.recents.RecentsTransitionHandler import com.android.wm.shell.recents.RecentsTransitionStateListener import com.android.wm.shell.shared.DesktopModeStatus @@ -93,6 +98,7 @@ import com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_DESKTOP_MODE import com.android.wm.shell.transition.Transitions.TransitionHandler import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertWithMessage +import java.util.Optional import org.junit.After import org.junit.Assume.assumeTrue import org.junit.Before @@ -115,7 +121,6 @@ import org.mockito.kotlin.anyOrNull import org.mockito.kotlin.atLeastOnce import org.mockito.kotlin.capture import org.mockito.quality.Strictness -import java.util.Optional import junit.framework.Assert.assertFalse import junit.framework.Assert.assertTrue import org.mockito.Mockito.`when` as whenever @@ -154,6 +159,7 @@ class DesktopTasksControllerTest : ShellTestCase() { @Mock lateinit var multiInstanceHelper: MultiInstanceHelper @Mock lateinit var desktopModeLoggerTransitionObserver: DesktopModeLoggerTransitionObserver @Mock lateinit var desktopModeVisualIndicator: DesktopModeVisualIndicator + @Mock lateinit var recentTasksController: RecentTasksController private lateinit var mockitoSession: StaticMockitoSession private lateinit var controller: DesktopTasksController @@ -233,6 +239,7 @@ class DesktopTasksControllerTest : ShellTestCase() { multiInstanceHelper, shellExecutor, Optional.of(desktopTasksLimiter), + recentTasksController ) } @@ -622,7 +629,7 @@ class DesktopTasksControllerTest : ShellTestCase() { controller.moveToDesktop(task) val wct = getLatestMoveToDesktopWct() assertThat(wct.changes[task.token.asBinder()]?.windowingMode) - .isEqualTo(WINDOWING_MODE_FREEFORM) + .isEqualTo(WINDOWING_MODE_FREEFORM) } @Test @@ -643,14 +650,17 @@ class DesktopTasksControllerTest : ShellTestCase() { } @Test - fun moveToDesktop_deviceNotSupported_doesNothing() { - val task = setUpFullscreenTask() + fun moveToDesktop_nonRunningTask_launchesInFreeform() { + whenever(shellTaskOrganizer.getRunningTaskInfo(anyInt())).thenReturn(null) - // Simulate non compatible device - doReturn(false).`when` { DesktopModeStatus.isDesktopModeSupported(any()) } + val task = createTaskInfo(1) - controller.moveToDesktop(task) - verifyWCTNotExecuted() + whenever(recentTasksController.findTaskInBackground(anyInt())).thenReturn(task) + + controller.moveToDesktop(task.taskId) + with(getLatestMoveToDesktopWct()){ + assertLaunchTaskAt(0, task.taskId, WINDOWING_MODE_FREEFORM) + } } @Test @@ -666,6 +676,17 @@ class DesktopTasksControllerTest : ShellTestCase() { } @Test + fun moveToDesktop_deviceNotSupported_doesNothing() { + val task = setUpFullscreenTask() + + // Simulate non compatible device + doReturn(false).`when` { DesktopModeStatus.isDesktopModeSupported(any()) } + + controller.moveToDesktop(task) + verifyWCTNotExecuted() + } + + @Test fun moveToDesktop_deviceNotSupported_deviceRestrictionsOverridden_taskIsMovedToDesktop() { val task = setUpFullscreenTask() @@ -1834,6 +1855,20 @@ private fun WindowContainerTransaction.assertPendingIntentAt(index: Int, intent: assertThat(op.pendingIntent?.intent?.component).isEqualTo(intent.component) } +private fun WindowContainerTransaction.assertLaunchTaskAt( + index: Int, + taskId: Int, + windowingMode: Int +) { + val keyLaunchWindowingMode = "android.activity.windowingMode" + + assertIndexInBounds(index) + val op = hierarchyOps[index] + assertThat(op.type).isEqualTo(HIERARCHY_OP_TYPE_LAUNCH_TASK) + assertThat(op.launchOptions?.getInt(LAUNCH_KEY_TASK_ID)).isEqualTo(taskId) + assertThat(op.launchOptions?.getInt(keyLaunchWindowingMode, WINDOWING_MODE_UNDEFINED)) + .isEqualTo(windowingMode) +} private fun WindowContainerTransaction?.anyDensityConfigChange( token: WindowContainerToken ): Boolean { @@ -1841,3 +1876,7 @@ private fun WindowContainerTransaction?.anyDensityConfigChange( change.key == token.asBinder() && ((change.value.configSetMask and CONFIG_DENSITY) != 0) } ?: false } +private fun createTaskInfo(id: Int) = RecentTaskInfo().apply { + taskId = id + token = WindowContainerToken(mock(IWindowContainerToken::class.java)) +} diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java index 679e8a1b95e6..5672cd54e369 100644 --- a/media/java/android/media/MediaRouter2.java +++ b/media/java/android/media/MediaRouter2.java @@ -681,8 +681,19 @@ public final class MediaRouter2 { /** * Registers a callback to discover routes and to receive events when they change. * + * <p>Clients can register multiple callbacks, as long as the {@link RouteCallback} instances + * are different. Each callback can provide a unique {@link RouteDiscoveryPreference preference} + * and will only receive updates related to that set preference. + * * <p>If the specified callback is already registered, its registration will be updated for the * given {@link Executor executor} and {@link RouteDiscoveryPreference discovery preference}. + * + * <p>{@link #getInstance(Context) Local routers} must register a route callback to register in + * the system and start receiving updates. Otherwise, all operations will be no-ops. + * + * <p>Any discovery preference passed by a {@link #getInstance(Context, String) proxy router} + * will be ignored and will receive route updates based on the preference set by its matching + * local router. */ public void registerRouteCallback( @NonNull @CallbackExecutor Executor executor, diff --git a/media/tests/MediaRouter/Android.bp b/media/tests/MediaRouter/Android.bp index 61b18c88e734..d21cb9319885 100644 --- a/media/tests/MediaRouter/Android.bp +++ b/media/tests/MediaRouter/Android.bp @@ -9,6 +9,7 @@ package { android_test { name: "mediaroutertest", + team: "trendy_team_android_media_solutions", srcs: ["**/*.java"], diff --git a/packages/InputDevices/res/values-ar/strings.xml b/packages/InputDevices/res/values-ar/strings.xml index c5be20840384..fe8f59c45d30 100644 --- a/packages/InputDevices/res/values-ar/strings.xml +++ b/packages/InputDevices/res/values-ar/strings.xml @@ -52,8 +52,6 @@ <string name="keyboard_layout_georgian" msgid="4596185456863747454">"الجورجية"</string> <string name="keyboard_layout_thai_kedmanee" msgid="6637147314580760938">"التايلاندية (Kedmanee)"</string> <string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"التايلاندية (Pattachote)"</string> - <!-- no translation found for keyboard_layout_serbian_latin (3128791759390046571) --> - <skip /> - <!-- no translation found for keyboard_layout_montenegrin_latin (1467832503378949945) --> - <skip /> + <string name="keyboard_layout_serbian_latin" msgid="3128791759390046571">"الصربية (اللاتينية)"</string> + <string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"لغة الجبل الأسود (اللاتينية)"</string> </resources> diff --git a/packages/InputDevices/res/values-be/strings.xml b/packages/InputDevices/res/values-be/strings.xml index 1b6491aec773..697ab632aef9 100644 --- a/packages/InputDevices/res/values-be/strings.xml +++ b/packages/InputDevices/res/values-be/strings.xml @@ -52,8 +52,6 @@ <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Грузінская"</string> <string name="keyboard_layout_thai_kedmanee" msgid="6637147314580760938">"Тайская (Kedmanee)"</string> <string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"Тайская (Патачотэ)"</string> - <!-- no translation found for keyboard_layout_serbian_latin (3128791759390046571) --> - <skip /> - <!-- no translation found for keyboard_layout_montenegrin_latin (1467832503378949945) --> - <skip /> + <string name="keyboard_layout_serbian_latin" msgid="3128791759390046571">"Сербская (лацініца)"</string> + <string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Чарнагорская (лацініца)"</string> </resources> diff --git a/packages/InputDevices/res/values-el/strings.xml b/packages/InputDevices/res/values-el/strings.xml index 78677b3093e3..fb34edd476eb 100644 --- a/packages/InputDevices/res/values-el/strings.xml +++ b/packages/InputDevices/res/values-el/strings.xml @@ -52,8 +52,6 @@ <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Γεωργιανά"</string> <string name="keyboard_layout_thai_kedmanee" msgid="6637147314580760938">"Ταϊλανδικά (Kedmanee)"</string> <string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"Ταϊλανδικά (Pattachote)"</string> - <!-- no translation found for keyboard_layout_serbian_latin (3128791759390046571) --> - <skip /> - <!-- no translation found for keyboard_layout_montenegrin_latin (1467832503378949945) --> - <skip /> + <string name="keyboard_layout_serbian_latin" msgid="3128791759390046571">"Σερβικά (Λατινικά)"</string> + <string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Μαυροβουνιακά (Λατινικά)"</string> </resources> diff --git a/packages/InputDevices/res/values-es/strings.xml b/packages/InputDevices/res/values-es/strings.xml index 5c40ca824d83..39905de11fc0 100644 --- a/packages/InputDevices/res/values-es/strings.xml +++ b/packages/InputDevices/res/values-es/strings.xml @@ -52,8 +52,6 @@ <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Georgiano"</string> <string name="keyboard_layout_thai_kedmanee" msgid="6637147314580760938">"Tailandés (Kedmanee)"</string> <string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"Tailandés (Pattachote)"</string> - <!-- no translation found for keyboard_layout_serbian_latin (3128791759390046571) --> - <skip /> - <!-- no translation found for keyboard_layout_montenegrin_latin (1467832503378949945) --> - <skip /> + <string name="keyboard_layout_serbian_latin" msgid="3128791759390046571">"Serbio (latino)"</string> + <string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Montenegrino (latino)"</string> </resources> diff --git a/packages/InputDevices/res/values-et/strings.xml b/packages/InputDevices/res/values-et/strings.xml index 48eb369b2949..f2d434070fb7 100644 --- a/packages/InputDevices/res/values-et/strings.xml +++ b/packages/InputDevices/res/values-et/strings.xml @@ -52,8 +52,6 @@ <string name="keyboard_layout_georgian" msgid="4596185456863747454">"gruusia"</string> <string name="keyboard_layout_thai_kedmanee" msgid="6637147314580760938">"tai (Kedmanee)"</string> <string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"Tai (Pattachote)"</string> - <!-- no translation found for keyboard_layout_serbian_latin (3128791759390046571) --> - <skip /> - <!-- no translation found for keyboard_layout_montenegrin_latin (1467832503378949945) --> - <skip /> + <string name="keyboard_layout_serbian_latin" msgid="3128791759390046571">"Serbia (ladina)"</string> + <string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Montenegro (ladina)"</string> </resources> diff --git a/packages/InputDevices/res/values-in/strings.xml b/packages/InputDevices/res/values-in/strings.xml index 5ed73dd89d57..d4f024ab3fa2 100644 --- a/packages/InputDevices/res/values-in/strings.xml +++ b/packages/InputDevices/res/values-in/strings.xml @@ -52,8 +52,6 @@ <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Georgia"</string> <string name="keyboard_layout_thai_kedmanee" msgid="6637147314580760938">"Thai (Kedmanee)"</string> <string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"Thai (Pattachote)"</string> - <!-- no translation found for keyboard_layout_serbian_latin (3128791759390046571) --> - <skip /> - <!-- no translation found for keyboard_layout_montenegrin_latin (1467832503378949945) --> - <skip /> + <string name="keyboard_layout_serbian_latin" msgid="3128791759390046571">"Serbia (Latin)"</string> + <string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Montenegro (Latin)"</string> </resources> diff --git a/packages/InputDevices/res/values-is/strings.xml b/packages/InputDevices/res/values-is/strings.xml index 12bdf3d444cb..680c4e303af7 100644 --- a/packages/InputDevices/res/values-is/strings.xml +++ b/packages/InputDevices/res/values-is/strings.xml @@ -52,8 +52,6 @@ <string name="keyboard_layout_georgian" msgid="4596185456863747454">"georgíska"</string> <string name="keyboard_layout_thai_kedmanee" msgid="6637147314580760938">"Taílenskt (Kedmanee)"</string> <string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"Taílenskt (Pattachote)"</string> - <!-- no translation found for keyboard_layout_serbian_latin (3128791759390046571) --> - <skip /> - <!-- no translation found for keyboard_layout_montenegrin_latin (1467832503378949945) --> - <skip /> + <string name="keyboard_layout_serbian_latin" msgid="3128791759390046571">"Serbneska (latneskt)"</string> + <string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Svartfellska (latneskt)"</string> </resources> diff --git a/packages/InputDevices/res/values-km/strings.xml b/packages/InputDevices/res/values-km/strings.xml index abf55515f7b7..b8571ec0a8f2 100644 --- a/packages/InputDevices/res/values-km/strings.xml +++ b/packages/InputDevices/res/values-km/strings.xml @@ -52,8 +52,6 @@ <string name="keyboard_layout_georgian" msgid="4596185456863747454">"ហ្សកហ្ស៊ី"</string> <string name="keyboard_layout_thai_kedmanee" msgid="6637147314580760938">"ថៃ (Kedmanee)"</string> <string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"ថៃ (ប៉ាតាឈោត)"</string> - <!-- no translation found for keyboard_layout_serbian_latin (3128791759390046571) --> - <skip /> - <!-- no translation found for keyboard_layout_montenegrin_latin (1467832503378949945) --> - <skip /> + <string name="keyboard_layout_serbian_latin" msgid="3128791759390046571">"ស៊ែប៊ី (ឡាតាំង)"</string> + <string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"ម៉ុងតេណេហ្គ្រោ (ឡាតាំង)"</string> </resources> diff --git a/packages/InputDevices/res/values-lt/strings.xml b/packages/InputDevices/res/values-lt/strings.xml index ac2a689ec5e1..b9a3e209e578 100644 --- a/packages/InputDevices/res/values-lt/strings.xml +++ b/packages/InputDevices/res/values-lt/strings.xml @@ -52,8 +52,6 @@ <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Gruzinų"</string> <string name="keyboard_layout_thai_kedmanee" msgid="6637147314580760938">"Tajų („Kedmanee“)"</string> <string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"Tajų („Pattachote“)"</string> - <!-- no translation found for keyboard_layout_serbian_latin (3128791759390046571) --> - <skip /> - <!-- no translation found for keyboard_layout_montenegrin_latin (1467832503378949945) --> - <skip /> + <string name="keyboard_layout_serbian_latin" msgid="3128791759390046571">"Serbų (lotynų rašmenys)"</string> + <string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Juodkalniečių (lotynų rašmenys)"</string> </resources> diff --git a/packages/InputDevices/res/values-mn/strings.xml b/packages/InputDevices/res/values-mn/strings.xml index 51f1a1405509..2490d81923e6 100644 --- a/packages/InputDevices/res/values-mn/strings.xml +++ b/packages/InputDevices/res/values-mn/strings.xml @@ -52,8 +52,6 @@ <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Гүрж"</string> <string name="keyboard_layout_thai_kedmanee" msgid="6637147314580760938">"Тай (кедмани)"</string> <string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"Тай (паттачоте)"</string> - <!-- no translation found for keyboard_layout_serbian_latin (3128791759390046571) --> - <skip /> - <!-- no translation found for keyboard_layout_montenegrin_latin (1467832503378949945) --> - <skip /> + <string name="keyboard_layout_serbian_latin" msgid="3128791759390046571">"Серби (латин)"</string> + <string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Монтенегро (латин)"</string> </resources> diff --git a/packages/InputDevices/res/values-my/strings.xml b/packages/InputDevices/res/values-my/strings.xml index 009a6c64fbd6..051024024049 100644 --- a/packages/InputDevices/res/values-my/strings.xml +++ b/packages/InputDevices/res/values-my/strings.xml @@ -52,8 +52,6 @@ <string name="keyboard_layout_georgian" msgid="4596185456863747454">"ဂျော်ဂျီယာ"</string> <string name="keyboard_layout_thai_kedmanee" msgid="6637147314580760938">"ထိုင်း (ကတ်မနီး)"</string> <string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"ထိုင်း (ပတ်တာချုတ်)"</string> - <!-- no translation found for keyboard_layout_serbian_latin (3128791759390046571) --> - <skip /> - <!-- no translation found for keyboard_layout_montenegrin_latin (1467832503378949945) --> - <skip /> + <string name="keyboard_layout_serbian_latin" msgid="3128791759390046571">"ဆားဘီးယား (လက်တင်)"</string> + <string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"မွန်တီနီဂရင်း (လက်တင်)"</string> </resources> diff --git a/packages/InputDevices/res/values-nl/strings.xml b/packages/InputDevices/res/values-nl/strings.xml index 7fe2153e18c3..1893704ea19f 100644 --- a/packages/InputDevices/res/values-nl/strings.xml +++ b/packages/InputDevices/res/values-nl/strings.xml @@ -52,8 +52,6 @@ <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Georgisch"</string> <string name="keyboard_layout_thai_kedmanee" msgid="6637147314580760938">"Thai (Kedmanee)"</string> <string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"Thai (Pattachote)"</string> - <!-- no translation found for keyboard_layout_serbian_latin (3128791759390046571) --> - <skip /> - <!-- no translation found for keyboard_layout_montenegrin_latin (1467832503378949945) --> - <skip /> + <string name="keyboard_layout_serbian_latin" msgid="3128791759390046571">"Servisch (Latijns)"</string> + <string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Montenegrijns (Latijns)"</string> </resources> diff --git a/packages/InputDevices/res/values-pl/strings.xml b/packages/InputDevices/res/values-pl/strings.xml index c44cab5c82be..b76c0fec702f 100644 --- a/packages/InputDevices/res/values-pl/strings.xml +++ b/packages/InputDevices/res/values-pl/strings.xml @@ -52,8 +52,6 @@ <string name="keyboard_layout_georgian" msgid="4596185456863747454">"gruziński"</string> <string name="keyboard_layout_thai_kedmanee" msgid="6637147314580760938">"tajski (Kedmanee)"</string> <string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"tajski (Pattachote)"</string> - <!-- no translation found for keyboard_layout_serbian_latin (3128791759390046571) --> - <skip /> - <!-- no translation found for keyboard_layout_montenegrin_latin (1467832503378949945) --> - <skip /> + <string name="keyboard_layout_serbian_latin" msgid="3128791759390046571">"serbski (alfabet łaciński)"</string> + <string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"czarnogórski (alfabet łaciński)"</string> </resources> diff --git a/packages/InputDevices/res/values-uz/strings.xml b/packages/InputDevices/res/values-uz/strings.xml index 7717909fdc5d..0e80d71ba56a 100644 --- a/packages/InputDevices/res/values-uz/strings.xml +++ b/packages/InputDevices/res/values-uz/strings.xml @@ -52,8 +52,6 @@ <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Gruzin"</string> <string name="keyboard_layout_thai_kedmanee" msgid="6637147314580760938">"Tay (Kedmanee)"</string> <string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"Tay (Pattachote)"</string> - <!-- no translation found for keyboard_layout_serbian_latin (3128791759390046571) --> - <skip /> - <!-- no translation found for keyboard_layout_montenegrin_latin (1467832503378949945) --> - <skip /> + <string name="keyboard_layout_serbian_latin" msgid="3128791759390046571">"Serb (lotin)"</string> + <string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Chernogor (lotin)"</string> </resources> diff --git a/packages/InputDevices/res/values-vi/strings.xml b/packages/InputDevices/res/values-vi/strings.xml index 1e3d7e4979d1..5094a29d04c0 100644 --- a/packages/InputDevices/res/values-vi/strings.xml +++ b/packages/InputDevices/res/values-vi/strings.xml @@ -52,8 +52,6 @@ <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Tiếng Georgia"</string> <string name="keyboard_layout_thai_kedmanee" msgid="6637147314580760938">"Tiếng Thái (Kedmanee)"</string> <string name="keyboard_layout_thai_pattachote" msgid="2547992342794252205">"Tiếng Thái (Pattachote)"</string> - <!-- no translation found for keyboard_layout_serbian_latin (3128791759390046571) --> - <skip /> - <!-- no translation found for keyboard_layout_montenegrin_latin (1467832503378949945) --> - <skip /> + <string name="keyboard_layout_serbian_latin" msgid="3128791759390046571">"Tiếng Serbia (Latinh)"</string> + <string name="keyboard_layout_montenegrin_latin" msgid="1467832503378949945">"Tiếng Montenegro (Latinh)"</string> </resources> diff --git a/packages/PrintSpooler/res/values-kk/strings.xml b/packages/PrintSpooler/res/values-kk/strings.xml index 939e1b43d2bc..1755c7a313e4 100644 --- a/packages/PrintSpooler/res/values-kk/strings.xml +++ b/packages/PrintSpooler/res/values-kk/strings.xml @@ -74,7 +74,7 @@ <string name="enabled_services_title" msgid="7036986099096582296">"Қосылған қызметтер"</string> <string name="recommended_services_title" msgid="3799434882937956924">"Ұсынылған қызметтер"</string> <string name="disabled_services_title" msgid="7313253167968363211">"Өшірілген қызметтер"</string> - <string name="all_services_title" msgid="5578662754874906455">"Барлық қызметтер"</string> + <string name="all_services_title" msgid="5578662754874906455">"Барлық қызмет"</string> <plurals name="print_services_recommendation_subtitle" formatted="false" msgid="5678487708807185138"> <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> принтерді табу үшін орнатыңыз</item> <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> принтерді табу үшін орнатыңыз</item> diff --git a/packages/SettingsLib/ProfileSelector/res/values-cs/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-cs/strings.xml index d50fc9a7da88..3e5f52696916 100644 --- a/packages/SettingsLib/ProfileSelector/res/values-cs/strings.xml +++ b/packages/SettingsLib/ProfileSelector/res/values-cs/strings.xml @@ -18,6 +18,6 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_category_personal" msgid="1142302328104700620">"Osobní"</string> - <string name="settingslib_category_work" msgid="4867750733682444676">"Prácovní"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"Pracovní"</string> <string name="settingslib_category_private" msgid="5039276873477591386">"Soukromé"</string> </resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-el/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-el/strings.xml index 628388d696b8..b1bc69ce7a41 100644 --- a/packages/SettingsLib/ProfileSelector/res/values-el/strings.xml +++ b/packages/SettingsLib/ProfileSelector/res/values-el/strings.xml @@ -19,5 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_category_personal" msgid="1142302328104700620">"Προσωπικά"</string> <string name="settingslib_category_work" msgid="4867750733682444676">"Εργασία"</string> - <string name="settingslib_category_private" msgid="5039276873477591386">"Ιδιωτικό"</string> + <string name="settingslib_category_private" msgid="5039276873477591386">"Ιδιωτικός"</string> </resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-is/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-is/strings.xml index 75668e8c55ff..b7aa61bf8566 100644 --- a/packages/SettingsLib/ProfileSelector/res/values-is/strings.xml +++ b/packages/SettingsLib/ProfileSelector/res/values-is/strings.xml @@ -19,5 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_category_personal" msgid="1142302328104700620">"Persónulegt"</string> <string name="settingslib_category_work" msgid="4867750733682444676">"Vinna"</string> - <string name="settingslib_category_private" msgid="5039276873477591386">"Lokað"</string> + <string name="settingslib_category_private" msgid="5039276873477591386">"Laynirými"</string> </resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-ja/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-ja/strings.xml index 21419e65e408..c9faa3c353c5 100644 --- a/packages/SettingsLib/ProfileSelector/res/values-ja/strings.xml +++ b/packages/SettingsLib/ProfileSelector/res/values-ja/strings.xml @@ -19,5 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_category_personal" msgid="1142302328104700620">"個人用"</string> <string name="settingslib_category_work" msgid="4867750733682444676">"仕事用"</string> - <string name="settingslib_category_private" msgid="5039276873477591386">"非公開"</string> + <string name="settingslib_category_private" msgid="5039276873477591386">"プライベート"</string> </resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-mk/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-mk/strings.xml index 07cf9c71e5f3..e8c2bf563c40 100644 --- a/packages/SettingsLib/ProfileSelector/res/values-mk/strings.xml +++ b/packages/SettingsLib/ProfileSelector/res/values-mk/strings.xml @@ -19,5 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_category_personal" msgid="1142302328104700620">"Лични"</string> <string name="settingslib_category_work" msgid="4867750733682444676">"Работа"</string> - <string name="settingslib_category_private" msgid="5039276873477591386">"Приватен"</string> + <string name="settingslib_category_private" msgid="5039276873477591386">"Приватно"</string> </resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-pa/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-pa/strings.xml index e1e68c758a15..1e4abc1e2025 100644 --- a/packages/SettingsLib/ProfileSelector/res/values-pa/strings.xml +++ b/packages/SettingsLib/ProfileSelector/res/values-pa/strings.xml @@ -18,6 +18,6 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_category_personal" msgid="1142302328104700620">"ਨਿੱਜੀ"</string> - <string name="settingslib_category_work" msgid="4867750733682444676">"ਕਾਰਜ"</string> + <string name="settingslib_category_work" msgid="4867750733682444676">"ਕੰਮ ਸੰਬੰਧੀ"</string> <string name="settingslib_category_private" msgid="5039276873477591386">"ਪ੍ਰਾਈਵੇਟ"</string> </resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-ru/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-ru/strings.xml index ee4212f82ba4..e0b1471c0859 100644 --- a/packages/SettingsLib/ProfileSelector/res/values-ru/strings.xml +++ b/packages/SettingsLib/ProfileSelector/res/values-ru/strings.xml @@ -19,5 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_category_personal" msgid="1142302328104700620">"Личный профиль"</string> <string name="settingslib_category_work" msgid="4867750733682444676">"Рабочий профиль"</string> - <string name="settingslib_category_private" msgid="5039276873477591386">"Личное"</string> + <string name="settingslib_category_private" msgid="5039276873477591386">"Частный профиль"</string> </resources> diff --git a/packages/SettingsLib/ProfileSelector/res/values-tr/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-tr/strings.xml index 59f21c8c8ba6..e4e2bdcc44f0 100644 --- a/packages/SettingsLib/ProfileSelector/res/values-tr/strings.xml +++ b/packages/SettingsLib/ProfileSelector/res/values-tr/strings.xml @@ -19,5 +19,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="settingslib_category_personal" msgid="1142302328104700620">"Kişisel"</string> <string name="settingslib_category_work" msgid="4867750733682444676">"İş"</string> - <string name="settingslib_category_private" msgid="5039276873477591386">"Gizli"</string> + <string name="settingslib_category_private" msgid="5039276873477591386">"Özel"</string> </resources> diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml index 3f39d4d0e962..d02164704884 100644 --- a/packages/SettingsLib/res/values-as/strings.xml +++ b/packages/SettingsLib/res/values-as/strings.xml @@ -237,7 +237,7 @@ <string name="choose_profile" msgid="343803890897657450">"প্ৰ’ফাইল বাছনি কৰক"</string> <string name="category_personal" msgid="6236798763159385225">"ব্যক্তিগত"</string> <string name="category_work" msgid="4014193632325996115">"কৰ্মস্থান-সম্পৰ্কীয়"</string> - <string name="category_private" msgid="4244892185452788977">"গোপনীয়"</string> + <string name="category_private" msgid="4244892185452788977">"প্ৰাইভেট"</string> <string name="category_clone" msgid="1554511758987195974">"ক্ল’ন"</string> <string name="development_settings_title" msgid="140296922921597393">"বিকাশকৰ্তাৰ বিকল্পসমূহ"</string> <string name="development_settings_enable" msgid="4285094651288242183">"বিকাশকৰ্তা বিষয়ক বিকল্পসমূহ সক্ষম কৰক"</string> diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml index b9961b9d0d14..1533a1961cc1 100644 --- a/packages/SettingsLib/res/values-bn/strings.xml +++ b/packages/SettingsLib/res/values-bn/strings.xml @@ -237,7 +237,7 @@ <string name="choose_profile" msgid="343803890897657450">"প্রোফাইল বেছে নিন"</string> <string name="category_personal" msgid="6236798763159385225">"ব্যক্তিগত"</string> <string name="category_work" msgid="4014193632325996115">"অফিস"</string> - <string name="category_private" msgid="4244892185452788977">"ব্যক্তিগত"</string> + <string name="category_private" msgid="4244892185452788977">"প্রাইভেট"</string> <string name="category_clone" msgid="1554511758987195974">"ক্লোন"</string> <string name="development_settings_title" msgid="140296922921597393">"ডেভেলপার বিকল্প"</string> <string name="development_settings_enable" msgid="4285094651288242183">"ডেভেলপার বিকল্প সক্ষম করুন"</string> diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml index 240b0f0802f0..194c616b8ca5 100644 --- a/packages/SettingsLib/res/values-cs/strings.xml +++ b/packages/SettingsLib/res/values-cs/strings.xml @@ -237,7 +237,7 @@ <string name="choose_profile" msgid="343803890897657450">"Vyberte profil"</string> <string name="category_personal" msgid="6236798763159385225">"Osobní"</string> <string name="category_work" msgid="4014193632325996115">"Pracovní"</string> - <string name="category_private" msgid="4244892185452788977">"Soukromé"</string> + <string name="category_private" msgid="4244892185452788977">"Soukromý"</string> <string name="category_clone" msgid="1554511758987195974">"Klon"</string> <string name="development_settings_title" msgid="140296922921597393">"Pro vývojáře"</string> <string name="development_settings_enable" msgid="4285094651288242183">"Aktivovat možnosti pro vývojáře"</string> diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml index f549ae2bc197..94d4297d7f57 100644 --- a/packages/SettingsLib/res/values-el/strings.xml +++ b/packages/SettingsLib/res/values-el/strings.xml @@ -235,9 +235,9 @@ <item msgid="6946761421234586000">"400%"</item> </string-array> <string name="choose_profile" msgid="343803890897657450">"Επιλογή προφίλ"</string> - <string name="category_personal" msgid="6236798763159385225">"Προσωπικό"</string> + <string name="category_personal" msgid="6236798763159385225">"Προσωπικός"</string> <string name="category_work" msgid="4014193632325996115">"Εργασίας"</string> - <string name="category_private" msgid="4244892185452788977">"Ιδιωτικό"</string> + <string name="category_private" msgid="4244892185452788977">"Ιδιωτικός"</string> <string name="category_clone" msgid="1554511758987195974">"Κλωνοποίηση"</string> <string name="development_settings_title" msgid="140296922921597393">"Επιλογές για προγραμματιστές"</string> <string name="development_settings_enable" msgid="4285094651288242183">"Ενεργοποίηση επιλογών για προγραμματιστές"</string> diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml index 8f832162be3a..f66499fba432 100644 --- a/packages/SettingsLib/res/values-hi/strings.xml +++ b/packages/SettingsLib/res/values-hi/strings.xml @@ -708,7 +708,7 @@ <string name="physical_keyboard_title" msgid="4811935435315835220">"फ़िज़िकल कीबोर्ड"</string> <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"कीबोर्ड का लेआउट चुनें"</string> <string name="keyboard_layout_default_label" msgid="1997292217218546957">"डिफ़ॉल्ट"</string> - <string name="turn_screen_on_title" msgid="2662312432042116026">"इन ऐप के पास स्क्रीन को चालू करने का कंट्रोल है"</string> + <string name="turn_screen_on_title" msgid="2662312432042116026">"इस ऐप के पास स्क्रीन को चालू करने का कंट्रोल है"</string> <string name="allow_turn_screen_on" msgid="6194845766392742639">"स्क्रीन चालू करने की अनुमति दें"</string> <string name="allow_turn_screen_on_description" msgid="43834403291575164">"ऐप्लिकेशन को स्क्रीन चालू करने की अनुमति दें. ऐसा करने पर, ऐप्लिकेशन आपकी अनुमति लिए बिना भी, जब चाहे स्क्रीन चालू कर सकता है."</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"<xliff:g id="APP_NAME">%1$s</xliff:g> पर ब्रॉडकास्ट करना रोकें?"</string> diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml index 66be184efe8b..47cdcca2bbe4 100644 --- a/packages/SettingsLib/res/values-is/strings.xml +++ b/packages/SettingsLib/res/values-is/strings.xml @@ -235,7 +235,7 @@ <item msgid="6946761421234586000">"400%"</item> </string-array> <string name="choose_profile" msgid="343803890897657450">"Veldu snið"</string> - <string name="category_personal" msgid="6236798763159385225">"Persónulegt"</string> + <string name="category_personal" msgid="6236798763159385225">"Einkasnið"</string> <string name="category_work" msgid="4014193632325996115">"Vinna"</string> <string name="category_private" msgid="4244892185452788977">"Lokað"</string> <string name="category_clone" msgid="1554511758987195974">"Afrit"</string> diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml index 630dd649d3f7..b2456d3f9b53 100644 --- a/packages/SettingsLib/res/values-mk/strings.xml +++ b/packages/SettingsLib/res/values-mk/strings.xml @@ -235,9 +235,9 @@ <item msgid="6946761421234586000">"400 %"</item> </string-array> <string name="choose_profile" msgid="343803890897657450">"Изберете профил"</string> - <string name="category_personal" msgid="6236798763159385225">"Личен"</string> + <string name="category_personal" msgid="6236798763159385225">"Лично"</string> <string name="category_work" msgid="4014193632325996115">"Работа"</string> - <string name="category_private" msgid="4244892185452788977">"Приватен"</string> + <string name="category_private" msgid="4244892185452788977">"Приватно"</string> <string name="category_clone" msgid="1554511758987195974">"Клон"</string> <string name="development_settings_title" msgid="140296922921597393">"Програмерски опции"</string> <string name="development_settings_enable" msgid="4285094651288242183">"Овозможете ги програмерските опции"</string> diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml index 04c8a4080c5a..c4677beb6e11 100644 --- a/packages/SettingsLib/res/values-sv/strings.xml +++ b/packages/SettingsLib/res/values-sv/strings.xml @@ -235,7 +235,7 @@ <item msgid="6946761421234586000">"400 %"</item> </string-array> <string name="choose_profile" msgid="343803890897657450">"Välj profil"</string> - <string name="category_personal" msgid="6236798763159385225">"Privat"</string> + <string name="category_personal" msgid="6236798763159385225">"Personlig"</string> <string name="category_work" msgid="4014193632325996115">"Jobb"</string> <string name="category_private" msgid="4244892185452788977">"Privat"</string> <string name="category_clone" msgid="1554511758987195974">"Klon"</string> diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml index afda7cbd5ade..014ba26e2f3b 100644 --- a/packages/SettingsLib/res/values-th/strings.xml +++ b/packages/SettingsLib/res/values-th/strings.xml @@ -235,7 +235,7 @@ <item msgid="6946761421234586000">"400%"</item> </string-array> <string name="choose_profile" msgid="343803890897657450">"เลือกโปรไฟล์"</string> - <string name="category_personal" msgid="6236798763159385225">"ส่วนตัว"</string> + <string name="category_personal" msgid="6236798763159385225">"ส่วนบุคคล"</string> <string name="category_work" msgid="4014193632325996115">"งาน"</string> <string name="category_private" msgid="4244892185452788977">"ส่วนตัว"</string> <string name="category_clone" msgid="1554511758987195974">"โคลน"</string> diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml index c79db5fc2933..6aea659292c3 100644 --- a/packages/SettingsLib/res/values-tr/strings.xml +++ b/packages/SettingsLib/res/values-tr/strings.xml @@ -237,7 +237,7 @@ <string name="choose_profile" msgid="343803890897657450">"Profil seçin"</string> <string name="category_personal" msgid="6236798763159385225">"Kişisel"</string> <string name="category_work" msgid="4014193632325996115">"İş"</string> - <string name="category_private" msgid="4244892185452788977">"Gizli"</string> + <string name="category_private" msgid="4244892185452788977">"Özel"</string> <string name="category_clone" msgid="1554511758987195974">"Klon"</string> <string name="development_settings_title" msgid="140296922921597393">"Geliştirici seçenekleri"</string> <string name="development_settings_enable" msgid="4285094651288242183">"Geliştirici seçeneklerini etkinleştir"</string> diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java index 04922d6e2c99..c8992c344b2d 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java @@ -64,6 +64,7 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; +import java.io.InputStream; import java.io.IOException; import java.io.PrintWriter; import java.nio.file.Files; @@ -85,13 +86,13 @@ import java.util.concurrent.CountDownLatch; // FOR ACONFIGD TEST MISSION AND ROLLOUT import java.io.DataInputStream; import java.io.DataOutputStream; -import android.net.LocalSocketAddress; -import android.net.LocalSocket; import android.util.proto.ProtoInputStream; import android.aconfigd.Aconfigd.StorageRequestMessage; import android.aconfigd.Aconfigd.StorageRequestMessages; import android.aconfigd.Aconfigd.StorageReturnMessage; import android.aconfigd.Aconfigd.StorageReturnMessages; +import android.aconfigd.AconfigdClientSocket; +import android.aconfigd.AconfigdFlagInfo; import android.aconfigd.AconfigdJavaUtils; import static com.android.aconfig_new_storage.Flags.enableAconfigStorageDaemon; /** @@ -265,6 +266,10 @@ final class SettingsState { @NonNull private Map<String, Map<String, String>> mNamespaceDefaults; + // TOBO(b/312444587): remove the comparison logic after Test Mission 2. + @NonNull + private Map<String, AconfigdFlagInfo> mAconfigDefaultFlags; + public static final int SETTINGS_TYPE_GLOBAL = 0; public static final int SETTINGS_TYPE_SYSTEM = 1; public static final int SETTINGS_TYPE_SECURE = 2; @@ -334,8 +339,13 @@ final class SettingsState { + settingTypeToString(getTypeFromKey(key)) + "]"; } - public SettingsState(Context context, Object lock, File file, int key, - int maxBytesPerAppPackage, Looper looper) { + public SettingsState( + Context context, + Object lock, + File file, + int key, + int maxBytesPerAppPackage, + Looper looper) { // It is important that we use the same lock as the settings provider // to ensure multiple mutations on this state are atomically persisted // as the async persistence should be blocked while we make changes. @@ -353,12 +363,15 @@ final class SettingsState { mPackageToMemoryUsage = null; } - mHistoricalOperations = Build.IS_DEBUGGABLE - ? new ArrayList<>(HISTORICAL_OPERATION_COUNT) : null; + mHistoricalOperations = + Build.IS_DEBUGGABLE ? new ArrayList<>(HISTORICAL_OPERATION_COUNT) : null; mNamespaceDefaults = new HashMap<>(); + mAconfigDefaultFlags = new HashMap<>(); ProtoOutputStream requests = null; + Map<String, AconfigdFlagInfo> aconfigFlagMap = new HashMap<>(); + synchronized (mLock) { readStateSyncLocked(); @@ -375,39 +388,114 @@ final class SettingsState { } } + if (enableAconfigStorageDaemon()) { + if (isConfigSettingsKey(mKey)) { + aconfigFlagMap = getAllAconfigFlagsFromSettings(); + } + } + if (isConfigSettingsKey(mKey)) { - requests = handleBulkSyncToNewStorage(); + requests = handleBulkSyncToNewStorage(aconfigFlagMap); } } - if (requests != null) { - LocalSocket client = new LocalSocket(); - try{ - client.connect(new LocalSocketAddress( - "aconfigd", LocalSocketAddress.Namespace.RESERVED)); - Slog.d(LOG_TAG, "connected to aconfigd socket"); - } catch (IOException ioe) { - Slog.e(LOG_TAG, "failed to connect to aconfigd socket", ioe); - return; + if (enableAconfigStorageDaemon()) { + if (isConfigSettingsKey(mKey)){ + AconfigdClientSocket localSocket = AconfigdJavaUtils.getAconfigdClientSocket(); + if (requests != null) { + InputStream res = localSocket.send(requests.getBytes()); + if (res == null) { + Slog.w(LOG_TAG, "Bulk sync request to acongid failed."); + } + } + // TOBO(b/312444587): remove the comparison logic after Test Mission 2. + if (mSettings.get("aconfigd_marker/bulk_synced").value.equals("true") + && requests == null) { + Map<String, AconfigdFlagInfo> aconfigdFlagMap = + AconfigdJavaUtils.listFlagsValueInNewStorage(localSocket); + compareFlagValueInNewStorage( + aconfigFlagMap, + mAconfigDefaultFlags, + aconfigdFlagMap); + } } - AconfigdJavaUtils.sendAconfigdRequests(client, requests); } } - // TODO(b/341764371): migrate aconfig flag push to GMS core - public static class FlagOverrideToSync { - public String packageName; - public String flagName; - public String flagValue; - public boolean isLocal; + // TOBO(b/312444587): remove the comparison logic after Test Mission 2. + public int compareFlagValueInNewStorage( + Map<String, AconfigdFlagInfo> settingFlagMap, + Map<String, AconfigdFlagInfo> defaultFlagMap, + Map<String, AconfigdFlagInfo> aconfigdFlagMap) { + + // Get all defaults from the default map. The mSettings may not contain + // all flags, since it only contains updated flags. + int diffNum = 0; + for (Map.Entry<String, AconfigdFlagInfo> entry : defaultFlagMap.entrySet()) { + String key = entry.getKey(); + AconfigdFlagInfo flag = entry.getValue(); + if (settingFlagMap.containsKey(key)) { + flag.merge(settingFlagMap.get(key)); + } + + AconfigdFlagInfo aconfigdFlag = aconfigdFlagMap.get(key); + if (aconfigdFlag == null) { + Slog.w(LOG_TAG, String.format("Flag %s is missing from aconfigd", key)); + diffNum++; + continue; + } + String diff = flag.dumpDiff(aconfigdFlag); + if (!diff.isEmpty()) { + Slog.w( + LOG_TAG, + String.format( + "Flag %s is different in Settings and aconfig: %s", key, diff)); + diffNum++; + } + } + + for (String key : aconfigdFlagMap.keySet()) { + if (defaultFlagMap.containsKey(key)) continue; + Slog.w(LOG_TAG, String.format("Flag %s is missing from Settings", key)); + diffNum++; + } + + if (diffNum == 0) { + Slog.i(LOG_TAG, "Settings and new storage have same flags."); + } + return diffNum; + } + + @GuardedBy("mLock") + public Map<String, AconfigdFlagInfo> getAllAconfigFlagsFromSettings() { + Map<String, AconfigdFlagInfo> ret = new HashMap<>(); + int numSettings = mSettings.size(); + int num_requests = 0; + for (int i = 0; i < numSettings; i++) { + String name = mSettings.keyAt(i); + Setting setting = mSettings.valueAt(i); + AconfigdFlagInfo flag = + getFlagOverrideToSync(name, setting.getValue()); + if (flag == null) { + continue; + } + String fullFlagName = flag.getFullFlagName(); + AconfigdFlagInfo prev = ret.putIfAbsent(fullFlagName,flag); + if (prev != null) { + prev.merge(flag); + } + ++num_requests; + } + Slog.i(LOG_TAG, num_requests + " flag override requests created"); + return ret; } // TODO(b/341764371): migrate aconfig flag push to GMS core @VisibleForTesting @GuardedBy("mLock") - public FlagOverrideToSync getFlagOverrideToSync(String name, String value) { + public AconfigdFlagInfo getFlagOverrideToSync(String name, String value) { int slashIdx = name.indexOf("/"); - if (slashIdx <= 0 || slashIdx >= name.length()-1) { + if (slashIdx <= 0 || slashIdx >= name.length() - 1) { Slog.e(LOG_TAG, "invalid flag name " + name); return null; } @@ -430,8 +518,9 @@ final class SettingsState { } String aconfigName = namespace + "/" + fullFlagName; - boolean isAconfig = mNamespaceDefaults.containsKey(namespace) - && mNamespaceDefaults.get(namespace).containsKey(aconfigName); + boolean isAconfig = + mNamespaceDefaults.containsKey(namespace) + && mNamespaceDefaults.get(namespace).containsKey(aconfigName); if (!isAconfig) { return null; } @@ -443,25 +532,30 @@ final class SettingsState { return null; } - FlagOverrideToSync flag = new FlagOverrideToSync(); - flag.packageName = fullFlagName.substring(0, dotIdx); - flag.flagName = fullFlagName.substring(dotIdx + 1); - flag.isLocal = isLocal; - flag.flagValue = value; - return flag; + AconfigdFlagInfo.Builder builder = AconfigdFlagInfo.newBuilder() + .setPackageName(fullFlagName.substring(0, dotIdx)) + .setFlagName(fullFlagName.substring(dotIdx + 1)) + .setDefaultFlagValue(mNamespaceDefaults.get(namespace).get(aconfigName)); + + if (isLocal) { + builder.setHasLocalOverride(isLocal).setBootFlagValue(value).setLocalFlagValue(value); + } else { + builder.setHasServerOverride(true).setServerFlagValue(value).setBootFlagValue(value); + } + return builder.build(); } // TODO(b/341764371): migrate aconfig flag push to GMS core @VisibleForTesting @GuardedBy("mLock") - public ProtoOutputStream handleBulkSyncToNewStorage() { + public ProtoOutputStream handleBulkSyncToNewStorage( + Map<String, AconfigdFlagInfo> aconfigFlagMap) { // get marker or add marker if it does not exist final String bulkSyncMarkerName = new String("aconfigd_marker/bulk_synced"); Setting markerSetting = mSettings.get(bulkSyncMarkerName); if (markerSetting == null) { - markerSetting = new Setting( - bulkSyncMarkerName, "false", false, "aconfig", "aconfig"); + markerSetting = new Setting(bulkSyncMarkerName, "false", false, "aconfig", "aconfig"); mSettings.put(bulkSyncMarkerName, markerSetting); } @@ -479,24 +573,19 @@ final class SettingsState { AconfigdJavaUtils.writeResetStorageRequest(requests); // loop over all settings and add flag override requests - final int numSettings = mSettings.size(); - int num_requests = 0; - for (int i = 0; i < numSettings; i++) { - String name = mSettings.keyAt(i); - Setting setting = mSettings.valueAt(i); - FlagOverrideToSync flag = - getFlagOverrideToSync(name, setting.getValue()); - if (flag == null) { - continue; - } - ++num_requests; + for (AconfigdFlagInfo flag : aconfigFlagMap.values()) { + String value = + flag.getHasLocalOverride() + ? flag.getLocalFlagValue() + : flag.getServerFlagValue(); AconfigdJavaUtils.writeFlagOverrideRequest( - requests, flag.packageName, flag.flagName, flag.flagValue, - flag.isLocal); + requests, + flag.getPackageName(), + flag.getFlagName(), + value, + flag.getHasLocalOverride()); } - Slog.i(LOG_TAG, num_requests + " flag override requests created"); - // mark sync has been done markerSetting.value = "true"; scheduleWriteIfNeededLocked(); @@ -513,14 +602,14 @@ final class SettingsState { return null; } } - } @GuardedBy("mLock") private void loadAconfigDefaultValuesLocked(List<String> filePaths) { for (String fileName : filePaths) { try (FileInputStream inputStream = new FileInputStream(fileName)) { - loadAconfigDefaultValues(inputStream.readAllBytes(), mNamespaceDefaults); + loadAconfigDefaultValues( + inputStream.readAllBytes(), mNamespaceDefaults, mAconfigDefaultFlags); } catch (IOException e) { Slog.e(LOG_TAG, "failed to read protobuf", e); } @@ -566,21 +655,30 @@ final class SettingsState { @VisibleForTesting @GuardedBy("mLock") - public static void loadAconfigDefaultValues(byte[] fileContents, - @NonNull Map<String, Map<String, String>> defaultMap) { + public static void loadAconfigDefaultValues( + byte[] fileContents, + @NonNull Map<String, Map<String, String>> defaultMap, + @NonNull Map<String, AconfigdFlagInfo> flagInfoDefault) { try { - parsed_flags parsedFlags = - parsed_flags.parseFrom(fileContents); + parsed_flags parsedFlags = parsed_flags.parseFrom(fileContents); for (parsed_flag flag : parsedFlags.getParsedFlagList()) { if (!defaultMap.containsKey(flag.getNamespace())) { Map<String, String> defaults = new HashMap<>(); defaultMap.put(flag.getNamespace(), defaults); } - String flagName = flag.getNamespace() - + "/" + flag.getPackage() + "." + flag.getName(); - String flagValue = flag.getState() == flag_state.ENABLED - ? "true" : "false"; + String fullFlagName = flag.getPackage() + "." + flag.getName(); + String flagName = flag.getNamespace() + "/" + fullFlagName; + String flagValue = flag.getState() == flag_state.ENABLED ? "true" : "false"; defaultMap.get(flag.getNamespace()).put(flagName, flagValue); + if (!flagInfoDefault.containsKey(fullFlagName)) { + flagInfoDefault.put( + fullFlagName, + AconfigdFlagInfo.newBuilder() + .setPackageName(flag.getPackage()) + .setFlagName(flag.getName()) + .setDefaultFlagValue(flagValue) + .build()); + } } } catch (IOException e) { Slog.e(LOG_TAG, "failed to parse protobuf", e); @@ -1646,7 +1744,6 @@ final class SettingsState { } } } - mSettings.put(name, new Setting(name, value, defaultValue, packageName, tag, fromSystem, id, isPreservedInRestore)); diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java index 244c8c4d99bc..256b999ca6c5 100644 --- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java +++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java @@ -24,13 +24,13 @@ import static junit.framework.Assert.fail; import android.aconfig.Aconfig; import android.aconfig.Aconfig.parsed_flag; import android.aconfig.Aconfig.parsed_flags; +import android.aconfigd.AconfigdFlagInfo; import android.os.Looper; import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.CheckFlagsRule; import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.util.Xml; import android.util.proto.ProtoOutputStream; -import com.android.providers.settings.SettingsState.FlagOverrideToSync; import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; @@ -145,16 +145,32 @@ public class SettingsStateTest { .setState(Aconfig.flag_state.ENABLED) .setPermission(Aconfig.flag_permission.READ_WRITE)) .build(); + + AconfigdFlagInfo flag1 = AconfigdFlagInfo.newBuilder() + .setPackageName("com.android.flags") + .setFlagName("flag1") + .setDefaultFlagValue("false") + .build(); + AconfigdFlagInfo flag2 = AconfigdFlagInfo.newBuilder() + .setPackageName("com.android.flags") + .setFlagName("flag2") + .setDefaultFlagValue("true") + .build(); + Map<String, AconfigdFlagInfo> flagInfoDefault = new HashMap<>(); synchronized (lock) { Map<String, Map<String, String>> defaults = new HashMap<>(); - settingsState.loadAconfigDefaultValues(flags.toByteArray(), defaults); + settingsState.loadAconfigDefaultValues( + flags.toByteArray(), defaults, flagInfoDefault); Map<String, String> namespaceDefaults = defaults.get("test_namespace"); assertEquals(2, namespaceDefaults.keySet().size()); assertEquals("false", namespaceDefaults.get("test_namespace/com.android.flags.flag1")); assertEquals("true", namespaceDefaults.get("test_namespace/com.android.flags.flag2")); } + + assertEquals(flag1, flagInfoDefault.get(flag1.getFullFlagName())); + assertEquals(flag2, flagInfoDefault.get(flag2.getFullFlagName())); } @Test @@ -165,6 +181,8 @@ public class SettingsStateTest { InstrumentationRegistry.getContext(), lock, mSettingsFile, configKey, SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); + Map<String, AconfigdFlagInfo> flagInfoDefault = new HashMap<>(); + parsed_flags flags = parsed_flags .newBuilder() .addParsedFlag(parsed_flag @@ -177,7 +195,8 @@ public class SettingsStateTest { synchronized (lock) { Map<String, Map<String, String>> defaults = new HashMap<>(); - settingsState.loadAconfigDefaultValues(flags.toByteArray(), defaults); + settingsState.loadAconfigDefaultValues( + flags.toByteArray(), defaults, flagInfoDefault); Map<String, String> namespaceDefaults = defaults.get("test_namespace"); assertEquals(null, namespaceDefaults); @@ -204,10 +223,12 @@ public class SettingsStateTest { .setState(Aconfig.flag_state.DISABLED) .setPermission(Aconfig.flag_permission.READ_WRITE)) .build(); + Map<String, AconfigdFlagInfo> flagInfoDefault = new HashMap<>(); synchronized (lock) { Map<String, Map<String, String>> defaults = new HashMap<>(); - settingsState.loadAconfigDefaultValues(flags.toByteArray(), defaults); + settingsState.loadAconfigDefaultValues( + flags.toByteArray(), defaults, flagInfoDefault); settingsState.addAconfigDefaultValuesFromMap(defaults); settingsState.insertSettingLocked("test_namespace/com.android.flags.flag5", @@ -238,8 +259,10 @@ public class SettingsStateTest { @Test public void testInvalidAconfigProtoDoesNotCrash() { Map<String, Map<String, String>> defaults = new HashMap<>(); + Map<String, AconfigdFlagInfo> flagInfoDefault = new HashMap<>(); SettingsState settingsState = getSettingStateObject(); - settingsState.loadAconfigDefaultValues("invalid protobuf".getBytes(), defaults); + settingsState.loadAconfigDefaultValues( + "invalid protobuf".getBytes(), defaults, flagInfoDefault); } @Test @@ -759,6 +782,8 @@ public class SettingsStateTest { Map<String, String> keyValues = Map.of("test_namespace/com.android.flags.flag3", "true"); + Map<String, AconfigdFlagInfo> flagInfoDefault = new HashMap<>(); + parsed_flags flags = parsed_flags .newBuilder() .addParsedFlag(parsed_flag @@ -774,7 +799,8 @@ public class SettingsStateTest { synchronized (mLock) { settingsState.loadAconfigDefaultValues( - flags.toByteArray(), settingsState.getAconfigDefaultValues()); + flags.toByteArray(), + settingsState.getAconfigDefaultValues(), flagInfoDefault); List<String> updates = settingsState.setSettingsLocked("test_namespace/", keyValues, packageName); assertEquals(1, updates.size()); @@ -840,10 +866,13 @@ public class SettingsStateTest { .setState(Aconfig.flag_state.DISABLED) .setPermission(Aconfig.flag_permission.READ_WRITE)) .build(); + Map<String, AconfigdFlagInfo> flagInfoDefault = new HashMap<>(); synchronized (mLock) { settingsState.loadAconfigDefaultValues( - flags.toByteArray(), settingsState.getAconfigDefaultValues()); + flags.toByteArray(), + settingsState.getAconfigDefaultValues(), + flagInfoDefault); List<String> updates = settingsState.setSettingsLocked("test_namespace/", keyValues, packageName); assertEquals(3, updates.size()); @@ -973,10 +1002,12 @@ public class SettingsStateTest { .setState(Aconfig.flag_state.DISABLED) .setPermission(Aconfig.flag_permission.READ_WRITE)) .build(); + Map<String, AconfigdFlagInfo> flagInfoDefault = new HashMap<>(); synchronized (lock) { Map<String, Map<String, String>> defaults = new HashMap<>(); - settingsState.loadAconfigDefaultValues(flags.toByteArray(), defaults); + settingsState.loadAconfigDefaultValues( + flags.toByteArray(), defaults, flagInfoDefault); Map<String, String> namespaceDefaults = defaults.get("test_namespace"); assertEquals(1, namespaceDefaults.keySet().size()); settingsState.addAconfigDefaultValuesFromMap(defaults); @@ -991,22 +1022,28 @@ public class SettingsStateTest { "some_namespace/some_flag", "false") == null); // server override - FlagOverrideToSync flag = settingsState.getFlagOverrideToSync( + AconfigdFlagInfo flag = settingsState.getFlagOverrideToSync( "test_namespace/com.android.flags.flag1", "false"); assertTrue(flag != null); - assertEquals(flag.packageName, "com.android.flags"); - assertEquals(flag.flagName, "flag1"); - assertEquals(flag.flagValue, "false"); - assertEquals(flag.isLocal, false); + assertEquals(flag.getPackageName(), "com.android.flags"); + assertEquals(flag.getFlagName(), "flag1"); + assertEquals("false", flag.getBootFlagValue()); + assertEquals("false", flag.getServerFlagValue()); + assertFalse(flag.getHasLocalOverride()); + assertNull(flag.getLocalFlagValue()); + assertEquals("false", flag.getDefaultFlagValue()); // local override flag = settingsState.getFlagOverrideToSync( "device_config_overrides/test_namespace:com.android.flags.flag1", "false"); assertTrue(flag != null); - assertEquals(flag.packageName, "com.android.flags"); - assertEquals(flag.flagName, "flag1"); - assertEquals(flag.flagValue, "false"); - assertEquals(flag.isLocal, true); + assertEquals(flag.getPackageName(), "com.android.flags"); + assertEquals(flag.getFlagName(), "flag1"); + assertEquals("false", flag.getLocalFlagValue()); + assertEquals("false", flag.getBootFlagValue()); + assertTrue(flag.getHasLocalOverride()); + assertNull(flag.getServerFlagValue()); + assertEquals("false", flag.getDefaultFlagValue()); } @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); @@ -1020,18 +1057,25 @@ public class SettingsStateTest { InstrumentationRegistry.getContext(), lock, mSettingsFile, configKey, SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); + Map<String, AconfigdFlagInfo> flags = new HashMap<>(); + AconfigdFlagInfo flag = AconfigdFlagInfo.newBuilder() + .setPackageName("com.android.flags") + .setFlagName("flag1") + .setBootFlagValue("true").build(); + flags.put("com.android.flags/flag1", flag); + synchronized (lock) { settingsState.insertSettingLocked("aconfigd_marker/bulk_synced", "false", null, false, "aconfig"); // first bulk sync - ProtoOutputStream requests = settingsState.handleBulkSyncToNewStorage(); + ProtoOutputStream requests = settingsState.handleBulkSyncToNewStorage(flags); assertTrue(requests != null); String value = settingsState.getSettingLocked("aconfigd_marker/bulk_synced").getValue(); assertEquals("true", value); // send time should no longer bulk sync - requests = settingsState.handleBulkSyncToNewStorage(); + requests = settingsState.handleBulkSyncToNewStorage(flags); assertTrue(requests == null); value = settingsState.getSettingLocked("aconfigd_marker/bulk_synced").getValue(); assertEquals("true", value); @@ -1047,21 +1091,200 @@ public class SettingsStateTest { InstrumentationRegistry.getContext(), lock, mSettingsFile, configKey, SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); + Map<String, AconfigdFlagInfo> flags = new HashMap<>(); synchronized (lock) { settingsState.insertSettingLocked("aconfigd_marker/bulk_synced", "true", null, false, "aconfig"); // when aconfigd is off, should change the marker to false - ProtoOutputStream requests = settingsState.handleBulkSyncToNewStorage(); + ProtoOutputStream requests = settingsState.handleBulkSyncToNewStorage(flags); assertTrue(requests == null); String value = settingsState.getSettingLocked("aconfigd_marker/bulk_synced").getValue(); assertEquals("false", value); // marker started with false value, after call, it should remain false - requests = settingsState.handleBulkSyncToNewStorage(); + requests = settingsState.handleBulkSyncToNewStorage(flags); assertTrue(requests == null); value = settingsState.getSettingLocked("aconfigd_marker/bulk_synced").getValue(); assertEquals("false", value); } } + + @Test + public void testGetAllAconfigFlagsFromSettings() throws Exception { + final Object lock = new Object(); + final PrintStream os = new PrintStream(new FileOutputStream(mSettingsFile)); + os.print( + "<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>" + + "<settings version=\"120\">" + + " <setting id=\"0\" name=\"test_namespace/com.android.flags.flag1\" " + + "value=\"false\" package=\"com.android.flags\" />" + + " <setting id=\"1\" name=\"device_config_overrides/test_namespace:com.android.flags.flag1\" " + + "value=\"true\" package=\"com.android.flags\" />" + + " <setting id=\"2\" name=\"device_config_overrides/test_namespace:com.android.flags.flag2\" " + + "value=\"true\" package=\"com.android.flags\" />" + + " <setting id=\"3\" name=\"test_namespace/com.android.flags.flag3\" " + + "value=\"true\" package=\"com.android.flags\" />" + + "</settings>"); + os.close(); + + int configKey = SettingsState.makeKey(SettingsState.SETTINGS_TYPE_CONFIG, 0); + + SettingsState settingsState = new SettingsState( + InstrumentationRegistry.getContext(), lock, mSettingsFile, configKey, + SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); + + Map<String, AconfigdFlagInfo> ret; + synchronized (lock) { + ret = settingsState.getAllAconfigFlagsFromSettings(); + } + + assertTrue(ret.isEmpty()); + + parsed_flags flags = + parsed_flags + .newBuilder() + .addParsedFlag( + parsed_flag + .newBuilder() + .setPackage("com.android.flags") + .setName("flag1") + .setNamespace("test_namespace") + .setDescription("test flag") + .addBug("12345678") + .setState(Aconfig.flag_state.DISABLED) + .setPermission(Aconfig.flag_permission.READ_WRITE)) + .addParsedFlag( + parsed_flag + .newBuilder() + .setPackage("com.android.flags") + .setName("flag2") + .setNamespace("test_namespace") + .setDescription("test flag") + .addBug("12345678") + .setState(Aconfig.flag_state.DISABLED) + .setPermission(Aconfig.flag_permission.READ_WRITE)) + .addParsedFlag( + parsed_flag + .newBuilder() + .setPackage("com.android.flags") + .setName("flag3") + .setNamespace("test_namespace") + .setDescription("test flag") + .addBug("12345678") + .setState(Aconfig.flag_state.DISABLED) + .setPermission(Aconfig.flag_permission.READ_WRITE)) + .build(); + + Map<String, Map<String, String>> defaults = new HashMap<>(); + Map<String, AconfigdFlagInfo> flagInfoDefault = new HashMap<>(); + synchronized (lock) { + settingsState.loadAconfigDefaultValues( + flags.toByteArray(), defaults, flagInfoDefault); + settingsState.addAconfigDefaultValuesFromMap(defaults); + ret = settingsState.getAllAconfigFlagsFromSettings(); + } + + AconfigdFlagInfo expectedFlag1 = + AconfigdFlagInfo.newBuilder() + .setPackageName("com.android.flags") + .setFlagName("flag1") + .setServerFlagValue("false") + .setLocalFlagValue("true") + .setDefaultFlagValue("false") + .setBootFlagValue("true") + .setHasServerOverride(true) + .setHasLocalOverride(true) + .setIsReadWrite(false) + .build(); + + AconfigdFlagInfo expectedFlag2 = + AconfigdFlagInfo.newBuilder() + .setPackageName("com.android.flags") + .setFlagName("flag2") + .setLocalFlagValue("true") + .setDefaultFlagValue("false") + .setBootFlagValue("true") + .setHasLocalOverride(true) + .setHasServerOverride(false) + .setIsReadWrite(false) + .build(); + + + AconfigdFlagInfo expectedFlag3 = + AconfigdFlagInfo.newBuilder() + .setPackageName("com.android.flags") + .setFlagName("flag3") + .setServerFlagValue("true") + .setBootFlagValue("true") + .setDefaultFlagValue("false") + .setHasServerOverride(true) + .setIsReadWrite(false) + .build(); + + assertEquals(expectedFlag1, ret.get("com.android.flags.flag1")); + assertEquals(expectedFlag2, ret.get("com.android.flags.flag2")); + assertEquals(expectedFlag3, ret.get("com.android.flags.flag3")); + } + + @Test + public void testCompareFlagValueInNewStorage() { + int configKey = SettingsState.makeKey(SettingsState.SETTINGS_TYPE_CONFIG, 0); + Object lock = new Object(); + SettingsState settingsState = + new SettingsState( + InstrumentationRegistry.getContext(), + lock, + mSettingsFile, + configKey, + SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, + Looper.getMainLooper()); + + AconfigdFlagInfo defaultFlag1 = + AconfigdFlagInfo.newBuilder() + .setPackageName("com.android.flags") + .setFlagName("flag1") + .setDefaultFlagValue("false") + .build(); + + AconfigdFlagInfo settingFlag1 = + AconfigdFlagInfo.newBuilder() + .setPackageName("com.android.flags") + .setFlagName("flag1") + .setServerFlagValue("true") + .setHasServerOverride(true) + .build(); + + AconfigdFlagInfo expectedFlag1 = + AconfigdFlagInfo.newBuilder() + .setPackageName("com.android.flags") + .setFlagName("flag1") + .setBootFlagValue("true") + .setServerFlagValue("true") + .setDefaultFlagValue("false") + .setHasServerOverride(true) + .build(); + + Map<String, AconfigdFlagInfo> settingMap = new HashMap<>(); + Map<String, AconfigdFlagInfo> aconfigdMap = new HashMap<>(); + Map<String, AconfigdFlagInfo> defaultMap = new HashMap<>(); + + defaultMap.put("com.android.flags.flag1", defaultFlag1); + settingMap.put("com.android.flags.flag1", settingFlag1); + aconfigdMap.put("com.android.flags.flag1", expectedFlag1); + + int ret = settingsState.compareFlagValueInNewStorage(settingMap, defaultMap, aconfigdMap); + assertEquals(0, ret); + + AconfigdFlagInfo defaultFlag2 = + AconfigdFlagInfo.newBuilder() + .setPackageName("com.android.flags") + .setFlagName("flag2") + .setDefaultFlagValue("false") + .build(); + defaultMap.put("com.android.flags.flag2", defaultFlag2); + + ret = settingsState.compareFlagValueInNewStorage(settingMap, defaultMap, aconfigdMap); + assertEquals(1, ret); + } } diff --git a/packages/SystemUI/aconfig/accessibility.aconfig b/packages/SystemUI/aconfig/accessibility.aconfig index 55edff6d9518..d201071620e4 100644 --- a/packages/SystemUI/aconfig/accessibility.aconfig +++ b/packages/SystemUI/aconfig/accessibility.aconfig @@ -81,3 +81,13 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + name: "hearing_devices_dialog_related_tools" + namespace: "accessibility" + description: "Shows the related tools for hearing devices dialog." + bug: "341648471" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig index 36bad5e622cf..1df9c88e48ac 100644 --- a/packages/SystemUI/aconfig/systemui.aconfig +++ b/packages/SystemUI/aconfig/systemui.aconfig @@ -184,6 +184,13 @@ flag { } flag { + name: "notification_avalanche_throttle_hun" + namespace: "systemui" + description: "(currently unused) During notification avalanche, throttle HUNs showing in fast succession." + bug: "307288824" +} + +flag { name: "notification_avalanche_suppression" namespace: "systemui" description: "After notification avalanche floodgate event, suppress HUNs completely." @@ -990,6 +997,13 @@ flag { } flag { + name: "glanceable_hub_shortcut_button" + namespace: "systemui" + description: "Shows a button over the dream and lock screen to open the glanceable hub" + bug: "339667383" +} + +flag { name: "glanceable_hub_gesture_handle" namespace: "systemui" description: "Shows a vertical bar at the right edge to indicate the user can swipe to open the glanceable hub" diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt index b1240252796f..978943ae7f7c 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt @@ -179,8 +179,15 @@ class TextAnimator( private val fontVariationUtils = FontVariationUtils() - fun updateLayout(layout: Layout) { + fun updateLayout(layout: Layout, textSize: Float = -1f) { textInterpolator.layout = layout + + if (textSize >= 0) { + textInterpolator.targetPaint.textSize = textSize + textInterpolator.basePaint.textSize = textSize + textInterpolator.onTargetPaintModified() + textInterpolator.onBasePaintModified() + } } fun isRunning(): Boolean { diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt index c19c08e09349..b8f9ca82f072 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt @@ -66,6 +66,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.asImageBitmap import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.input.key.onKeyEvent import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalDensity @@ -137,7 +138,7 @@ fun BouncerContent( // Despite the keyboard only being part of the password bouncer, adding it at this level is // both necessary to properly handle the keyboard in all layouts and harmless in cases when // the keyboard isn't used (like the PIN or pattern auth methods). - modifier = modifier.imePadding(), + modifier = modifier.imePadding().onKeyEvent(viewModel::onKeyEvent), ) { when (layout) { BouncerSceneLayout.STANDARD_BOUNCER -> diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt index cd27d5713c2d..8ee1e1f7f504 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt @@ -640,11 +640,16 @@ private fun AnimatedVisibilityScope.ButtonToEditWidgets( enter = fadeIn( initialAlpha = 0f, - animationSpec = tween(durationMillis = 500, easing = LinearEasing) + animationSpec = tween(durationMillis = 83, easing = LinearEasing) ), exit = fadeOut( - animationSpec = tween(durationMillis = 500, easing = LinearEasing) + animationSpec = + tween( + durationMillis = 83, + delayMillis = 167, + easing = LinearEasing + ) ) ) .background(colors.secondary, RoundedCornerShape(50.dp)), @@ -658,7 +663,7 @@ private fun AnimatedVisibilityScope.ButtonToEditWidgets( animationSpec = tween( durationMillis = 167, - delayMillis = 500, + delayMillis = 83, easing = LinearEasing ) ), diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationHeadsUpHeight.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationHeadsUpHeight.kt new file mode 100644 index 000000000000..75a565b2d2a0 --- /dev/null +++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationHeadsUpHeight.kt @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2024 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.notifications.ui.composable + +import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.Measurable +import androidx.compose.ui.layout.MeasureResult +import androidx.compose.ui.layout.MeasureScope +import androidx.compose.ui.node.LayoutModifierNode +import androidx.compose.ui.node.ModifierNodeElement +import androidx.compose.ui.node.invalidateMeasurement +import androidx.compose.ui.unit.Constraints +import androidx.compose.ui.unit.IntOffset +import com.android.systemui.statusbar.notification.stack.ui.view.NotificationScrollView + +/** + * Modify element, which updates the height to the height of current top heads up notification, or + * to 0 if there is none. + * + * @param view Notification stack scroll view + */ +fun Modifier.notificationHeadsUpHeight(view: NotificationScrollView) = + this then HeadsUpLayoutElement(view) + +private data class HeadsUpLayoutElement( + val view: NotificationScrollView, +) : ModifierNodeElement<HeadsUpLayoutNode>() { + + override fun create(): HeadsUpLayoutNode = HeadsUpLayoutNode(view) + + override fun update(node: HeadsUpLayoutNode) { + check(view == node.view) { "Trying to reuse the node with a new View." } + } +} + +private class HeadsUpLayoutNode(val view: NotificationScrollView) : + LayoutModifierNode, Modifier.Node() { + + private val headsUpHeightChangedListener = Runnable { invalidateMeasureIfAttached() } + + override fun onAttach() { + super.onAttach() + view.addHeadsUpHeightChangedListener(headsUpHeightChangedListener) + } + + override fun onDetach() { + super.onDetach() + view.removeHeadsUpHeightChangedListener(headsUpHeightChangedListener) + } + + override fun MeasureScope.measure( + measurable: Measurable, + constraints: Constraints + ): MeasureResult { + // TODO(b/339181697) make sure, that the row is already measured. + val contentHeight = view.topHeadsUpHeight + val placeable = + measurable.measure( + constraints.copy(minHeight = contentHeight, maxHeight = contentHeight) + ) + return layout(placeable.width, placeable.height) { placeable.place(IntOffset.Zero) } + } + + override fun toString(): String { + return "HeadsUpLayoutNode(view=$view)" + } + + fun invalidateMeasureIfAttached() { + if (isAttached) { + this.invalidateMeasurement() + } + } +} diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt index e6132c6a2a59..c26259f3287c 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt @@ -67,7 +67,6 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.compose.animation.scene.ElementKey import com.android.compose.animation.scene.NestedScrollBehavior import com.android.compose.animation.scene.SceneScope -import com.android.compose.modifiers.height import com.android.compose.modifiers.thenIf import com.android.systemui.common.ui.compose.windowinsets.LocalRawScreenHeight import com.android.systemui.common.ui.compose.windowinsets.LocalScreenCornerRadius @@ -108,18 +107,17 @@ object Notifications { */ @Composable fun SceneScope.HeadsUpNotificationSpace( + stackScrollView: NotificationScrollView, viewModel: NotificationsPlaceholderViewModel, modifier: Modifier = Modifier, isPeekFromBottom: Boolean = false, ) { - val headsUpHeight = viewModel.headsUpHeight.collectAsStateWithLifecycle() - Element( Notifications.Elements.HeadsUpNotificationPlaceholder, modifier = modifier - .height { headsUpHeight.value.roundToInt() } .fillMaxWidth() + .notificationHeadsUpHeight(stackScrollView) .debugBackground(viewModel, DEBUG_HUN_COLOR) .onGloballyPositioned { coordinates: LayoutCoordinates -> val boundsInWindow = coordinates.boundsInWindow() @@ -152,6 +150,7 @@ fun SceneScope.ConstrainedNotificationStack( modifier = Modifier.fillMaxSize(), ) HeadsUpNotificationSpace( + stackScrollView = stackScrollView, viewModel = viewModel, modifier = Modifier.align(Alignment.TopCenter), ) @@ -358,7 +357,7 @@ fun SceneScope.NotificationScrollingStack( .onSizeChanged { size -> stackHeight.intValue = size.height }, ) } - HeadsUpNotificationSpace(viewModel = viewModel) + HeadsUpNotificationSpace(stackScrollView = stackScrollView, viewModel = viewModel) } } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt index d76b19f3fa82..0ee485c496be 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt @@ -42,7 +42,6 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.navigationBars -import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.rememberScrollState @@ -60,7 +59,6 @@ import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.compose.ui.res.colorResource -import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.compose.animation.scene.SceneScope @@ -79,14 +77,13 @@ import com.android.systemui.media.controls.ui.composable.MediaCarousel import com.android.systemui.media.controls.ui.controller.MediaCarouselController import com.android.systemui.media.controls.ui.view.MediaHost import com.android.systemui.media.dagger.MediaModule -import com.android.systemui.notifications.ui.composable.NotificationScrollingStack +import com.android.systemui.notifications.ui.composable.HeadsUpNotificationSpace import com.android.systemui.qs.footer.ui.compose.FooterActionsWithAnimatedVisibility import com.android.systemui.qs.ui.viewmodel.QuickSettingsSceneViewModel import com.android.systemui.res.R import com.android.systemui.scene.session.ui.composable.SaveableSession import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.scene.ui.composable.ComposableScene -import com.android.systemui.shade.shared.model.ShadeMode import com.android.systemui.shade.ui.composable.CollapsedShadeHeader import com.android.systemui.shade.ui.composable.ExpandedShadeHeader import com.android.systemui.shade.ui.composable.Shade @@ -99,7 +96,6 @@ import com.android.systemui.statusbar.phone.ui.TintedIconManager import dagger.Lazy import javax.inject.Inject import javax.inject.Named -import kotlin.math.roundToInt import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.stateIn @@ -368,15 +364,11 @@ private fun SceneScope.QuickSettingsScene( Modifier.align(Alignment.CenterHorizontally).sysuiResTag("qs_footer_actions"), ) } - NotificationScrollingStack( + HeadsUpNotificationSpace( stackScrollView = notificationStackScrollView, viewModel = notificationsPlaceholderViewModel, - shadeSession = shadeSession, - maxScrimTop = { screenHeight }, - shouldPunchHoleBehindScrim = shouldPunchHoleBehindScrim, - shadeMode = ShadeMode.Single, - modifier = - Modifier.fillMaxWidth().offset { IntOffset(x = 0, y = screenHeight.roundToInt()) }, + modifier = Modifier.align(Alignment.BottomCenter), + isPeekFromBottom = true, ) } } diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt index d2a1de3e4695..f0fb9f62fdad 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt @@ -371,96 +371,57 @@ private fun prepareInterruption( transition: TransitionState.Transition, previousTransition: TransitionState.Transition, ) { - val previousUniqueState = reconcileStates(element, previousTransition) - if (previousUniqueState == null) { - reconcileStates(element, transition) - return - } - - val fromSceneState = element.sceneStates[transition.fromScene] - val toSceneState = element.sceneStates[transition.toScene] - - if ( - fromSceneState == null || - toSceneState == null || - sharedElementTransformation(element.key, transition)?.enabled != false - ) { - // If there is only one copy of the element or if the element is shared, animate deltas in - // both scenes. - fromSceneState?.updateValuesBeforeInterruption(previousUniqueState) - toSceneState?.updateValuesBeforeInterruption(previousUniqueState) - } + val sceneStates = element.sceneStates + sceneStates[previousTransition.fromScene]?.selfUpdateValuesBeforeInterruption() + sceneStates[previousTransition.toScene]?.selfUpdateValuesBeforeInterruption() + sceneStates[transition.fromScene]?.selfUpdateValuesBeforeInterruption() + sceneStates[transition.toScene]?.selfUpdateValuesBeforeInterruption() + + reconcileStates(element, previousTransition) + reconcileStates(element, transition) } /** * Reconcile the state of [element] in the fromScene and toScene of [transition] so that the values * before interruption have their expected values, taking shared transitions into account. - * - * If the element had a unique state, i.e. it is shared in [transition] or it is only present in one - * of the scenes, return it. */ private fun reconcileStates( element: Element, transition: TransitionState.Transition, -): Element.SceneState? { - val fromSceneState = element.sceneStates[transition.fromScene] - val toSceneState = element.sceneStates[transition.toScene] - when { - // Element is in both scenes. - fromSceneState != null && toSceneState != null -> { - val isSharedTransformationDisabled = - sharedElementTransformation(element.key, transition)?.enabled == false - when { - // Element shared transition is disabled so the element is placed in both scenes. - isSharedTransformationDisabled -> { - fromSceneState.updateValuesBeforeInterruption(fromSceneState) - toSceneState.updateValuesBeforeInterruption(toSceneState) - return null - } - - // Element is shared and placed in fromScene only. - fromSceneState.lastOffset != Offset.Unspecified -> { - fromSceneState.updateValuesBeforeInterruption(fromSceneState) - toSceneState.updateValuesBeforeInterruption(fromSceneState) - return fromSceneState - } - - // Element is shared and placed in toScene only. - toSceneState.lastOffset != Offset.Unspecified -> { - fromSceneState.updateValuesBeforeInterruption(toSceneState) - toSceneState.updateValuesBeforeInterruption(toSceneState) - return toSceneState - } - - // Element is in none of the scenes. - else -> { - fromSceneState.updateValuesBeforeInterruption(null) - toSceneState.updateValuesBeforeInterruption(null) - return null - } - } - } - - // Element is only in fromScene. - fromSceneState != null -> { - fromSceneState.updateValuesBeforeInterruption(fromSceneState) - return fromSceneState - } +) { + val fromSceneState = element.sceneStates[transition.fromScene] ?: return + val toSceneState = element.sceneStates[transition.toScene] ?: return + if (!isSharedElementEnabled(element.key, transition)) { + return + } - // Element is only in toScene. - toSceneState != null -> { - toSceneState.updateValuesBeforeInterruption(toSceneState) - return toSceneState - } - else -> return null + if ( + fromSceneState.offsetBeforeInterruption != Offset.Unspecified && + toSceneState.offsetBeforeInterruption == Offset.Unspecified + ) { + // Element is shared and placed in fromScene only. + toSceneState.updateValuesBeforeInterruption(fromSceneState) + } else if ( + toSceneState.offsetBeforeInterruption != Offset.Unspecified && + fromSceneState.offsetBeforeInterruption == Offset.Unspecified + ) { + // Element is shared and placed in toScene only. + fromSceneState.updateValuesBeforeInterruption(toSceneState) } } -private fun Element.SceneState.updateValuesBeforeInterruption(lastState: Element.SceneState?) { - offsetBeforeInterruption = lastState?.lastOffset ?: Offset.Unspecified - sizeBeforeInterruption = lastState?.lastSize ?: Element.SizeUnspecified - scaleBeforeInterruption = lastState?.lastScale ?: Scale.Unspecified - alphaBeforeInterruption = lastState?.lastAlpha ?: Element.AlphaUnspecified +private fun Element.SceneState.selfUpdateValuesBeforeInterruption() { + offsetBeforeInterruption = lastOffset + sizeBeforeInterruption = lastSize + scaleBeforeInterruption = lastScale + alphaBeforeInterruption = lastAlpha +} + +private fun Element.SceneState.updateValuesBeforeInterruption(lastState: Element.SceneState) { + offsetBeforeInterruption = lastState.offsetBeforeInterruption + sizeBeforeInterruption = lastState.sizeBeforeInterruption + scaleBeforeInterruption = lastState.scaleBeforeInterruption + alphaBeforeInterruption = lastState.alphaBeforeInterruption clearInterruptionDeltas() } diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt index bdeab797d165..079c1d922275 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt @@ -17,7 +17,6 @@ package com.android.systemui.shared.clocks import android.animation.TimeInterpolator import android.annotation.ColorInt -import android.annotation.FloatRange import android.annotation.IntRange import android.annotation.SuppressLint import android.content.Context @@ -27,7 +26,7 @@ import android.text.TextUtils import android.text.format.DateFormat import android.util.AttributeSet import android.util.MathUtils.constrainedMap -import android.util.TypedValue +import android.util.TypedValue.COMPLEX_UNIT_PX import android.view.View import android.view.View.MeasureSpec.EXACTLY import android.widget.TextView @@ -219,9 +218,7 @@ constructor( override fun setTextSize(type: Int, size: Float) { super.setTextSize(type, size) - if (type == TypedValue.COMPLEX_UNIT_PX) { - lastUnconstrainedTextSize = size - } + lastUnconstrainedTextSize = if (type == COMPLEX_UNIT_PX) size else Float.MAX_VALUE } @SuppressLint("DrawAllocation") @@ -234,23 +231,19 @@ constructor( MeasureSpec.getMode(heightMeasureSpec) == EXACTLY ) { // Call straight into TextView.setTextSize to avoid setting lastUnconstrainedTextSize - super.setTextSize( - TypedValue.COMPLEX_UNIT_PX, - min(lastUnconstrainedTextSize, MeasureSpec.getSize(heightMeasureSpec) / 2F) - ) + val size = min(lastUnconstrainedTextSize, MeasureSpec.getSize(heightMeasureSpec) / 2F) + super.setTextSize(COMPLEX_UNIT_PX, size) } super.onMeasure(widthMeasureSpec, heightMeasureSpec) - val animator = textAnimator - if (animator == null) { - textAnimator = - textAnimatorFactory(layout, ::invalidate)?.also { - onTextAnimatorInitialized?.invoke(it) - onTextAnimatorInitialized = null - } - } else { - animator.updateLayout(layout) - } + textAnimator?.let { animator -> animator.updateLayout(layout, textSize) } + ?: run { + textAnimator = + textAnimatorFactory(layout, ::invalidate).also { + onTextAnimatorInitialized?.invoke(it) + onTextAnimatorInitialized = null + } + } if (migratedClocks && hasCustomPositionUpdatedAnimation) { // Expand width to avoid clock being clipped during stepping animation @@ -307,18 +300,18 @@ constructor( logger.d("animateColorChange") setTextStyle( weight = lockScreenWeight, - textSize = -1f, color = null, /* using current color */ animate = false, + interpolator = null, duration = 0, delay = 0, onAnimationEnd = null ) setTextStyle( weight = lockScreenWeight, - textSize = -1f, color = lockScreenColor, animate = true, + interpolator = null, duration = COLOR_ANIM_DURATION, delay = 0, onAnimationEnd = null @@ -329,16 +322,15 @@ constructor( logger.d("animateAppearOnLockscreen") setTextStyle( weight = dozingWeight, - textSize = -1f, color = lockScreenColor, animate = false, + interpolator = null, duration = 0, delay = 0, onAnimationEnd = null ) setTextStyle( weight = lockScreenWeight, - textSize = -1f, color = lockScreenColor, animate = true, duration = APPEAR_ANIM_DURATION, @@ -356,16 +348,15 @@ constructor( logger.d("animateFoldAppear") setTextStyle( weight = lockScreenWeightInternal, - textSize = -1f, color = lockScreenColor, animate = false, + interpolator = null, duration = 0, delay = 0, onAnimationEnd = null ) setTextStyle( weight = dozingWeightInternal, - textSize = -1f, color = dozingColor, animate = animate, interpolator = Interpolators.EMPHASIZED_DECELERATE, @@ -385,9 +376,9 @@ constructor( val startAnimPhase2 = Runnable { setTextStyle( weight = if (isDozing()) dozingWeight else lockScreenWeight, - textSize = -1f, color = null, animate = true, + interpolator = null, duration = CHARGE_ANIM_DURATION_PHASE_1, delay = 0, onAnimationEnd = null @@ -395,9 +386,9 @@ constructor( } setTextStyle( weight = if (isDozing()) lockScreenWeight else dozingWeight, - textSize = -1f, color = null, animate = true, + interpolator = null, duration = CHARGE_ANIM_DURATION_PHASE_0, delay = chargeAnimationDelay.toLong(), onAnimationEnd = startAnimPhase2 @@ -408,9 +399,9 @@ constructor( logger.d("animateDoze") setTextStyle( weight = if (isDozing) dozingWeight else lockScreenWeight, - textSize = -1f, color = if (isDozing) dozingColor else lockScreenColor, animate = animate, + interpolator = null, duration = DOZE_ANIM_DURATION, delay = 0, onAnimationEnd = null @@ -448,7 +439,6 @@ constructor( */ private fun setTextStyle( @IntRange(from = 0, to = 1000) weight: Int, - @FloatRange(from = 0.0) textSize: Float, color: Int?, animate: Boolean, interpolator: TimeInterpolator?, @@ -459,7 +449,6 @@ constructor( textAnimator?.let { it.setTextStyle( weight = weight, - textSize = textSize, color = color, animate = animate && isAnimationEnabled, duration = duration, @@ -474,7 +463,6 @@ constructor( onTextAnimatorInitialized = { textAnimator -> textAnimator.setTextStyle( weight = weight, - textSize = textSize, color = color, animate = false, duration = duration, @@ -487,27 +475,6 @@ constructor( } } - private fun setTextStyle( - @IntRange(from = 0, to = 1000) weight: Int, - @FloatRange(from = 0.0) textSize: Float, - color: Int?, - animate: Boolean, - duration: Long, - delay: Long, - onAnimationEnd: Runnable? - ) { - setTextStyle( - weight = weight, - textSize = textSize, - color = color, - animate = animate, - interpolator = null, - duration = duration, - delay = delay, - onAnimationEnd = onAnimationEnd - ) - } - fun refreshFormat() = refreshFormat(DateFormat.is24HourFormat(context)) fun refreshFormat(use24HourFormat: Boolean) { Patterns.update(context) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt index 256687b56f4e..89bafb952211 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt @@ -16,6 +16,12 @@ package com.android.systemui.bouncer.ui.viewmodel +import android.view.KeyEvent.KEYCODE_0 +import android.view.KeyEvent.KEYCODE_4 +import android.view.KeyEvent.KEYCODE_A +import android.view.KeyEvent.KEYCODE_DEL +import android.view.KeyEvent.KEYCODE_NUMPAD_0 +import androidx.compose.ui.input.key.KeyEventType import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.compose.animation.scene.SceneKey @@ -34,6 +40,8 @@ import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat +import kotlin.random.Random +import kotlin.random.nextInt import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow @@ -444,6 +452,44 @@ class PinBouncerViewModelTest : SysuiTestCase() { assertThat(pin).hasSize(FakeAuthenticationRepository.HINTING_PIN_LENGTH + 1) } + @Test + fun onKeyboardInput_pinInput_isUpdated() = + testScope.runTest { + val pin by collectLastValue(underTest.pinInput.map { it.getPin() }) + lockDeviceAndOpenPinBouncer() + val random = Random(System.currentTimeMillis()) + // Generate a random 4 digit PIN + val expectedPin = + with(random) { arrayOf(nextInt(0..9), nextInt(0..9), nextInt(0..9), nextInt(0..9)) } + + // Enter the PIN using NUM pad and normal number keyboard events + underTest.onKeyEvent(KeyEventType.KeyDown, KEYCODE_0 + expectedPin[0]) + underTest.onKeyEvent(KeyEventType.KeyUp, KEYCODE_0 + expectedPin[0]) + + underTest.onKeyEvent(KeyEventType.KeyDown, KEYCODE_NUMPAD_0 + expectedPin[1]) + underTest.onKeyEvent(KeyEventType.KeyUp, KEYCODE_NUMPAD_0 + expectedPin[1]) + + underTest.onKeyEvent(KeyEventType.KeyDown, KEYCODE_0 + expectedPin[2]) + underTest.onKeyEvent(KeyEventType.KeyUp, KEYCODE_0 + expectedPin[2]) + + // Enter an additional digit in between and delete it + underTest.onKeyEvent(KeyEventType.KeyDown, KEYCODE_4) + underTest.onKeyEvent(KeyEventType.KeyUp, KEYCODE_4) + + // Delete that additional digit + underTest.onKeyEvent(KeyEventType.KeyDown, KEYCODE_DEL) + underTest.onKeyEvent(KeyEventType.KeyUp, KEYCODE_DEL) + + // Try entering a non digit character, this should be ignored. + underTest.onKeyEvent(KeyEventType.KeyDown, KEYCODE_A) + underTest.onKeyEvent(KeyEventType.KeyUp, KEYCODE_A) + + underTest.onKeyEvent(KeyEventType.KeyDown, KEYCODE_NUMPAD_0 + expectedPin[3]) + underTest.onKeyEvent(KeyEventType.KeyUp, KEYCODE_NUMPAD_0 + expectedPin[3]) + + assertThat(pin).containsExactly(*expectedPin) + } + private fun TestScope.switchToScene(toScene: SceneKey) { val currentScene by collectLastValue(sceneInteractor.currentScene) val bouncerHidden = currentScene == Scenes.Bouncer && toScene != Scenes.Bouncer diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/touch/CommunalTouchHandlerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/touch/CommunalTouchHandlerTest.java index 29fbee01a18b..7936ccc1ddd1 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/touch/CommunalTouchHandlerTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/touch/CommunalTouchHandlerTest.java @@ -108,7 +108,7 @@ public class CommunalTouchHandlerTest extends SysuiTestCase { mTouchHandler.onSessionStart(mTouchSession); verify(mTouchSession).registerInputListener(inputEventListenerArgumentCaptor.capture()); inputEventListenerArgumentCaptor.getValue().onInputEvent(motionEvent); - verify(mCentralSurfaces).handleDreamTouch(motionEvent); + verify(mCentralSurfaces).handleCommunalHubTouch(motionEvent); } @Test diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLegacySettingSyncerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLegacySettingSyncerTest.kt index 26fcb234843d..49d039970a24 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLegacySettingSyncerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLegacySettingSyncerTest.kt @@ -90,6 +90,7 @@ class KeyguardQuickAffordanceLegacySettingSyncerTest : SysuiTestCase() { .thenReturn(FakeSharedPreferences()) }, userTracker = FakeUserTracker(), + systemSettings = FakeSettings(), broadcastDispatcher = fakeBroadcastDispatcher, ) settings = FakeSettings() diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManagerTest.kt index 99a01858471c..9ab1ac116b0d 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManagerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManagerTest.kt @@ -22,13 +22,14 @@ import android.content.SharedPreferences import android.content.pm.UserInfo import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest -import com.android.systemui.res.R import com.android.systemui.SysuiTestCase import com.android.systemui.backup.BackupHelper +import com.android.systemui.res.R import com.android.systemui.settings.FakeUserTracker import com.android.systemui.settings.UserFileManager import com.android.systemui.util.FakeSharedPreferences import com.android.systemui.util.mockito.whenever +import com.android.systemui.util.settings.FakeSettings import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -80,6 +81,7 @@ class KeyguardQuickAffordanceLocalUserSelectionManagerTest : SysuiTestCase() { context = context, userFileManager = userFileManager, userTracker = userTracker, + systemSettings = FakeSettings(), broadcastDispatcher = fakeBroadcastDispatcher, ) } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepositoryTest.kt index 567e0a9717fc..159ce36bea2d 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepositoryTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepositoryTest.kt @@ -21,7 +21,6 @@ import android.content.pm.UserInfo import android.os.UserHandle import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest -import com.android.systemui.res.R import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue import com.android.systemui.keyguard.data.quickaffordance.FakeKeyguardQuickAffordanceConfig @@ -32,6 +31,7 @@ import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanc import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceRemoteUserSelectionManager import com.android.systemui.keyguard.shared.model.KeyguardQuickAffordancePickerRepresentation import com.android.systemui.keyguard.shared.model.KeyguardSlotPickerRepresentation +import com.android.systemui.res.R import com.android.systemui.settings.FakeUserTracker import com.android.systemui.settings.UserFileManager import com.android.systemui.shared.customization.data.content.FakeCustomizationProviderClient @@ -91,6 +91,7 @@ class KeyguardQuickAffordanceRepositoryTest : SysuiTestCase() { .thenReturn(FakeSharedPreferences()) }, userTracker = userTracker, + systemSettings = FakeSettings(), broadcastDispatcher = fakeBroadcastDispatcher, ) client1 = FakeCustomizationProviderClient() diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt index 2d77f4f1c436..78a116737349 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt @@ -148,6 +148,7 @@ class KeyguardQuickAffordanceInteractorTest : SysuiTestCase() { .thenReturn(FakeSharedPreferences()) }, userTracker = userTracker, + systemSettings = FakeSettings(), broadcastDispatcher = fakeBroadcastDispatcher, ) val remoteUserSelectionManager = diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt index 2b8a644162c7..9dc930babc10 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt @@ -27,18 +27,22 @@ import com.android.systemui.coroutines.collectValues import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor import com.android.systemui.flags.DisableSceneContainer import com.android.systemui.flags.EnableSceneContainer +import com.android.systemui.keyguard.data.repository.deviceEntryFingerprintAuthRepository import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.kosmos.testScope import com.android.systemui.scene.data.repository.sceneContainerRepository +import com.android.systemui.scene.data.repository.setSceneTransition import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.testKosmos import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat +import com.google.common.truth.Truth.assertWithMessage import junit.framework.Assert.assertEquals import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.flowOf @@ -192,6 +196,175 @@ class WindowManagerLockscreenVisibilityInteractorTest : SysuiTestCase() { } @Test + @EnableSceneContainer + fun surfaceBehindVisibility_fromLockscreenToGone_trueThroughout() = + testScope.runTest { + val isSurfaceBehindVisible by collectLastValue(underTest.value.surfaceBehindVisibility) + val currentScene by collectLastValue(kosmos.sceneInteractor.currentScene) + + // Before the transition, we start on Lockscreen so the surface should start invisible. + kosmos.setSceneTransition(ObservableTransitionState.Idle(Scenes.Lockscreen)) + assertThat(currentScene).isEqualTo(Scenes.Lockscreen) + assertThat(isSurfaceBehindVisible).isFalse() + + // Unlocked with fingerprint. + kosmos.deviceEntryFingerprintAuthRepository.setAuthenticationStatus( + SuccessFingerprintAuthenticationStatus(0, true) + ) + + // Start the transition to Gone, the surface should become immediately visible. + kosmos.setSceneTransition( + ObservableTransitionState.Transition( + fromScene = Scenes.Lockscreen, + toScene = Scenes.Gone, + isInitiatedByUserInput = false, + isUserInputOngoing = flowOf(false), + progress = flowOf(0.3f), + currentScene = flowOf(Scenes.Lockscreen), + ) + ) + assertThat(currentScene).isEqualTo(Scenes.Lockscreen) + assertThat(isSurfaceBehindVisible).isTrue() + + // Towards the end of the transition, the surface should continue to be visible. + kosmos.setSceneTransition( + ObservableTransitionState.Transition( + fromScene = Scenes.Lockscreen, + toScene = Scenes.Gone, + isInitiatedByUserInput = false, + isUserInputOngoing = flowOf(false), + progress = flowOf(0.9f), + currentScene = flowOf(Scenes.Gone), + ) + ) + assertThat(currentScene).isEqualTo(Scenes.Lockscreen) + assertThat(isSurfaceBehindVisible).isTrue() + + // After the transition, settles on Gone. Surface behind should stay visible now. + kosmos.setSceneTransition(ObservableTransitionState.Idle(Scenes.Gone)) + kosmos.sceneInteractor.changeScene(Scenes.Gone, "") + assertThat(currentScene).isEqualTo(Scenes.Gone) + assertThat(isSurfaceBehindVisible).isTrue() + } + + @Test + @EnableSceneContainer + fun surfaceBehindVisibility_fromBouncerToGone_becomesTrue() = + testScope.runTest { + val isSurfaceBehindVisible by collectLastValue(underTest.value.surfaceBehindVisibility) + val currentScene by collectLastValue(kosmos.sceneInteractor.currentScene) + + // Before the transition, we start on Bouncer so the surface should start invisible. + kosmos.setSceneTransition(ObservableTransitionState.Idle(Scenes.Bouncer)) + kosmos.sceneInteractor.changeScene(Scenes.Bouncer, "") + assertThat(currentScene).isEqualTo(Scenes.Bouncer) + assertThat(isSurfaceBehindVisible).isFalse() + + // Unlocked with fingerprint. + kosmos.deviceEntryFingerprintAuthRepository.setAuthenticationStatus( + SuccessFingerprintAuthenticationStatus(0, true) + ) + + // Start the transition to Gone, the surface should remain invisible prior to hitting + // the + // threshold. + kosmos.setSceneTransition( + ObservableTransitionState.Transition( + fromScene = Scenes.Bouncer, + toScene = Scenes.Gone, + isInitiatedByUserInput = false, + isUserInputOngoing = flowOf(false), + progress = + flowOf( + FromPrimaryBouncerTransitionInteractor + .TO_GONE_SURFACE_BEHIND_VISIBLE_THRESHOLD + ), + currentScene = flowOf(Scenes.Bouncer), + ) + ) + assertThat(currentScene).isEqualTo(Scenes.Bouncer) + assertThat(isSurfaceBehindVisible).isFalse() + + // Once the transition passes the threshold, the surface should become visible. + kosmos.setSceneTransition( + ObservableTransitionState.Transition( + fromScene = Scenes.Bouncer, + toScene = Scenes.Gone, + isInitiatedByUserInput = false, + isUserInputOngoing = flowOf(false), + progress = + flowOf( + FromPrimaryBouncerTransitionInteractor + .TO_GONE_SURFACE_BEHIND_VISIBLE_THRESHOLD + 0.01f + ), + currentScene = flowOf(Scenes.Gone), + ) + ) + assertThat(currentScene).isEqualTo(Scenes.Bouncer) + assertThat(isSurfaceBehindVisible).isTrue() + + // After the transition, settles on Gone. Surface behind should stay visible now. + kosmos.setSceneTransition(ObservableTransitionState.Idle(Scenes.Gone)) + kosmos.sceneInteractor.changeScene(Scenes.Gone, "") + assertThat(currentScene).isEqualTo(Scenes.Gone) + assertThat(isSurfaceBehindVisible).isTrue() + } + + @Test + @EnableSceneContainer + fun surfaceBehindVisibility_idleWhileUnlocked_alwaysTrue() = + testScope.runTest { + val isSurfaceBehindVisible by collectLastValue(underTest.value.surfaceBehindVisibility) + val currentScene by collectLastValue(kosmos.sceneInteractor.currentScene) + + // Unlocked with fingerprint. + kosmos.deviceEntryFingerprintAuthRepository.setAuthenticationStatus( + SuccessFingerprintAuthenticationStatus(0, true) + ) + kosmos.setSceneTransition(ObservableTransitionState.Idle(Scenes.Gone)) + kosmos.sceneInteractor.changeScene(Scenes.Gone, "") + assertThat(currentScene).isEqualTo(Scenes.Gone) + + listOf( + Scenes.Shade, + Scenes.QuickSettings, + Scenes.Shade, + Scenes.Gone, + ) + .forEach { scene -> + kosmos.setSceneTransition(ObservableTransitionState.Idle(scene)) + kosmos.sceneInteractor.changeScene(scene, "") + assertThat(currentScene).isEqualTo(scene) + assertWithMessage("Unexpected visibility for scene \"${scene.debugName}\"") + .that(isSurfaceBehindVisible) + .isTrue() + } + } + + @Test + @EnableSceneContainer + fun surfaceBehindVisibility_idleWhileLocked_alwaysFalse() = + testScope.runTest { + val isSurfaceBehindVisible by collectLastValue(underTest.value.surfaceBehindVisibility) + val currentScene by collectLastValue(kosmos.sceneInteractor.currentScene) + assertThat(currentScene).isEqualTo(Scenes.Lockscreen) + + listOf( + Scenes.Shade, + Scenes.QuickSettings, + Scenes.Shade, + Scenes.Lockscreen, + ) + .forEach { scene -> + kosmos.setSceneTransition(ObservableTransitionState.Idle(scene)) + kosmos.sceneInteractor.changeScene(scene, "") + assertWithMessage("Unexpected visibility for scene \"${scene.debugName}\"") + .that(isSurfaceBehindVisible) + .isFalse() + } + } + + @Test @DisableSceneContainer fun testUsingGoingAwayAnimation_duringTransitionToGone() = testScope.runTest { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/A11yShortcutAutoAddableListTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/A11yShortcutAutoAddableListTest.kt index 311122d7f8d5..16f30feb7e3b 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/A11yShortcutAutoAddableListTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/A11yShortcutAutoAddableListTest.kt @@ -27,6 +27,7 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.qs.pipeline.shared.TileSpec import com.android.systemui.qs.tiles.ColorCorrectionTile import com.android.systemui.qs.tiles.ColorInversionTile +import com.android.systemui.qs.tiles.HearingDevicesTile import com.android.systemui.qs.tiles.OneHandedModeTile import com.android.systemui.qs.tiles.ReduceBrightColorsTile import com.android.systemui.util.mockito.mock @@ -77,6 +78,10 @@ class A11yShortcutAutoAddableListTest : SysuiTestCase() { TileSpec.create(ReduceBrightColorsTile.TILE_SPEC), AccessibilityShortcutController.REDUCE_BRIGHT_COLORS_COMPONENT_NAME ), + factory.create( + TileSpec.create(HearingDevicesTile.TILE_SPEC), + AccessibilityShortcutController.ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME + ), ) val autoAddables = A11yShortcutAutoAddableList.getA11yShortcutAutoAddables(factory) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java index 0f66a93bcbec..3bfc046e46b4 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java @@ -38,6 +38,7 @@ import static org.mockito.Mockito.when; import android.app.Notification; import android.app.PendingIntent; import android.app.Person; +import android.platform.test.annotations.EnableFlags; import android.platform.test.flag.junit.FlagsParameterization; import android.testing.TestableLooper; @@ -150,6 +151,62 @@ public class BaseHeadsUpManagerTest extends SysuiTestCase { } @Test + public void testHasNotifications_headsUpManagerMapNotEmpty_true() { + final BaseHeadsUpManager bhum = createHeadsUpManager(); + final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext); + bhum.showNotification(entry); + + assertThat(bhum.mHeadsUpEntryMap).isNotEmpty(); + assertThat(bhum.hasNotifications()).isTrue(); + } + + @Test + @EnableFlags(NotificationThrottleHun.FLAG_NAME) + public void testHasNotifications_avalancheMapNotEmpty_true() { + final BaseHeadsUpManager bhum = createHeadsUpManager(); + final NotificationEntry notifEntry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, + mContext); + final BaseHeadsUpManager.HeadsUpEntry headsUpEntry = bhum.createHeadsUpEntry(notifEntry); + mAvalancheController.addToNext(headsUpEntry, () -> {}); + + assertThat(mAvalancheController.getWaitingEntryList()).isNotEmpty(); + assertThat(bhum.hasNotifications()).isTrue(); + } + + @Test + @EnableFlags(NotificationThrottleHun.FLAG_NAME) + public void testHasNotifications_false() { + final BaseHeadsUpManager bhum = createHeadsUpManager(); + assertThat(bhum.mHeadsUpEntryMap).isEmpty(); + assertThat(mAvalancheController.getWaitingEntryList()).isEmpty(); + assertThat(bhum.hasNotifications()).isFalse(); + } + + @Test + @EnableFlags(NotificationThrottleHun.FLAG_NAME) + public void testGetHeadsUpEntryList_includesAvalancheEntryList() { + final BaseHeadsUpManager bhum = createHeadsUpManager(); + final NotificationEntry notifEntry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, + mContext); + final BaseHeadsUpManager.HeadsUpEntry headsUpEntry = bhum.createHeadsUpEntry(notifEntry); + mAvalancheController.addToNext(headsUpEntry, () -> {}); + + assertThat(bhum.getHeadsUpEntryList()).contains(headsUpEntry); + } + + @Test + @EnableFlags(NotificationThrottleHun.FLAG_NAME) + public void testGetHeadsUpEntry_returnsAvalancheEntry() { + final BaseHeadsUpManager bhum = createHeadsUpManager(); + final NotificationEntry notifEntry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, + mContext); + final BaseHeadsUpManager.HeadsUpEntry headsUpEntry = bhum.createHeadsUpEntry(notifEntry); + mAvalancheController.addToNext(headsUpEntry, () -> {}); + + assertThat(bhum.getHeadsUpEntry(notifEntry.getKey())).isEqualTo(headsUpEntry); + } + + @Test public void testShowNotification_addsEntry() { final BaseHeadsUpManager alm = createHeadsUpManager(); final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext); diff --git a/packages/SystemUI/res/drawable/ic_widgets.xml b/packages/SystemUI/res/drawable/ic_widgets.xml new file mode 100644 index 000000000000..b21d047f9386 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_widgets.xml @@ -0,0 +1,27 @@ +<!-- + ~ Copyright (C) 2024 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. + --> + +<!-- go/gm2-icons, from gs_widgets_vd_theme_24.xml --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:tint="?attr/colorControlNormal" + android:viewportHeight="960" + android:viewportWidth="960"> + <path + android:fillColor="@android:color/black" + android:pathData="M666,520L440,294L666,68L892,294L666,520ZM120,440L120,120L440,120L440,440L120,440ZM520,840L520,520L840,520L840,840L520,840ZM120,840L120,520L440,520L440,840L120,840ZM200,360L360,360L360,200L200,200L200,360ZM667,408L780,295L667,182L554,295L667,408ZM600,760L760,760L760,600L600,600L600,760ZM200,760L360,760L360,600L200,600L200,760ZM360,360L360,360L360,360L360,360L360,360ZM554,295L554,295L554,295L554,295L554,295ZM360,600L360,600L360,600L360,600L360,600ZM600,600L600,600L600,600L600,600L600,600Z" /> +</vector>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/qs_hearing_devices_related_tools_background.xml b/packages/SystemUI/res/drawable/qs_hearing_devices_related_tools_background.xml new file mode 100644 index 000000000000..627b92b8a779 --- /dev/null +++ b/packages/SystemUI/res/drawable/qs_hearing_devices_related_tools_background.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2021 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<ripple + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" + android:color="?android:attr/colorControlHighlight"> + <item> + <shape android:shape="rectangle"> + <solid android:color="@android:color/transparent"/> + <corners android:radius="@dimen/hearing_devices_preset_spinner_background_radius"/> + <stroke + android:width="1dp" + android:color="?androidprv:attr/textColorTertiary" /> + </shape> + </item> +</ripple> diff --git a/packages/SystemUI/res/layout/dream_overlay_open_hub_chip.xml b/packages/SystemUI/res/layout/dream_overlay_open_hub_chip.xml new file mode 100644 index 000000000000..be063a9631e8 --- /dev/null +++ b/packages/SystemUI/res/layout/dream_overlay_open_hub_chip.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2024 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. +--> +<com.android.systemui.animation.view.LaunchableImageView + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_height="@dimen/dream_overlay_bottom_affordance_height" + android:layout_width="@dimen/dream_overlay_bottom_affordance_width" + android:layout_gravity="bottom|start" + android:padding="@dimen/dream_overlay_bottom_affordance_padding" + android:scaleType="fitCenter" + android:tint="?android:attr/textColorPrimary" + android:src="@drawable/ic_widgets" + android:contentDescription="@string/accessibility_action_open_communal_hub" /> diff --git a/packages/SystemUI/res/layout/hearing_devices_tile_dialog.xml b/packages/SystemUI/res/layout/hearing_devices_tile_dialog.xml index 2bf6f80c32d0..4a7bef9f48b9 100644 --- a/packages/SystemUI/res/layout/hearing_devices_tile_dialog.xml +++ b/packages/SystemUI/res/layout/hearing_devices_tile_dialog.xml @@ -36,9 +36,8 @@ style="@style/BluetoothTileDialog.Device" android:layout_width="match_parent" android:layout_height="wrap_content" - android:minHeight="@dimen/hearing_devices_preset_spinner_height" android:layout_marginTop="@dimen/hearing_devices_layout_margin" - android:layout_marginBottom="@dimen/hearing_devices_layout_margin" + android:minHeight="@dimen/hearing_devices_preset_spinner_height" android:gravity="center_vertical" android:background="@drawable/hearing_devices_preset_spinner_background" android:popupBackground="@drawable/hearing_devices_preset_spinner_popup_background" @@ -54,9 +53,10 @@ android:visibility="gone"/> <androidx.constraintlayout.widget.Barrier - android:id="@+id/device_barrier" + android:id="@+id/device_function_barrier" android:layout_width="wrap_content" android:layout_height="wrap_content" + app:barrierAllowsGoneWidgets="false" app:barrierDirection="bottom" app:constraint_referenced_ids="device_list,preset_spinner" /> @@ -71,7 +71,8 @@ android:contentDescription="@string/accessibility_hearing_device_pair_new_device" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintTop_toBottomOf="@id/device_barrier" + app:layout_constraintTop_toBottomOf="@id/device_function_barrier" + app:layout_constraintBottom_toTopOf="@id/related_tools_scroll" android:drawableStart="@drawable/ic_add" android:drawablePadding="20dp" android:drawableTint="?android:attr/textColorPrimary" @@ -83,4 +84,32 @@ android:maxLines="1" android:ellipsize="end" /> + <androidx.constraintlayout.widget.Barrier + android:id="@+id/device_barrier" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + app:barrierAllowsGoneWidgets="false" + app:barrierDirection="bottom" + app:constraint_referenced_ids="device_function_barrier, pair_new_device_button" /> + + <HorizontalScrollView + android:id="@+id/related_tools_scroll" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/bluetooth_dialog_layout_margin" + android:layout_marginEnd="@dimen/bluetooth_dialog_layout_margin" + android:layout_marginTop="@dimen/hearing_devices_layout_margin" + android:scrollbars="none" + android:fillViewport="true" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toBottomOf="@id/preset_spinner"> + <LinearLayout + android:id="@+id/related_tools_container" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="horizontal"> + </LinearLayout> + </HorizontalScrollView> + </androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/hearing_tool_item.xml b/packages/SystemUI/res/layout/hearing_tool_item.xml new file mode 100644 index 000000000000..84462d08d4a0 --- /dev/null +++ b/packages/SystemUI/res/layout/hearing_tool_item.xml @@ -0,0 +1,53 @@ +<!-- + Copyright (C) 2024 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/tool_view" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" + android:gravity="center" + android:focusable="true" + android:clickable="true" + android:layout_weight="1"> + <FrameLayout + android:id="@+id/icon_frame" + android:layout_width="@dimen/hearing_devices_tool_icon_frame_width" + android:layout_height="@dimen/hearing_devices_tool_icon_frame_height" + android:background="@drawable/qs_hearing_devices_related_tools_background" + android:focusable="false" > + <ImageView + android:id="@+id/tool_icon" + android:layout_width="@dimen/hearing_devices_tool_icon_size" + android:layout_height="@dimen/hearing_devices_tool_icon_size" + android:layout_gravity="center" + android:scaleType="fitCenter" + android:focusable="false" /> + </FrameLayout> + <TextView + android:id="@+id/tool_name" + android:textDirection="locale" + android:textAlignment="center" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/hearing_devices_layout_margin" + android:ellipsize="end" + android:maxLines="1" + android:textSize="12sp" + android:textAppearance="@style/TextAppearance.Dialog.Body.Message" + android:focusable="false" /> +</LinearLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index e19b3feb08ad..63aa97f542ae 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"het \'n prent gestuur"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Stoor tans skermkiekie..."</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Stoor tans skermskoot in werkprofiel …"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"Stoor tans skermskoot in privaat"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"Skermkiekie is gestoor"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"Kon nie skermkiekie stoor nie"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"Eksterne skerm"</string> diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index b257f0fd46bd..58940bb27d95 100644 --- a/packages/SystemUI/res/values-am/strings.xml +++ b/packages/SystemUI/res/values-am/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ምስል ተልኳል"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"ቅጽበታዊ ገፅ ዕይታ በማስቀመጥ ላይ..."</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"ቅጽበታዊ ገፅ እይታን ወደ የስራ መገለጫ በማስቀመጥ ላይ…"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"ቅጽበታዊ ገጽ ዕይታን ወደ ግል በማስቀመጥ ላይ"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"ቅጽበታዊ ገፅ ዕይታ ተቀምጧል"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"ቅጽበታዊ ገፅ ዕይታን ማስቀመጥ አልተቻለም"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"ውጫዊ ማሳያ"</string> diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index d145ee990024..b74b6cc6759e 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"أرسَل صورة"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"جارٍ حفظ لقطة الشاشة..."</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"جارٍ حفظ لقطة الشاشة في ملف العمل…"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"يتم حاليًا حفظ لقطة الشاشة في الملف الشخصي الخاص"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"تم حفظ لقطة الشاشة."</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"تعذّر حفظ لقطة الشاشة"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"الشاشة الخارجية"</string> diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml index 33c0b7e3b0e7..e25a19e7f128 100644 --- a/packages/SystemUI/res/values-as/strings.xml +++ b/packages/SystemUI/res/values-as/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"এখন প্ৰতিচ্ছবি পঠিয়াইছে"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"স্ক্ৰীনশ্বট ছেভ কৰি থকা হৈছে…"</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"কৰ্মস্থানৰ প্ৰ’ফাইলত স্ক্ৰীনশ্বট ছেভ কৰি থকা হৈছে…"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"ব্যক্তিগত প্ৰ’ফাইলত স্ক্ৰীনশ্বট ছেভ কৰি থকা হৈছে"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"স্ক্ৰীনশ্বট ছেভ কৰা হ’ল"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"স্ক্ৰীনশ্বট ছেভ কৰিব পৰা নগ\'ল"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"বাহ্যিক ডিছপ্লে’"</string> diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml index 5ff6b1ab9ec1..f7c252ea94e4 100644 --- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml +++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"je poslao/la sliku"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Čuvanje snimka ekrana..."</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Snimak ekrana se čuva na poslovnom profilu…"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"Snimak ekrana se čuva na privatnom profilu"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"Snimak ekrana je sačuvan"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"Čuvanje snimka ekrana nije uspelo"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"Spoljni ekran"</string> diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml index aa34a8827d1a..60084389d9fb 100644 --- a/packages/SystemUI/res/values-be/strings.xml +++ b/packages/SystemUI/res/values-be/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"адпраўлены відарыс"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Захаванне скрыншота..."</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Захаванне здымка экрана ў працоўны профіль…"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"Здымак экрана захоўваецца ў прыватны профіль"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"Здымак экрана захаваны"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"Не атрымалася зрабіць здымак экрана"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"Знешні дысплэй"</string> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index 4b305ae92ce8..efaa31f502bd 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"изпратено изображение"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Екранната снимка се запазва..."</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Екранната снимка се запазва в служебния профил…"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"Екранната снимка се запазва в личния потребителски профил"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"Екранната снимка е запазена"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"Не можа да се запази екранна снимка"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"Външен екран"</string> diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml index 87d5ffeccc3f..6decb6169419 100644 --- a/packages/SystemUI/res/values-bn/strings.xml +++ b/packages/SystemUI/res/values-bn/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"একটি ছবি পাঠানো হয়েছে"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"স্ক্রিনশট সেভ করা হচ্ছে..."</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"অফিস প্রোফাইলে স্ক্রিনশট সেভ করা হচ্ছে…"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"ব্যক্তিগত প্রোফাইলে স্ক্রিনশট সেভ করা হয়েছে"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"স্ক্রিনশট সেভ করা হয়েছে"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"স্ক্রিনশট সেভ করা যায়নি"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"এক্সটার্নাল ডিসপ্লে"</string> diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml index 2b80eef03fe2..1aea98254a2e 100644 --- a/packages/SystemUI/res/values-bs/strings.xml +++ b/packages/SystemUI/res/values-bs/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"je poslao/la sliku"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Spašavanje snimka ekrana..."</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Pohranjivanje snimka ekrana na radni profil…"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"Pohranjivanje snimka ekrana na privatni profil"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"Snimak ekrana je sačuvan"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"Nije moguće sačuvati snimak ekrana"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"Vanjski ekran"</string> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index 66875caf7a46..8229e4b4c7ac 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ha enviat una imatge"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"S\'està desant la captura de pantalla..."</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"S\'està desant la captura al perfil de treball…"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"S\'està desant la captura de pantalla al perfil privat"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"S\'ha desat la captura de pantalla"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"No s\'ha pogut desar la captura de pantalla"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"Pantalla externa"</string> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index 706076c3f530..85cef4b65426 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"odesílá obrázek"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Ukládání snímku obrazovky..."</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Ukládání snímku obrazovky do pracovního profilu…"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"Ukládání snímku obrazovky do soukromého profilu"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"Snímek obrazovky byl uložen"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"Snímek obrazovky se nepodařilo uložit"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"Externí displej"</string> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index 8c364473041c..07a07a83e10f 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"Bild gesendet"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Screenshot wird gespeichert..."</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Screenshot wird in Arbeitsprofil gespeichert…"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"Screenshot wird im vertraulichen Profil gespeichert"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"Screenshot gespeichert"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"Screenshot konnte nicht gespeichert werden"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"Äußeres Display"</string> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index 11c348190d14..a1dd5f920a39 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"έστειλε μια εικόνα"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Αποθήκευση στιγμιότυπου οθόνης..."</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Αποθήκευση στιγμιότ. οθόνης στο προφίλ εργασίας…"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"Αποθήκευση στιγμιότυπου οθόνης σε ιδιωτικό"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"Το στιγμιότυπο οθόνης αποθηκεύτηκε"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"Μη δυνατή αποθήκευση του στιγμιότυπου οθόνης"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"Εξωτερική οθόνη"</string> diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml index 6df88b9a74fe..4ac0efe0d853 100644 --- a/packages/SystemUI/res/values-en-rCA/strings.xml +++ b/packages/SystemUI/res/values-en-rCA/strings.xml @@ -372,8 +372,7 @@ <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Pair new device"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Click to pair new device"</string> <string name="hearing_devices_presets_error" msgid="350363093458408536">"Couldn\'t update preset"</string> - <!-- no translation found for hearing_devices_preset_label (7878267405046232358) --> - <skip /> + <string name="hearing_devices_preset_label" msgid="7878267405046232358">"Preset"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Unblock device microphone?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Unblock device camera?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Unblock device camera and microphone?"</string> diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml index 8354cc73888e..67c332eef5f0 100644 --- a/packages/SystemUI/res/values-en-rXC/strings.xml +++ b/packages/SystemUI/res/values-en-rXC/strings.xml @@ -372,8 +372,7 @@ <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Pair new device"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Click to pair new device"</string> <string name="hearing_devices_presets_error" msgid="350363093458408536">"Couldn\'t update preset"</string> - <!-- no translation found for hearing_devices_preset_label (7878267405046232358) --> - <skip /> + <string name="hearing_devices_preset_label" msgid="7878267405046232358">"Preset"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Unblock device microphone?"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Unblock device camera?"</string> <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Unblock device camera and microphone?"</string> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index 32c242d48adb..c6d206b8a746 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"envió una imagen"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Guardando la captura de pantalla..."</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Guardando cap. de pantalla en perfil de trabajo…"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"Guardando captura de pantalla en privado"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"Se guardó la captura de pantalla"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"No se pudo guardar la captura de pantalla"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"Pantalla externa"</string> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index 9a5f70ad3e1b..76effd15c665 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ha enviado una imagen"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Guardando captura..."</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Guardando captura en el perfil de trabajo…"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"Guardando captura de pantalla en espacio privado"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"Se ha guardado la captura de pantalla"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"No se ha podido guardar la captura de pantalla"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"Pantalla externa"</string> diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml index 2697eb312d74..f2bae1b1a488 100644 --- a/packages/SystemUI/res/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"a envoyé une image"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Enregistrement capture écran…"</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Sauv. de la capture dans le profil prof. en cours…"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"Enregistrement de la capture d\'écran dans le profil privé en cours…"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"Capture d\'écran enregistrée"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"Impossible d\'enregistrer la capture d\'écran"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"Écran externe"</string> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index 945d353e01eb..e216c8453b07 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"a envoyé une image"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Enregistrement de la capture d\'écran…"</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Enregistrement de capture d\'écran dans profil pro…"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"Enregistrement de la capture d\'écran dans le profil privé"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"Capture d\'écran enregistrée"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"Impossible d\'enregistrer la capture d\'écran"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"Écran externe"</string> diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml index 913d65fba67c..1ccab5d8dd60 100644 --- a/packages/SystemUI/res/values-gl/strings.xml +++ b/packages/SystemUI/res/values-gl/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"enviou unha imaxe"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Gardando captura de pantalla…"</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Gardando captura de pantalla no perfil de traballo"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"Gardando captura de pantalla no perfil privado"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"Gardouse a captura de pantalla"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"Non se puido gardar a captura de pantalla"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"Pantalla externa"</string> diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml index b6b27301d2bf..e096fff98221 100644 --- a/packages/SystemUI/res/values-gu/strings.xml +++ b/packages/SystemUI/res/values-gu/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"છબી મોકલી"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"સ્ક્રીનશોટ સાચવી રહ્યું છે…"</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"ઑફિસની પ્રોફાઇલમાં સ્ક્રીનશૉટ સાચવી રહ્યાં છીએ…"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"ખાનગી પ્રોફાઇલમાં સ્ક્રીનશૉટ સાચવી રહ્યાં છીએ"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"સ્ક્રીનશૉટ સાચવ્યો"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"સ્ક્રીનશૉટ સાચવી શક્યાં નથી"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"બાહ્ય ડિસ્પ્લે"</string> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index 639a3070d01d..d8c7dcd67f18 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"एक इमेज भेजी गई"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"स्क्रीनशॉट सहेजा जा रहा है..."</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"स्क्रीनशॉट, वर्क प्रोफ़ाइल में सेव किया जा रहा है…"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"स्क्रीनशॉट को निजी प्रोफ़ाइल में सेव किया जा रहा है"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"स्क्रीनशॉट सेव किया गया"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"स्क्रीनशॉट सेव नहीं किया जा सका"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"बाहरी डिसप्ले"</string> diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index 6a53ad159da2..19625bd0c887 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"šalje sliku"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Spremanje snimke zaslona..."</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Spremanje snimke zaslona na poslovni profil…"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"Spremanje snimke zaslona na osobni profil"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"Snimka zaslona je spremljena"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"Snimka zaslona nije spremljena"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"Vanjski prikaz"</string> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index d0b87da25de3..70990336e93f 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"képet küldött"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Képernyőkép mentése..."</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Képernyőkép mentése a munkaprofilba…"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"Képernyőkép mentése a privát területre"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"A képernyőkép mentése sikerült"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"Nem sikerült a képernyőkép mentése"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"Külső kijelző"</string> diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml index 66dd606198da..c539407f4efd 100644 --- a/packages/SystemUI/res/values-hy/strings.xml +++ b/packages/SystemUI/res/values-hy/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"պատկեր է ուղարկվել"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Սքրինշոթը պահվում է..."</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Սքրինշոթը պահվում է աշխատանքային պրոֆիլում…"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"Սքրինշոթը պահվում է մասնավոր պրոֆիլում"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"Սքրինշոթը պահվեց"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"Չհաջողվեց պահել սքրինշոթը"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"Արտաքին էկրան"</string> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index a72cae7bd948..5af06e8f6f11 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"mengirim gambar"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Menyimpan screenshot..."</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Menyimpan screenshot ke profil kerja …"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"Menyimpan screenshot ke profil privasi"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"Screenshot disimpan"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"Tidak dapat menyimpan screenshot"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"Layar Eksternal"</string> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index d19e9a1cd630..71d0c6be20b6 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"נשלחה תמונה"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"המערכת שומרת את צילום המסך..."</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"צילום המסך נשמר בפרופיל העבודה…"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"צילום המסך נשמר בפרופיל האישי"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"צילום המסך נשמר"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"לא ניתן היה לשמור את צילום המסך"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"תצוגה במסך חיצוני"</string> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index f29dee099327..d6dc93c8887f 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"画像を送信しました"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"スクリーンショットを保存しています..."</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"スクリーンショットを仕事用プロファイルに保存中…"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"スクリーンショットをプライベートに保存しています"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"スクリーンショットを保存しました"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"スクリーンショット保存エラー"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"外側ディスプレイ"</string> diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml index e37c16b04689..2670e4542344 100644 --- a/packages/SystemUI/res/values-ka/strings.xml +++ b/packages/SystemUI/res/values-ka/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"გაიგზავნა სურათი"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"ეკრანის სურათის შენახვა…"</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"მიმდინარეობს ეკრანის ანაბეჭდის შენახვა სამუშაო პროფილში…"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"მიმდინარეობს ეკრანის ანაბეჭდის შენახვა კერძო სივრცეში"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"ეკრანის ანაბეჭდი შენახულია"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"ეკრანის ანაბეჭდის შენახვა ვერ მოხერხდა"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"გარე ეკრანი"</string> diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml index 2618198392ee..c709bbec2b1f 100644 --- a/packages/SystemUI/res/values-kk/strings.xml +++ b/packages/SystemUI/res/values-kk/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"сурет жіберілді"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Скриншотты сақтауда…"</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Скриншот жұмыс профиліне сақталып жатыр…"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"Скриншот жеке профильде сақталып жатыр."</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"Скриншот сақталды"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"Скриншот сақталмады"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"Сыртқы дисплей"</string> diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml index 88259f34260a..042e7481370c 100644 --- a/packages/SystemUI/res/values-km/strings.xml +++ b/packages/SystemUI/res/values-km/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"បានផ្ញើរូបភាព"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"កំពុងរក្សាទុករូបថតអេក្រង់..."</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"កំពុងរក្សាទុករូបថតអេក្រង់ទៅកម្រងព័ត៌មានការងារ…"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"កំពុងរក្សាទុករូបថតអេក្រង់ទៅក្នុងកម្រងព័ត៌មានឯកជន"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"បានរក្សាទុករូបថតអេក្រង់"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"មិនអាចរក្សាទុករូបថតអេក្រង់បានទេ"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"ផ្ទាំងអេក្រង់ខាងក្រៅ"</string> diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml index cd14d0ef6925..8b1ab5f3b7e3 100644 --- a/packages/SystemUI/res/values-kn/strings.xml +++ b/packages/SystemUI/res/values-kn/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ಚಿತ್ರವನ್ನು ಕಳುಹಿಸಲಾಗಿದೆ"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"ಸ್ಕ್ರೀನ್ಶಾಟ್ ಉಳಿಸಲಾಗುತ್ತಿದೆ…"</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"ಉದ್ಯೋಗ ಪ್ರೊಫೈಲ್ಗೆ ಸ್ಕ್ರೀನ್ಶಾಟ್ ಉಳಿಸಲಾಗುತ್ತಿದೆ…"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"ಸ್ಕ್ರೀನ್ಶಾಟ್ ಅನ್ನು ಖಾಸಗಿ ಪ್ರೊಫೈಲ್ಗೆ ಸೇವ್ ಮಾಡಲಾಗುತ್ತಿದೆ"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"ಸ್ಕ್ರೀನ್ಶಾಟ್ ಅನ್ನು ಸೇವ್ ಮಾಡಲಾಗಿದೆ"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"ಸ್ಕ್ರೀನ್ಶಾಟ್ ಅನ್ನು ಉಳಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"ಬಾಹ್ಯ ಡಿಸ್ಪ್ಲೇ"</string> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index 0622dc5e5ed2..bec3cc1e61f2 100644 --- a/packages/SystemUI/res/values-lt/strings.xml +++ b/packages/SystemUI/res/values-lt/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"išsiuntė vaizdą"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Išsaugoma ekrano kopija..."</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Išsaugoma ekrano kopija darbo profilyje…"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"Ekrano kopija išsaugoma privačiame profilyje"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"Ekrano kopija išsaugota"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"Ekrano kopijos išsaugoti nepavyko"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"Išorinė pateiktis"</string> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index 7b7ba80d3ba5..001f6a027ce4 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"nosūtīts attēls"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Notiek ekrānuzņēmuma saglabāšana..."</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Notiek ekrānuzņēmuma saglabāšana darba profilā…"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"Ekrānuzņēmums tiek saglabāts privātajā profilā"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"Ekrānuzņēmums saglabāts"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"Ekrānuzņēmumu neizdevās saglabāt."</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"Ārējais displejs"</string> diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml index b9571ce2beb5..12bf5689525b 100644 --- a/packages/SystemUI/res/values-mk/strings.xml +++ b/packages/SystemUI/res/values-mk/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"испрати слика"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Сликата на екранот се зачувува..."</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Се зачувува слика од екранот на вашиот работен профил…"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"Сликата од екранот се зачувува во приватниот профил"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"Сликата од екранот е зачувана"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"Не може да се зачува слика од екранот"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"Надворешен екран"</string> diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml index 18fc5b498cee..d165242e49e1 100644 --- a/packages/SystemUI/res/values-ml/strings.xml +++ b/packages/SystemUI/res/values-ml/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ചിത്രം അയച്ചു"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"സ്ക്രീൻഷോട്ട് സംരക്ഷിക്കുന്നു..."</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"ഔദ്യോഗിക പ്രൊഫൈലിലേക്ക് സ്ക്രീൻഷോട്ട് സംരക്ഷിക്കുന്നു…"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"സ്ക്രീൻഷോട്ട് സ്വകാര്യമാക്കി സംരക്ഷിക്കുന്നു"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"സ്ക്രീൻഷോട്ട് സംരക്ഷിച്ചു"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"സ്ക്രീൻഷോട്ട് സംരക്ഷിക്കാനായില്ല"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"ബാഹ്യ ഡിസ്പ്ലേ"</string> diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml index 57e58fa0d32f..017a6c8067a5 100644 --- a/packages/SystemUI/res/values-mr/strings.xml +++ b/packages/SystemUI/res/values-mr/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"इमेज पाठवली आहे"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"स्क्रीनशॉट सेव्ह करत आहे…"</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"कार्य प्रोफाइलवर स्क्रीनशॉट सेव्ह करत आहे…"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"स्क्रीनशॉट खाजगीमध्ये सेव्ह करत आहे"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"स्क्रीनशॉट सेव्ह केला"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"स्क्रीनशॉट सेव्ह करू शकलो नाही"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"बाह्य डिस्प्ले"</string> diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml index 651d4989caef..23e4559d97a0 100644 --- a/packages/SystemUI/res/values-ms/strings.xml +++ b/packages/SystemUI/res/values-ms/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"menghantar imej"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Menyimpan tangkapan skrin..."</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Menyimpan tangkapan skrin ke profil kerja…"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"Menyimpan tangkapan skrin pada profil peribadi"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"Tangkapan skrin disimpan"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"Tidak dapat menyimpan tangkapan skrin"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"Paparan Luaran"</string> diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index edfbf09ed42b..dbcfaa366656 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"har sendt et bilde"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Lagrer skjermdumpen …"</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Lagrer skjermdumpen i jobbprofilen …"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"Lagrer skjermdump i den private profilen"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"Skjermdumpen er lagret"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"Kunne ikke lagre skjermdump"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"Ekstern skjerm"</string> diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml index f6650eecb1ef..29a5e7302530 100644 --- a/packages/SystemUI/res/values-or/strings.xml +++ b/packages/SystemUI/res/values-or/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ଏକ ଛବି ପଠାଯାଇଛି"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"ସ୍କ୍ରୀନଶଟ୍ ସେଭ୍ କରାଯାଉଛି…"</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"ୱାର୍କ ପ୍ରୋଫାଇଲରେ ସ୍କ୍ରିନସଟ ସେଭ କରାଯାଉଛି…"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"ପ୍ରାଇଭେଟରେ ସ୍କ୍ରିନସଟକୁ ସେଭ କରାଯାଉଛି"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"ସ୍କ୍ରୀନଶଟ୍ ସେଭ୍ ହୋଇଛି"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"ସ୍କ୍ରୀନ୍ଶଟ୍ ସେଭ୍ କରିହେବ ନାହିଁ"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"ଏକ୍ସଟର୍ନଲ ଡିସପ୍ଲେ"</string> diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml index 3886e781ab14..624557597677 100644 --- a/packages/SystemUI/res/values-pa/strings.xml +++ b/packages/SystemUI/res/values-pa/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ਚਿੱਤਰ ਭੇਜਿਆ ਗਿਆ"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਸੁਰੱਖਿਅਤ ਕਰ ਰਿਹਾ ਹੈ…"</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ \'ਤੇ ਰੱਖਿਅਤ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ…"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਨੂੰ ਪ੍ਰਾਈਵੇਟ ਵਜੋਂ ਰੱਖਿਅਤ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਰੱਖਿਅਤ ਕੀਤਾ ਗਿਆ"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਰੱਖਿਅਤ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"ਬਾਹਰੀ ਡਿਸਪਲੇ"</string> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index c8422cb3cfa9..e8e6f09d0d41 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"wysłano obraz"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Zapisywanie zrzutu ekranu..."</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Zapisuję zrzut ekranu w profilu służbowym…"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"Zapisuję zrzut ekranu w profilu prywatnym"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"Zrzut ekranu został zapisany"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"Nie udało się zapisać zrzutu ekranu"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"Wyświetlacz zewnętrzny"</string> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index b399cfa950bb..b6614c671126 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"a trimis o imagine"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Se salvează captura de ecran..."</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Se salvează captura în profilul de serviciu…"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"Se salvează captura de ecran în profilul privat"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"Captură de ecran salvată"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"Nu s-a putut salva captura de ecran"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"Afișaj extern"</string> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index a79818fed6a3..d6fa6abcbdc6 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"отправлено изображение"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Сохранение..."</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Сохранение скриншота в рабочем профиле…"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"Сохранение скриншота в частный профиль…"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"Скриншот сохранен"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"Не удалось сохранить скриншот"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"Внешний дисплей"</string> diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml index 28d3220912b1..3de42252dfee 100644 --- a/packages/SystemUI/res/values-si/strings.xml +++ b/packages/SystemUI/res/values-si/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"රූපයක් එවන ලදී"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"තිර රුව සුරැකෙමින් පවතී…"</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"කාර්යාල පැතිකඩ වෙත තිර රුව සුරකිමින්…"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"තිර රුව පුද්ගලික ලෙස සුරැකේ"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"තිර රුව සුරකින ලදී"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"තිර රුව සුරැකිය නොහැකි විය"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"බාහිර සංදර්ශකය"</string> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index 051690b22399..cb8cf5beb172 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"odoslal(a) obrázok"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Prebieha ukladanie snímky obrazovky..."</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Ukladá sa snímka obrazovky do pracovného profilu…"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"Snímka obrazovky sa ukladá do súkromného profilu"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"Snímka obrazovky bola uložená"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"Snímku obrazovky sa nepodarilo uložiť"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"Externá obrazovka"</string> diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index 13bf885474d8..2b851b4b522b 100644 --- a/packages/SystemUI/res/values-sr/strings.xml +++ b/packages/SystemUI/res/values-sr/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"је послао/ла слику"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Чување снимка екрана..."</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Снимак екрана се чува на пословном профилу…"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"Снимак екрана се чува на приватном профилу"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"Снимак екрана је сачуван"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"Чување снимка екрана није успело"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"Спољни екран"</string> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index 2fec9aa54989..0d1614fa66bd 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"har skickat en bild"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Skärmbilden sparas ..."</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Sparar skärmbild i jobbprofilen …"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"Sparar skärmbilden till privat profil"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"Skärmbilden har sparats"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"Det gick inte att spara skärmbilden"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"Extern skärm"</string> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index 1be2de14f788..670a85c181f5 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"imetuma picha"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Inahifadhi picha ya skrini..."</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Inahifadhi picha ya skrini kwenye wasifu wa kazini…"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"Inahifadhi picha ya skrini kwenye wasifu wa faragha"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"Imehifadhi picha ya skrini"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"Imeshindwa kuhifadhi picha ya skrini"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"Skrini ya Nje"</string> diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml index f716e612e637..224ed3989819 100644 --- a/packages/SystemUI/res/values-ta/strings.xml +++ b/packages/SystemUI/res/values-ta/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"படம் அனுப்பப்பட்டது"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"ஸ்க்ரீன் ஷாட்டைச் சேமிக்கிறது…"</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"பணிக் கணக்கில் ஸ்கிரீன்ஷாட் சேமிக்கப்படுகிறது…"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"தனிப்பட்ட சுயவிவரத்தில் ஸ்கிரீன்ஷாட் சேமிக்கப்படுகிறது"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"ஸ்கிரீன்ஷாட் சேமிக்கப்பட்டது"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"ஸ்கிரீன் ஷாட்டைச் சேமிக்க முடியவில்லை"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"வெளித் திரை"</string> diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml index 241e95248040..26bb871c7deb 100644 --- a/packages/SystemUI/res/values-te/strings.xml +++ b/packages/SystemUI/res/values-te/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ఇమేజ్ను పంపారు"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"స్క్రీన్షాట్ను సేవ్ చేస్తోంది…"</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"స్క్రీన్షాట్ను వర్క్ ప్రొఫైల్కు సేవ్ చేస్తోంది…"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"స్క్రీన్షాట్ను ప్రైవేట్ ప్రొఫైల్కు సేవ్ చేస్తోంది"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"స్క్రీన్షాట్ సేవ్ చేయబడింది"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"స్క్రీన్షాట్ని సేవ్ చేయడం సాధ్యం కాలేదు"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"వెలుపలి డిస్ప్లే"</string> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index b063a8f0a076..02ee0175f0e7 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ส่งรูปภาพ"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"กำลังบันทึกภาพหน้าจอ..."</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"กำลังบันทึกภาพหน้าจอไปยังโปรไฟล์งาน…"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"กำลังบันทึกภาพหน้าจอลงในโปรไฟล์ส่วนตัว"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"บันทึกภาพหน้าจอแล้ว"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"บันทึกภาพหน้าจอไม่ได้"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"จอแสดงผลภายนอก"</string> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index 9bc0cc02dbe2..db84644d7a5e 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"bir resim gönderildi"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Ekran görüntüsü kaydediliyor..."</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Ekran görüntüsü iş profiline kaydediliyor…"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"Ekran görüntüsü özel profile kaydediliyor"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"Ekran görüntüsü kaydedildi"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"Ekran görüntüsü kaydedilemedi"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"Harici Ekran"</string> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index 2f648128e964..1afcf2ac9065 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"надіслане зображення"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Збереження знімка екрана..."</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Зберігання знімка екрана в робочому профілі…"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"Збереження знімка екрана в приватному профілі"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"Знімок екрана збережено"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"Не вдалося зберегти знімок екрана"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"Зовнішній дисплей"</string> diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml index e8d2cf441e27..d7c4c88cd802 100644 --- a/packages/SystemUI/res/values-ur/strings.xml +++ b/packages/SystemUI/res/values-ur/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ایک تصویر بھیجی"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"اسکرین شاٹ محفوظ ہو رہا ہے…"</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"اسکرین شاٹ دفتری پروفائل میں محفوظ کیا جا رہا ہے…"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"اسکرین شاٹ کو نجی پروفائل میں محفوظ کیا جا رہا ہے"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"اسکرین شاٹ محفوظ ہو گیا"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"اسکرین شاٹ کو محفوظ نہیں کیا جا سکا"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"خارجی ڈسپلے"</string> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index 810fa4aca1cf..1a3055c3f226 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"发送了一张图片"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"正在保存屏幕截图..."</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"正在将屏幕截图保存到工作资料…"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"正在将屏幕截图保存到个人资料"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"已保存屏幕截图"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"无法保存屏幕截图"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"外部显示屏"</string> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index f253d4e528a8..6644b53591a8 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -76,8 +76,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"uthumele isithombe"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Ilondoloz umfanekiso weskrini..."</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Ilondoloza isithombe-skrini kuphrofayela yomsebenzi…"</string> - <!-- no translation found for screenshot_saving_private_profile (8934706048497093297) --> - <skip /> + <string name="screenshot_saving_private_profile" msgid="8934706048497093297">"Ilondoloza isithombe-skrini sibe esigodliwe"</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"Isithombe-skrini silondoloziwe"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"Ayikwazanga ukulondoloza isithombe-skrini"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"Isiboniso Sangaphandle"</string> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 638785402055..fb883640c9a9 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -125,6 +125,20 @@ <!-- Use collapsed layout for media player in landscape QQS --> <bool name="config_quickSettingsMediaLandscapeCollapsed">true</bool> + <!-- For hearing devices related tool list. Need to be in ComponentName format (package/class). + Should be activity to be launched. + Already contains tool that holds intent: "com.android.settings.action.live_caption". + Maximum number is 3. --> + <string-array name="config_quickSettingsHearingDevicesRelatedToolName" translatable="false"> + </string-array> + + <!-- The drawable resource names. If provided, it will replace the corresponding icons in + config_quickSettingsHearingDevicesRelatedToolName. Can be empty to use original icons. + Already contains tool that holds intent: "com.android.settings.action.live_caption". + Maximum number is 3. --> + <string-array name="config_quickSettingsHearingDevicesRelatedToolIcon" translatable="false"> + </string-array> + <!-- Show indicator for Wifi on but not connected. --> <bool name="config_showWifiIndicatorWhenEnabled">false</bool> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 7d7a5d4dbf14..edd3d77555f7 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1778,6 +1778,9 @@ <dimen name="hearing_devices_preset_spinner_text_padding_vertical">15dp</dimen> <dimen name="hearing_devices_preset_spinner_arrow_size">24dp</dimen> <dimen name="hearing_devices_preset_spinner_background_radius">28dp</dimen> + <dimen name="hearing_devices_tool_icon_frame_width">94dp</dimen> + <dimen name="hearing_devices_tool_icon_frame_height">64dp</dimen> + <dimen name="hearing_devices_tool_icon_size">28dp</dimen> <!-- Height percentage of the parent container occupied by the communal view --> <item name="communal_source_height_percentage" format="float" type="dimen">0.80</item> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 6f2806d80ef3..c038a8207d43 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -917,6 +917,8 @@ <string name="hearing_devices_presets_error">Couldn\'t update preset</string> <!-- QuickSettings: Title for hearing aids presets. Preset is a set of hearing aid settings. User can apply different settings in different environments (e.g. Outdoor, Restaurant, Home) [CHAR LIMIT=40]--> <string name="hearing_devices_preset_label">Preset</string> + <!-- QuickSettings: Tool name for hearing devices dialog related tools [CHAR LIMIT=40]--> + <string name="live_caption_title">Live Caption</string> <!--- Title of dialog triggered if the microphone is disabled but an app tried to access it. [CHAR LIMIT=150] --> <string name="sensor_privacy_start_use_mic_dialog_title">Unblock device microphone?</string> diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt index 3f3bb0bc94b6..86c807bf9d07 100644 --- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt +++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt @@ -15,12 +15,12 @@ */ package com.android.keyguard -import android.os.Trace import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import android.content.IntentFilter import android.content.res.Resources +import android.os.Trace import android.text.format.DateFormat import android.util.Log import android.util.TypedValue @@ -466,15 +466,11 @@ constructor( largeRegionSampler?.stopRegionSampler() smallTimeListener?.stop() largeTimeListener?.stop() - clock - ?.smallClock - ?.view - ?.removeOnAttachStateChangeListener(smallClockOnAttachStateChangeListener) + clock?.apply { + smallClock.view.removeOnAttachStateChangeListener(smallClockOnAttachStateChangeListener) + largeClock.view.removeOnAttachStateChangeListener(largeClockOnAttachStateChangeListener) + } smallClockFrame?.viewTreeObserver?.removeOnGlobalLayoutListener(onGlobalLayoutListener) - clock - ?.largeClock - ?.view - ?.removeOnAttachStateChangeListener(largeClockOnAttachStateChangeListener) } /** @@ -505,15 +501,17 @@ constructor( } } - private fun updateFontSizes() { + fun updateFontSizes() { clock?.run { - smallClock.events.onFontSettingChanged( - resources.getDimensionPixelSize(R.dimen.small_clock_text_size).toFloat() - ) + smallClock.events.onFontSettingChanged(getSmallClockSizePx()) largeClock.events.onFontSettingChanged(getLargeClockSizePx()) } } + private fun getSmallClockSizePx(): Float { + return resources.getDimensionPixelSize(R.dimen.small_clock_text_size).toFloat() + } + private fun getLargeClockSizePx(): Float { return if (largeClockOnSecondaryDisplay) { resources.getDimensionPixelSize(R.dimen.presentation_clock_text_size).toFloat() @@ -549,9 +547,8 @@ constructor( it.copy(value = 1f - it.value) }, keyguardTransitionInteractor.transition(Edge.create(LOCKSCREEN, AOD)), - ).filter { - it.transitionState != TransitionState.FINISHED - } + ) + .filter { it.transitionState != TransitionState.FINISHED } .collect { handleDoze(it.value) } } } @@ -574,28 +571,27 @@ constructor( internal fun listenForAnyStateToLockscreenTransition(scope: CoroutineScope): Job { return scope.launch { keyguardTransitionInteractor - .transitionStepsToState(LOCKSCREEN) - .filter { it.transitionState == TransitionState.STARTED } - .filter { it.from != AOD } - .collect { handleDoze(0f) } + .transitionStepsToState(LOCKSCREEN) + .filter { it.transitionState == TransitionState.STARTED } + .filter { it.from != AOD } + .collect { handleDoze(0f) } } } /** - * When keyguard is displayed due to pulsing notifications when AOD is off, - * we should make sure clock is in dozing state instead of LS state + * When keyguard is displayed due to pulsing notifications when AOD is off, we should make sure + * clock is in dozing state instead of LS state */ @VisibleForTesting internal fun listenForAnyStateToDozingTransition(scope: CoroutineScope): Job { return scope.launch { keyguardTransitionInteractor - .transitionStepsToState(DOZING) - .filter { it.transitionState == TransitionState.FINISHED } - .collect { handleDoze(1f) } + .transitionStepsToState(DOZING) + .filter { it.transitionState == TransitionState.FINISHED } + .collect { handleDoze(1f) } } } - @VisibleForTesting internal fun listenForDozing(scope: CoroutineScope): Job { return scope.launch { diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java index 27b2b92ab899..63ad41a808dc 100644 --- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java +++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java @@ -20,7 +20,6 @@ import static androidx.dynamicanimation.animation.DynamicAnimation.TRANSLATION_X import static androidx.dynamicanimation.animation.FloatPropertyCompat.createFloatPropertyCompat; import static com.android.systemui.classifier.Classifier.NOTIFICATION_DISMISS; -import static com.android.systemui.flags.Flags.SWIPE_UNCLEARED_TRANSIENT_VIEW_FIX; import static com.android.systemui.statusbar.notification.NotificationUtils.logKey; import android.animation.Animator; @@ -481,16 +480,11 @@ public class SwipeHelper implements Gefingerpoken, Dumpable { updateSwipeProgressFromOffset(animView, canBeDismissed); mDismissPendingMap.remove(animView); boolean wasRemoved = false; - if (animView instanceof ExpandableNotificationRow) { - ExpandableNotificationRow row = (ExpandableNotificationRow) animView; - if (mFeatureFlags.isEnabled(SWIPE_UNCLEARED_TRANSIENT_VIEW_FIX)) { - // If the view is already removed from its parent and added as Transient, - // we need to clean the transient view upon animation end - wasRemoved = row.getTransientContainer() != null - || row.getParent() == null || row.isRemoved(); - } else { - wasRemoved = row.isRemoved(); - } + if (animView instanceof ExpandableNotificationRow row) { + // If the view is already removed from its parent and added as Transient, + // we need to clean the transient view upon animation end + wasRemoved = row.getTransientContainer() != null + || row.getParent() == null || row.isRemoved(); } if (!mCancelled || wasRemoved) { mCallback.onChildDismissed(animView); diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/data/repository/AccessibilityQsShortcutsRepository.kt b/packages/SystemUI/src/com/android/systemui/accessibility/data/repository/AccessibilityQsShortcutsRepository.kt index 4069cece7790..63791f9228c0 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/data/repository/AccessibilityQsShortcutsRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/accessibility/data/repository/AccessibilityQsShortcutsRepository.kt @@ -30,6 +30,7 @@ import com.android.systemui.qs.pipeline.shared.TileSpec import com.android.systemui.qs.tiles.ColorCorrectionTile import com.android.systemui.qs.tiles.ColorInversionTile import com.android.systemui.qs.tiles.FontScalingTile +import com.android.systemui.qs.tiles.HearingDevicesTile import com.android.systemui.qs.tiles.OneHandedModeTile import com.android.systemui.qs.tiles.ReduceBrightColorsTile import javax.inject.Inject @@ -74,6 +75,8 @@ constructor( .REDUCE_BRIGHT_COLORS_TILE_SERVICE_COMPONENT_NAME, FontScalingTile.TILE_SPEC to AccessibilityShortcutController.FONT_SIZE_TILE_COMPONENT_NAME, + HearingDevicesTile.TILE_SPEC to + AccessibilityShortcutController.ACCESSIBILITY_HEARING_AIDS_TILE_COMPONENT_NAME ) } diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java index 28dd2338ff2b..961d6aa1b821 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java @@ -25,10 +25,14 @@ import android.bluetooth.BluetoothHapClient; import android.bluetooth.BluetoothHapPresetInfo; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.content.res.Resources; import android.media.AudioManager; import android.os.Bundle; import android.os.Handler; import android.provider.Settings; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.View.Visibility; @@ -36,7 +40,10 @@ import android.view.accessibility.AccessibilityNodeInfo; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.Button; +import android.widget.ImageView; +import android.widget.LinearLayout; import android.widget.Spinner; +import android.widget.TextView; import android.widget.Toast; import androidx.annotation.NonNull; @@ -69,6 +76,7 @@ import dagger.assisted.Assisted; import dagger.assisted.AssistedFactory; import dagger.assisted.AssistedInject; +import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; @@ -78,12 +86,15 @@ import java.util.stream.Collectors; */ public class HearingDevicesDialogDelegate implements SystemUIDialog.Delegate, HearingDeviceItemCallback, BluetoothCallback { - + private static final String TAG = "HearingDevicesDialogDelegate"; @VisibleForTesting static final String ACTION_BLUETOOTH_DEVICE_DETAILS = "com.android.settings.BLUETOOTH_DEVICE_DETAIL_SETTINGS"; private static final String EXTRA_SHOW_FRAGMENT_ARGUMENTS = ":settings:show_fragment_args"; private static final String KEY_BLUETOOTH_ADDRESS = "device_address"; + @VisibleForTesting + static final Intent LIVE_CAPTION_INTENT = new Intent( + "com.android.settings.action.live_caption"); private final SystemUIDialog.Factory mSystemUIDialogFactory; private final DialogTransitionAnimator mDialogTransitionAnimator; private final ActivityStarter mActivityStarter; @@ -102,6 +113,7 @@ public class HearingDevicesDialogDelegate implements SystemUIDialog.Delegate, private Spinner mPresetSpinner; private ArrayAdapter<String> mPresetInfoAdapter; private Button mPairButton; + private LinearLayout mRelatedToolsContainer; private final HearingDevicesPresetsController.PresetCallback mPresetCallback = new HearingDevicesPresetsController.PresetCallback() { @Override @@ -253,10 +265,14 @@ public class HearingDevicesDialogDelegate implements SystemUIDialog.Delegate, mPairButton = dialog.requireViewById(R.id.pair_new_device_button); mDeviceList = dialog.requireViewById(R.id.device_list); mPresetSpinner = dialog.requireViewById(R.id.preset_spinner); + mRelatedToolsContainer = dialog.requireViewById(R.id.related_tools_container); setupDeviceListView(dialog); setupPresetSpinner(dialog); setupPairNewDeviceButton(dialog, mShowPairNewDevice ? VISIBLE : GONE); + if (com.android.systemui.Flags.hearingDevicesDialogRelatedTools()) { + setupRelatedToolsView(dialog); + } } @Override @@ -351,6 +367,34 @@ public class HearingDevicesDialogDelegate implements SystemUIDialog.Delegate, } } + private void setupRelatedToolsView(SystemUIDialog dialog) { + final Context context = dialog.getContext(); + final List<ToolItem> toolItemList = new ArrayList<>(); + final String[] toolNameArray; + final String[] toolIconArray; + + ToolItem preInstalledItem = getLiveCaption(context); + if (preInstalledItem != null) { + toolItemList.add(preInstalledItem); + } + try { + toolNameArray = context.getResources().getStringArray( + R.array.config_quickSettingsHearingDevicesRelatedToolName); + toolIconArray = context.getResources().getStringArray( + R.array.config_quickSettingsHearingDevicesRelatedToolIcon); + toolItemList.addAll( + HearingDevicesToolItemParser.parseStringArray(context, toolNameArray, + toolIconArray)); + } catch (Resources.NotFoundException e) { + Log.i(TAG, "No hearing devices related tool config resource"); + } + final int listSize = toolItemList.size(); + for (int i = 0; i < listSize; i++) { + View view = createHearingToolView(context, toolItemList.get(i)); + mRelatedToolsContainer.addView(view); + } + } + private void refreshPresetInfoAdapter(List<BluetoothHapPresetInfo> presetInfos, int activePresetIndex) { mPresetInfoAdapter.clear(); @@ -400,6 +444,40 @@ public class HearingDevicesDialogDelegate implements SystemUIDialog.Delegate, return null; } + @NonNull + private View createHearingToolView(Context context, ToolItem item) { + View view = LayoutInflater.from(context).inflate(R.layout.hearing_tool_item, + mRelatedToolsContainer, false); + ImageView icon = view.requireViewById(R.id.tool_icon); + TextView text = view.requireViewById(R.id.tool_name); + view.setContentDescription(item.getToolName()); + icon.setImageDrawable(item.getToolIcon()); + text.setText(item.getToolName()); + Intent intent = item.getToolIntent(); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); + view.setOnClickListener( + v -> { + dismissDialogIfExists(); + mActivityStarter.postStartActivityDismissingKeyguard(intent, /* delay= */ 0, + mDialogTransitionAnimator.createActivityTransitionController(view)); + }); + return view; + } + + private ToolItem getLiveCaption(Context context) { + final PackageManager packageManager = context.getPackageManager(); + LIVE_CAPTION_INTENT.setPackage(packageManager.getSystemCaptionsServicePackageName()); + final List<ResolveInfo> resolved = packageManager.queryIntentActivities(LIVE_CAPTION_INTENT, + /* flags= */ 0); + if (!resolved.isEmpty()) { + return new ToolItem(context.getString(R.string.live_caption_title), + context.getDrawable(R.drawable.ic_volume_odi_captions), + LIVE_CAPTION_INTENT); + } + + return null; + } + private void dismissDialogIfExists() { if (mDialog != null) { mDialog.dismiss(); diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesToolItemParser.java b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesToolItemParser.java new file mode 100644 index 000000000000..2006726e6847 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesToolItemParser.java @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2024 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.accessibility.hearingaid; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; +import android.content.res.Resources; +import android.graphics.drawable.Drawable; +import android.util.Log; + +import androidx.annotation.VisibleForTesting; + +import com.google.common.collect.ImmutableList; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Utility class for managing and parsing tool items related to hearing devices. + */ +public class HearingDevicesToolItemParser { + private static final String TAG = "HearingDevicesToolItemParser"; + private static final String SPLIT_DELIMITER = "/"; + private static final String RES_TYPE = "drawable"; + @VisibleForTesting + static final int MAX_NUM = 3; + + /** + * Parses the string arrays to create a list of {@link ToolItem}. + * + * This method validates the structure of {@code toolNameArray} and {@code toolIconArray}. + * If {@code toolIconArray} is empty or mismatched in length with {@code toolNameArray}, the + * icon from {@link ActivityInfo#loadIcon(PackageManager)} will be used instead. + * + * @param context A valid context. + * @param toolNameArray An array of tool names in the format of {@link ComponentName}. + * @param toolIconArray An optional array of resource names for tool icons (can be empty). + * @return A list of {@link ToolItem} or an empty list if there are errors during parsing. + */ + public static ImmutableList<ToolItem> parseStringArray(Context context, String[] toolNameArray, + String[] toolIconArray) { + if (toolNameArray.length == 0) { + Log.i(TAG, "Empty hearing device related tool name in array."); + return ImmutableList.of(); + } + // For the performance concern, especially `getIdentifier` in `parseValidIcon`, we will + // limit the maximum number. + String[] nameArrayCpy = Arrays.copyOfRange(toolNameArray, 0, + Math.min(toolNameArray.length, MAX_NUM)); + String[] iconArrayCpy = Arrays.copyOfRange(toolIconArray, 0, + Math.min(toolIconArray.length, MAX_NUM)); + + final PackageManager packageManager = context.getPackageManager(); + final ImmutableList.Builder<ToolItem> toolItemList = ImmutableList.builder(); + final List<ActivityInfo> activityInfoList = parseValidActivityInfo(context, nameArrayCpy); + final List<Drawable> iconList = parseValidIcon(context, iconArrayCpy); + final int size = activityInfoList.size(); + // Only use custom icon if provided icon's list size is equal to provided name's list size. + final boolean useCustomIcons = (size == iconList.size()); + + for (int i = 0; i < size; i++) { + toolItemList.add(new ToolItem( + activityInfoList.get(i).loadLabel(packageManager).toString(), + useCustomIcons ? iconList.get(i) + : activityInfoList.get(i).loadIcon(packageManager), + new Intent(Intent.ACTION_MAIN).setComponent( + activityInfoList.get(i).getComponentName()) + )); + } + + return toolItemList.build(); + } + + private static List<ActivityInfo> parseValidActivityInfo(Context context, + String[] toolNameArray) { + final PackageManager packageManager = context.getPackageManager(); + final List<ActivityInfo> activityInfoList = new ArrayList<>(); + for (String toolName : toolNameArray) { + String[] nameParts = toolName.split(SPLIT_DELIMITER); + if (nameParts.length == 2) { + ComponentName componentName = ComponentName.unflattenFromString(toolName); + try { + ActivityInfo activityInfo = packageManager.getActivityInfo( + componentName, /* flags= */ 0); + activityInfoList.add(activityInfo); + } catch (PackageManager.NameNotFoundException e) { + Log.e(TAG, "Unable to find hearing device related tool: " + + componentName.flattenToString()); + } + } else { + Log.e(TAG, "Malformed hearing device related tool name item in array: " + + toolName); + } + } + return activityInfoList; + } + + private static List<Drawable> parseValidIcon(Context context, String[] toolIconArray) { + final List<Drawable> drawableList = new ArrayList<>(); + for (String icon : toolIconArray) { + int resId = context.getResources().getIdentifier(icon, RES_TYPE, + context.getPackageName()); + try { + drawableList.add(context.getDrawable(resId)); + } catch (Resources.NotFoundException e) { + Log.e(TAG, "Resource does not exist: " + icon); + } + } + return drawableList; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/ToolItem.kt b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/ToolItem.kt new file mode 100644 index 000000000000..66bb2b5e2328 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/ToolItem.kt @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2024 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.accessibility.hearingaid + +import android.content.Intent +import android.graphics.drawable.Drawable + +data class ToolItem( + var toolName: String = "", + var toolIcon: Drawable, + var toolIntent: Intent, +) diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt index 7c41b75d7105..40a141dcec77 100644 --- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt @@ -20,6 +20,8 @@ import android.app.admin.DevicePolicyManager import android.app.admin.DevicePolicyResources import android.content.Context import android.graphics.Bitmap +import androidx.compose.ui.input.key.KeyEvent +import androidx.compose.ui.input.key.type import androidx.core.graphics.drawable.toBitmap import com.android.compose.animation.scene.Back import com.android.compose.animation.scene.SceneKey @@ -326,7 +328,8 @@ class BouncerViewModel( { message }, failedAttempts, remainingAttempts, - ) ?: message + ) + ?: message } else { message } @@ -343,7 +346,8 @@ class BouncerViewModel( .KEYGUARD_DIALOG_FAILED_ATTEMPTS_ERASING_PROFILE, { message }, failedAttempts, - ) ?: message + ) + ?: message } else { message } @@ -377,6 +381,19 @@ class BouncerViewModel( Swipe(SwipeDirection.Down) to UserActionResult(prevScene), ) + /** + * Notifies that a key event has occurred. + * + * @return `true` when the [KeyEvent] was consumed as user input on bouncer; `false` otherwise. + */ + fun onKeyEvent(keyEvent: KeyEvent): Boolean { + return (authMethodViewModel.value as? PinBouncerViewModel)?.onKeyEvent( + keyEvent.type, + keyEvent.nativeKeyEvent.keyCode + ) + ?: false + } + data class DialogViewModel( val text: String, diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt index 4c2380c5e4db..aa447ffac154 100644 --- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt @@ -19,6 +19,14 @@ package com.android.systemui.bouncer.ui.viewmodel import android.content.Context +import android.view.KeyEvent.KEYCODE_0 +import android.view.KeyEvent.KEYCODE_9 +import android.view.KeyEvent.KEYCODE_DEL +import android.view.KeyEvent.KEYCODE_NUMPAD_0 +import android.view.KeyEvent.KEYCODE_NUMPAD_9 +import android.view.KeyEvent.isConfirmKey +import androidx.compose.ui.input.key.KeyEvent +import androidx.compose.ui.input.key.KeyEventType import com.android.keyguard.PinShapeAdapter import com.android.systemui.authentication.shared.model.AuthenticationMethodModel import com.android.systemui.bouncer.domain.interactor.BouncerInteractor @@ -196,6 +204,44 @@ class PinBouncerViewModel( else -> ActionButtonAppearance.Shown } } + + /** + * Notifies that a key event has occurred. + * + * @return `true` when the [KeyEvent] was consumed as user input on bouncer; `false` otherwise. + */ + fun onKeyEvent(type: KeyEventType, keyCode: Int): Boolean { + return when (type) { + KeyEventType.KeyUp -> { + if (isConfirmKey(keyCode)) { + onAuthenticateButtonClicked() + true + } else { + false + } + } + KeyEventType.KeyDown -> { + when (keyCode) { + KEYCODE_DEL -> { + onBackspaceButtonClicked() + true + } + in KEYCODE_0..KEYCODE_9 -> { + onPinButtonClicked(keyCode - KEYCODE_0) + true + } + in KEYCODE_NUMPAD_0..KEYCODE_NUMPAD_9 -> { + onPinButtonClicked(keyCode - KEYCODE_NUMPAD_0) + true + } + else -> { + false + } + } + } + else -> false + } + } } /** Appearance of pin-pad action buttons. */ diff --git a/packages/SystemUI/src/com/android/systemui/complication/DreamHomeControlsComplication.java b/packages/SystemUI/src/com/android/systemui/complication/DreamHomeControlsComplication.java index afa23755d937..e284bc7752cf 100644 --- a/packages/SystemUI/src/com/android/systemui/complication/DreamHomeControlsComplication.java +++ b/packages/SystemUI/src/com/android/systemui/complication/DreamHomeControlsComplication.java @@ -18,6 +18,7 @@ package com.android.systemui.complication; import static com.android.systemui.complication.dagger.DreamHomeControlsComplicationComponent.DreamHomeControlsModule.DREAM_HOME_CONTROLS_CHIP_VIEW; import static com.android.systemui.complication.dagger.RegisteredComplicationsModule.DREAM_HOME_CONTROLS_CHIP_LAYOUT_PARAMS; +import static com.android.systemui.complication.dagger.RegisteredComplicationsModule.OPEN_HUB_CHIP_REPLACE_HOME_CONTROLS; import static com.android.systemui.controls.dagger.ControlsComponent.Visibility.AVAILABLE; import static com.android.systemui.controls.dagger.ControlsComponent.Visibility.AVAILABLE_AFTER_UNLOCK; import static com.android.systemui.controls.dagger.ControlsComponent.Visibility.UNAVAILABLE; @@ -35,6 +36,7 @@ import androidx.annotation.Nullable; import com.android.internal.logging.UiEventLogger; import com.android.settingslib.Utils; import com.android.systemui.CoreStartable; +import com.android.systemui.Flags; import com.android.systemui.animation.ActivityTransitionAnimator; import com.android.systemui.complication.dagger.DreamHomeControlsComplicationComponent; import com.android.systemui.controls.ControlsServiceInfo; @@ -89,6 +91,7 @@ public class DreamHomeControlsComplication implements Complication { private final DreamHomeControlsComplication mComplication; private final DreamOverlayStateController mDreamOverlayStateController; private final ControlsComponent mControlsComponent; + private final boolean mReplacedByOpenHub; private boolean mOverlayActive = false; @@ -116,11 +119,13 @@ public class DreamHomeControlsComplication implements Complication { public Registrant(DreamHomeControlsComplication complication, DreamOverlayStateController dreamOverlayStateController, ControlsComponent controlsComponent, - @SystemUser Monitor monitor) { + @SystemUser Monitor monitor, + @Named(OPEN_HUB_CHIP_REPLACE_HOME_CONTROLS) boolean replacedByOpenHub) { super(monitor); mComplication = complication; mControlsComponent = controlsComponent; mDreamOverlayStateController = dreamOverlayStateController; + mReplacedByOpenHub = replacedByOpenHub; } @Override @@ -132,7 +137,9 @@ public class DreamHomeControlsComplication implements Complication { private void updateHomeControlsComplication() { mControlsComponent.getControlsListingController().ifPresent(c -> { - if (isHomeControlsAvailable(c.getCurrentServices())) { + final boolean replacedWithOpenHub = + Flags.glanceableHubShortcutButton() && mReplacedByOpenHub; + if (isHomeControlsAvailable(c.getCurrentServices()) && !replacedWithOpenHub) { mDreamOverlayStateController.addComplication(mComplication); } else { mDreamOverlayStateController.removeComplication(mComplication); diff --git a/packages/SystemUI/src/com/android/systemui/complication/OpenHubComplication.java b/packages/SystemUI/src/com/android/systemui/complication/OpenHubComplication.java new file mode 100644 index 000000000000..3cf22b1b55e4 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/complication/OpenHubComplication.java @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2024 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.complication; + +import static com.android.systemui.complication.dagger.OpenHubComplicationComponent.OpenHubModule.OPEN_HUB_CHIP_VIEW; +import static com.android.systemui.complication.dagger.RegisteredComplicationsModule.OPEN_HUB_CHIP_LAYOUT_PARAMS; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.drawable.Drawable; +import android.util.Log; +import android.view.View; +import android.widget.ImageView; + +import com.android.settingslib.Utils; +import com.android.systemui.CoreStartable; +import com.android.systemui.Flags; +import com.android.systemui.communal.domain.interactor.CommunalInteractor; +import com.android.systemui.communal.shared.model.CommunalScenes; +import com.android.systemui.complication.dagger.OpenHubComplicationComponent; +import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.dagger.qualifiers.SystemUser; +import com.android.systemui.dreams.DreamOverlayStateController; +import com.android.systemui.shared.condition.Monitor; +import com.android.systemui.statusbar.policy.ConfigurationController; +import com.android.systemui.util.ViewController; +import com.android.systemui.util.condition.ConditionalCoreStartable; + +import javax.inject.Inject; +import javax.inject.Named; + +/** + * A dream complication that shows a chip to open the glanceable hub. + */ +// TODO(b/339667383): delete or properly implement this once a product decision is made +public class OpenHubComplication implements Complication { + private final Resources mResources; + private final OpenHubComplicationComponent.Factory mComponentFactory; + + @Inject + public OpenHubComplication( + @Main Resources resources, + OpenHubComplicationComponent.Factory componentFactory) { + mResources = resources; + mComponentFactory = componentFactory; + } + + @Override + public ViewHolder createView(ComplicationViewModel model) { + return mComponentFactory.create(mResources).getViewHolder(); + } + + @Override + public int getRequiredTypeAvailability() { + // TODO(b/339667383): create a new complication type if we decide to productionize this + return COMPLICATION_TYPE_HOME_CONTROLS; + } + + /** + * {@link CoreStartable} for registering the complication with SystemUI on startup. + */ + public static class Registrant extends ConditionalCoreStartable { + private final OpenHubComplication mComplication; + private final DreamOverlayStateController mDreamOverlayStateController; + + private boolean mOverlayActive = false; + + private final DreamOverlayStateController.Callback mOverlayStateCallback = + new DreamOverlayStateController.Callback() { + @Override + public void onStateChanged() { + if (mOverlayActive == mDreamOverlayStateController.isOverlayActive()) { + return; + } + + mOverlayActive = !mOverlayActive; + + if (mOverlayActive) { + updateOpenHubComplication(); + } + } + }; + + @Inject + public Registrant(OpenHubComplication complication, + DreamOverlayStateController dreamOverlayStateController, + @SystemUser Monitor monitor) { + super(monitor); + mComplication = complication; + mDreamOverlayStateController = dreamOverlayStateController; + } + + @Override + public void onStart() { + mDreamOverlayStateController.addCallback(mOverlayStateCallback); + } + + private void updateOpenHubComplication() { + // TODO(b/339667383): don't show the complication if glanceable hub is disabled + if (Flags.glanceableHubShortcutButton()) { + mDreamOverlayStateController.addComplication(mComplication); + } else { + mDreamOverlayStateController.removeComplication(mComplication); + } + } + } + + /** + * Contains values/logic associated with the dream complication view. + */ + public static class OpenHubChipViewHolder implements ViewHolder { + private final ImageView mView; + private final ComplicationLayoutParams mLayoutParams; + private final OpenHubChipViewController mViewController; + + @Inject + OpenHubChipViewHolder( + OpenHubChipViewController dreamOpenHubChipViewController, + @Named(OPEN_HUB_CHIP_VIEW) ImageView view, + @Named(OPEN_HUB_CHIP_LAYOUT_PARAMS) ComplicationLayoutParams layoutParams + ) { + mView = view; + mLayoutParams = layoutParams; + mViewController = dreamOpenHubChipViewController; + mViewController.init(); + } + + @Override + public ImageView getView() { + return mView; + } + + @Override + public ComplicationLayoutParams getLayoutParams() { + return mLayoutParams; + } + } + + /** + * Controls behavior of the dream complication. + */ + static class OpenHubChipViewController extends ViewController<ImageView> { + private static final String TAG = "OpenHubCtrl"; + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + + private final Context mContext; + private final ConfigurationController mConfigurationController; + + private final ConfigurationController.ConfigurationListener mConfigurationListener = + new ConfigurationController.ConfigurationListener() { + @Override + public void onUiModeChanged() { + reloadResources(); + } + }; + private final CommunalInteractor mCommunalInteractor; + + @Inject + OpenHubChipViewController( + @Named(OPEN_HUB_CHIP_VIEW) ImageView view, + Context context, + ConfigurationController configurationController, + CommunalInteractor communalInteractor) { + super(view); + + mContext = context; + mConfigurationController = configurationController; + mCommunalInteractor = communalInteractor; + } + + @Override + protected void onViewAttached() { + reloadResources(); + mView.setOnClickListener(this::onClickOpenHub); + mConfigurationController.addCallback(mConfigurationListener); + } + + @Override + protected void onViewDetached() { + mConfigurationController.removeCallback(mConfigurationListener); + } + + private void reloadResources() { + mView.setImageTintList(Utils.getColorAttr(mContext, android.R.attr.textColorPrimary)); + final Drawable background = mView.getBackground(); + if (background != null) { + background.setTintList( + Utils.getColorAttr(mContext, com.android.internal.R.attr.colorSurface)); + } + } + + private void onClickOpenHub(View v) { + if (DEBUG) Log.d(TAG, "open hub complication tapped"); + + mCommunalInteractor.changeScene(CommunalScenes.Communal, null); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/complication/dagger/OpenHubComplicationComponent.java b/packages/SystemUI/src/com/android/systemui/complication/dagger/OpenHubComplicationComponent.java new file mode 100644 index 000000000000..501601ee32ba --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/complication/dagger/OpenHubComplicationComponent.java @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2024 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.complication.dagger; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.drawable.Drawable; +import android.view.LayoutInflater; +import android.widget.ImageView; + +import com.android.systemui.complication.OpenHubComplication; +import com.android.systemui.res.R; +import com.android.systemui.shared.shadow.DoubleShadowIconDrawable; +import com.android.systemui.shared.shadow.DoubleShadowTextHelper; + +import dagger.BindsInstance; +import dagger.Module; +import dagger.Provides; +import dagger.Subcomponent; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; + +import javax.inject.Named; +import javax.inject.Scope; + +/** + * Responsible for generating dependencies for the {@link OpenHubComplication}. + */ +@Subcomponent(modules = OpenHubComplicationComponent.OpenHubModule.class) +@OpenHubComplicationComponent.OpenHubComplicationScope +public interface OpenHubComplicationComponent { + /** + * Creates a view holder for the open hub complication. + */ + OpenHubComplication.OpenHubChipViewHolder getViewHolder(); + + /** + * Scope of the open hub complication. + */ + @Documented + @Retention(RUNTIME) + @Scope + @interface OpenHubComplicationScope { + } + + /** + * Factory that generates a {@link OpenHubComplicationComponent}. + */ + @Subcomponent.Factory + interface Factory { + /** + * Creates an instance of {@link OpenHubComplicationComponent}. + */ + OpenHubComplicationComponent create(@BindsInstance Resources resources); + } + + /** + * Scoped injected values for the {@link OpenHubComplicationComponent}. + */ + @Module + interface OpenHubModule { + String OPEN_HUB_CHIP_VIEW = "open_hub_chip_view"; + String OPEN_HUB_BACKGROUND_DRAWABLE = "open_hub_background_drawable"; + + /** + * Provides the dream open hub chip view. + */ + @Provides + @OpenHubComplicationScope + @Named(OPEN_HUB_CHIP_VIEW) + static ImageView provideOpenHubChipView( + LayoutInflater layoutInflater, + @Named(OPEN_HUB_BACKGROUND_DRAWABLE) Drawable backgroundDrawable) { + final ImageView chip = + (ImageView) layoutInflater.inflate(R.layout.dream_overlay_open_hub_chip, + null, false); + chip.setBackground(backgroundDrawable); + + return chip; + } + + /** + * Provides the background drawable for the open hub chip. + */ + @Provides + @OpenHubComplicationScope + @Named(OPEN_HUB_BACKGROUND_DRAWABLE) + static Drawable providesOpenHubBackground(Context context, Resources resources) { + return new DoubleShadowIconDrawable(createShadowInfo( + resources, + R.dimen.dream_overlay_bottom_affordance_key_text_shadow_radius, + R.dimen.dream_overlay_bottom_affordance_key_text_shadow_dx, + R.dimen.dream_overlay_bottom_affordance_key_text_shadow_dy, + R.dimen.dream_overlay_bottom_affordance_key_shadow_alpha + ), + createShadowInfo( + resources, + R.dimen.dream_overlay_bottom_affordance_ambient_text_shadow_radius, + R.dimen.dream_overlay_bottom_affordance_ambient_text_shadow_dx, + R.dimen.dream_overlay_bottom_affordance_ambient_text_shadow_dy, + R.dimen.dream_overlay_bottom_affordance_ambient_shadow_alpha + ), + resources.getDrawable(R.drawable.dream_overlay_bottom_affordance_bg), + resources.getDimensionPixelOffset( + R.dimen.dream_overlay_bottom_affordance_width), + resources.getDimensionPixelSize(R.dimen.dream_overlay_bottom_affordance_inset) + ); + } + + private static DoubleShadowTextHelper.ShadowInfo createShadowInfo(Resources resources, + int blurId, int offsetXId, int offsetYId, int alphaId) { + + return new DoubleShadowTextHelper.ShadowInfo( + resources.getDimension(blurId), + resources.getDimension(offsetXId), + resources.getDimension(offsetYId), + resources.getFloat(alphaId) + ); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/complication/dagger/RegisteredComplicationsModule.java b/packages/SystemUI/src/com/android/systemui/complication/dagger/RegisteredComplicationsModule.java index 6f1b09829671..edb5ff7799be 100644 --- a/packages/SystemUI/src/com/android/systemui/complication/dagger/RegisteredComplicationsModule.java +++ b/packages/SystemUI/src/com/android/systemui/complication/dagger/RegisteredComplicationsModule.java @@ -25,6 +25,7 @@ import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; import com.android.systemui.res.R; +import com.android.systemui.util.settings.SystemSettings; import dagger.Module; import dagger.Provides; @@ -39,6 +40,7 @@ import javax.inject.Named; subcomponents = { DreamClockTimeComplicationComponent.class, DreamHomeControlsComplicationComponent.class, + OpenHubComplicationComponent.class, DreamMediaEntryComplicationComponent.class }) public interface RegisteredComplicationsModule { @@ -46,6 +48,8 @@ public interface RegisteredComplicationsModule { String DREAM_SMARTSPACE_LAYOUT_PARAMS = "smartspace_layout_params"; String DREAM_HOME_CONTROLS_CHIP_LAYOUT_PARAMS = "home_controls_chip_layout_params"; String DREAM_MEDIA_ENTRY_LAYOUT_PARAMS = "media_entry_layout_params"; + String OPEN_HUB_CHIP_LAYOUT_PARAMS = "open_hub_chip_layout_params"; + String OPEN_HUB_CHIP_REPLACE_HOME_CONTROLS = "open_hub_chip_replace_home_controls"; int DREAM_CLOCK_TIME_COMPLICATION_WEIGHT = 1; int DREAM_CLOCK_TIME_COMPLICATION_WEIGHT_NO_SMARTSPACE = 2; @@ -109,6 +113,26 @@ public interface RegisteredComplicationsModule { } /** + * Provides layout parameters for the open hub complication. + */ + @Provides + @Named(OPEN_HUB_CHIP_LAYOUT_PARAMS) + static ComplicationLayoutParams provideOpenHubLayoutParams( + @Named(OPEN_HUB_CHIP_REPLACE_HOME_CONTROLS) boolean replaceHomeControls) { + int position = ComplicationLayoutParams.POSITION_BOTTOM | (replaceHomeControls + ? ComplicationLayoutParams.POSITION_START + : ComplicationLayoutParams.POSITION_END); + int direction = replaceHomeControls ? ComplicationLayoutParams.DIRECTION_END + : ComplicationLayoutParams.DIRECTION_START; + return new ComplicationLayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT, + position, + direction, + DREAM_HOME_CONTROLS_CHIP_COMPLICATION_WEIGHT); + } + + /** * Provides layout parameters for the smartspace complication. */ @Provides @@ -124,4 +148,14 @@ public interface RegisteredComplicationsModule { res.getDimensionPixelSize(R.dimen.dream_overlay_complication_smartspace_padding), res.getDimensionPixelSize(R.dimen.dream_overlay_complication_smartspace_max_width)); } + + /** + * If true, the home controls chip should not be shown and the open hub chip should be shown in + * its place. + */ + @Provides + @Named(OPEN_HUB_CHIP_REPLACE_HOME_CONTROLS) + static boolean providesOpenHubChipReplaceHomeControls(SystemSettings systemSettings) { + return systemSettings.getBool(OPEN_HUB_CHIP_REPLACE_HOME_CONTROLS, false); + } } diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java index 3e98fc1b4a2a..7aab37e12b8c 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java @@ -32,6 +32,8 @@ import com.android.systemui.dock.DockManager; import com.android.systemui.dock.DockManagerImpl; import com.android.systemui.doze.DozeHost; import com.android.systemui.keyguard.ui.composable.blueprint.DefaultBlueprintModule; +import com.android.systemui.keyguard.ui.view.layout.blueprints.KeyguardBlueprintModule; +import com.android.systemui.keyguard.ui.view.layout.sections.KeyguardSectionsModule; import com.android.systemui.media.dagger.MediaModule; import com.android.systemui.media.muteawait.MediaMuteAwaitConnectionCli; import com.android.systemui.media.nearby.NearbyMediaDevicesManager; @@ -112,6 +114,8 @@ import javax.inject.Named; GestureModule.class, HeadsUpModule.class, KeyboardShortcutsModule.class, + KeyguardBlueprintModule.class, + KeyguardSectionsModule.class, MediaModule.class, MediaMuteAwaitConnectionCli.StartableModule.class, MultiUserUtilsModule.class, diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java index 339e8f06e853..2ebb94f8bcf4 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java @@ -70,8 +70,6 @@ import com.android.systemui.inputmethod.InputMethodModule; import com.android.systemui.keyboard.KeyboardModule; import com.android.systemui.keyevent.data.repository.KeyEventRepositoryModule; import com.android.systemui.keyguard.ui.composable.LockscreenContent; -import com.android.systemui.keyguard.ui.view.layout.blueprints.KeyguardBlueprintModule; -import com.android.systemui.keyguard.ui.view.layout.sections.KeyguardSectionsModule; import com.android.systemui.log.dagger.LogModule; import com.android.systemui.log.dagger.MonitorLog; import com.android.systemui.log.table.TableLogBuffer; @@ -222,8 +220,6 @@ import javax.inject.Named; InputMethodModule.class, KeyEventRepositoryModule.class, KeyboardModule.class, - KeyguardBlueprintModule.class, - KeyguardSectionsModule.class, LetterboxModule.class, LogModule.class, MediaProjectionActivitiesModule.class, diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/CommunalTouchHandler.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/CommunalTouchHandler.java index 1c047ddcd3d8..04fda3313df6 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/touch/CommunalTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/CommunalTouchHandler.java @@ -98,7 +98,7 @@ public class CommunalTouchHandler implements TouchHandler { // Notification shade window has its own logic to be visible if the hub is open, no need to // do anything here other than send touch events over. session.registerInputListener(ev -> { - surfaces.handleDreamTouch((MotionEvent) ev); + surfaces.handleCommunalHubTouch((MotionEvent) ev); if (ev != null && ((MotionEvent) ev).getAction() == MotionEvent.ACTION_UP) { var unused = session.pop(); } diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt index 2e49919d489b..c08434015ab1 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt @@ -42,14 +42,6 @@ object Flags { @JvmField val NULL_FLAG = unreleasedFlag("null_flag") // 100 - notification - // TODO(b/297792660): Tracking Bug - @JvmField val UNCLEARED_TRANSIENT_HUN_FIX = - releasedFlag("uncleared_transient_hun_fix") - - // TODO(b/298308067): Tracking Bug - @JvmField val SWIPE_UNCLEARED_TRANSIENT_VIEW_FIX = - releasedFlag("swipe_uncleared_transient_view_fix") - // TODO(b/254512751): Tracking Bug val NOTIFICATION_PIPELINE_DEVELOPER_LOGGING = unreleasedFlag("notification_pipeline_developer_logging") @@ -170,12 +162,6 @@ object Flags { val WALLPAPER_PICKER_GRID_APPLY_BUTTON = unreleasedFlag("wallpaper_picker_grid_apply_button") - /** Keyguard Migration */ - - // TODO(b/297037052): Tracking bug. - @JvmField - val REMOVE_NPVC_BOTTOM_AREA_USAGE = unreleasedFlag("remove_npvc_bottom_area_usage") - /** Flag meant to guard the talkback fix for the KeyguardIndicationTextView */ // TODO(b/286563884): Tracking bug @JvmField val KEYGUARD_TALKBACK_FIX = unreleasedFlag("keyguard_talkback_fix") diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt index c32c226441fe..a50cc8fbacb3 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt @@ -53,7 +53,6 @@ import com.android.systemui.keyguard.ui.composable.LockscreenContent import com.android.systemui.keyguard.ui.composable.blueprint.ComposableLockscreenSceneBlueprint import com.android.systemui.keyguard.ui.view.KeyguardIndicationArea import com.android.systemui.keyguard.ui.view.KeyguardRootView -import com.android.systemui.keyguard.ui.view.layout.KeyguardBlueprintCommandListener import com.android.systemui.keyguard.ui.viewmodel.KeyguardBlueprintViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardIndicationAreaViewModel @@ -89,7 +88,6 @@ constructor( private val screenOffAnimationController: ScreenOffAnimationController, private val occludingAppDeviceEntryMessageViewModel: OccludingAppDeviceEntryMessageViewModel, private val chipbarCoordinator: ChipbarCoordinator, - private val keyguardBlueprintCommandListener: KeyguardBlueprintCommandListener, private val keyguardBlueprintViewModel: KeyguardBlueprintViewModel, private val keyguardStatusViewComponentFactory: KeyguardStatusViewComponent.Factory, private val configuration: ConfigurationState, @@ -160,7 +158,6 @@ constructor( ) } } - keyguardBlueprintCommandListener.start() } fun bindIndicationArea() { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/BuiltInKeyguardQuickAffordanceKeys.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/BuiltInKeyguardQuickAffordanceKeys.kt index 80675d373b8e..0863cd737529 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/BuiltInKeyguardQuickAffordanceKeys.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/BuiltInKeyguardQuickAffordanceKeys.kt @@ -28,6 +28,8 @@ object BuiltInKeyguardQuickAffordanceKeys { const val CREATE_NOTE = "create_note" const val DO_NOT_DISTURB = "do_not_disturb" const val FLASHLIGHT = "flashlight" + // TODO(b/339667383): delete or properly implement this once a product decision is made + const val GLANCEABLE_HUB = "glanceable_hub" const val HOME_CONTROLS = "home" const val MUTE = "mute" const val QR_CODE_SCANNER = "qr_code_scanner" diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfig.kt new file mode 100644 index 000000000000..d09b9f68ea60 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfig.kt @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2024 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.data.quickaffordance + +import com.android.systemui.Flags +import com.android.systemui.animation.Expandable +import com.android.systemui.common.shared.model.ContentDescription +import com.android.systemui.common.shared.model.Icon +import com.android.systemui.communal.data.repository.CommunalSceneRepository +import com.android.systemui.communal.shared.model.CommunalScenes +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.res.R +import javax.inject.Inject +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOf + +/** Shortcut that opens the glanceable hub. */ +// TODO(b/339667383): delete or properly implement this once a product decision is made +@SysUISingleton +class GlanceableHubQuickAffordanceConfig +@Inject +constructor( + private val communalRepository: CommunalSceneRepository, +) : KeyguardQuickAffordanceConfig { + + override val key: String = BuiltInKeyguardQuickAffordanceKeys.GLANCEABLE_HUB + override fun pickerName(): String = "Glanceable hub" + + override val pickerIconResourceId = R.drawable.ic_widgets + + override val lockScreenState: Flow<KeyguardQuickAffordanceConfig.LockScreenState> by lazy { + if (Flags.glanceableHubShortcutButton()) { + val contentDescription = ContentDescription.Loaded(pickerName()) + val icon = Icon.Resource(pickerIconResourceId, contentDescription) + flowOf(KeyguardQuickAffordanceConfig.LockScreenState.Visible(icon)) + } else { + flowOf(KeyguardQuickAffordanceConfig.LockScreenState.Hidden) + } + } + + override fun onTriggered( + expandable: Expandable? + ): KeyguardQuickAffordanceConfig.OnTriggeredResult { + communalRepository.changeScene(CommunalScenes.Communal, null) + return KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardDataQuickAffordanceModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardDataQuickAffordanceModule.kt index 45561959a7df..93296f0ca24b 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardDataQuickAffordanceModule.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardDataQuickAffordanceModule.kt @@ -36,6 +36,7 @@ interface KeyguardDataQuickAffordanceModule { camera: CameraQuickAffordanceConfig, doNotDisturb: DoNotDisturbQuickAffordanceConfig, flashlight: FlashlightQuickAffordanceConfig, + glanceableHub: GlanceableHubQuickAffordanceConfig, home: HomeControlsKeyguardQuickAffordanceConfig, mute: MuteQuickAffordanceConfig, quickAccessWallet: QuickAccessWalletKeyguardQuickAffordanceConfig, @@ -46,6 +47,7 @@ interface KeyguardDataQuickAffordanceModule { camera, doNotDisturb, flashlight, + glanceableHub, home, mute, quickAccessWallet, diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManager.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManager.kt index deedbdb9e72b..0748979a2465 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManager.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManager.kt @@ -20,15 +20,17 @@ package com.android.systemui.keyguard.data.quickaffordance import android.content.Context import android.content.IntentFilter import android.content.SharedPreferences -import com.android.systemui.res.R +import com.android.systemui.Flags import com.android.systemui.backup.BackupHelper import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.res.R import com.android.systemui.settings.UserFileManager import com.android.systemui.settings.UserTracker +import com.android.systemui.util.settings.SystemSettings import javax.inject.Inject import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.channels.awaitClose @@ -50,6 +52,7 @@ constructor( @Application private val context: Context, private val userFileManager: UserFileManager, private val userTracker: UserTracker, + private val systemSettings: SystemSettings, broadcastDispatcher: BroadcastDispatcher, ) : KeyguardQuickAffordanceSelectionManager { @@ -70,6 +73,22 @@ constructor( } private val defaults: Map<String, List<String>> by lazy { + // Quick hack to allow testing out a lock screen shortcut to open the glanceable hub. This + // flag will not be rolled out and is only used for local testing. + // TODO(b/339667383): delete or properly implement this once a product decision is made + if (Flags.glanceableHubShortcutButton()) { + if (systemSettings.getBool("open_hub_chip_replace_home_controls", false)) { + return@lazy mapOf( + "bottom_start" to listOf("glanceable_hub"), + "bottom_end" to listOf("create_note") + ) + } else { + return@lazy mapOf( + "bottom_start" to listOf("home"), + "bottom_end" to listOf("glanceable_hub") + ) + } + } context.resources .getStringArray(R.array.config_keyguardQuickAffordanceDefaults) .associate { item -> diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepository.kt index c11c49c7a8a0..b826a002b9d9 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepository.kt @@ -91,9 +91,9 @@ constructor( */ fun refreshBlueprint(config: Config = Config.DEFAULT) { fun scheduleCallback() { - // We use a handler here instead of a CoroutineDipsatcher because the one provided by + // We use a handler here instead of a CoroutineDispatcher because the one provided by // @Main CoroutineDispatcher is currently Dispatchers.Main.immediate, which doesn't - // delay the callback, and instead runs it imemdiately. + // delay the callback, and instead runs it immediately. handler.post { assert.isMainThread() targetTransitionConfig?.let { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt index 53a0c3200f3d..76a822369b0c 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt @@ -86,7 +86,7 @@ constructor( return@combine null } - fromBouncerStep.value > 0.5f + fromBouncerStep.value > TO_GONE_SURFACE_BEHIND_VISIBLE_THRESHOLD } .onStart { // Default to null ("don't care, use a reasonable default"). @@ -232,5 +232,6 @@ constructor( val TO_AOD_DURATION = DEFAULT_DURATION val TO_LOCKSCREEN_DURATION = DEFAULT_DURATION val TO_DOZING_DURATION = DEFAULT_DURATION + val TO_GONE_SURFACE_BEHIND_VISIBLE_THRESHOLD = 0.5f } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt index 7cee258dc39f..41c39597dc02 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt @@ -20,6 +20,7 @@ package com.android.systemui.keyguard.domain.interactor import android.content.Context +import com.android.systemui.CoreStartable import com.android.systemui.biometrics.domain.interactor.FingerprintPropertyInteractor import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor import com.android.systemui.dagger.SysUISingleton @@ -31,17 +32,17 @@ import com.android.systemui.keyguard.ui.view.layout.blueprints.DefaultKeyguardBl import com.android.systemui.keyguard.ui.view.layout.blueprints.SplitShadeKeyguardBlueprint import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition.Config import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition.Type +import com.android.systemui.keyguard.ui.view.layout.sections.ClockSection +import com.android.systemui.keyguard.ui.view.layout.sections.SmartspaceSection import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.shade.shared.model.ShadeMode import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.merge import kotlinx.coroutines.launch @SysUISingleton @@ -53,9 +54,11 @@ constructor( private val context: Context, private val shadeInteractor: ShadeInteractor, private val clockInteractor: KeyguardClockInteractor, - configurationInteractor: ConfigurationInteractor, - fingerprintPropertyInteractor: FingerprintPropertyInteractor, -) { + private val configurationInteractor: ConfigurationInteractor, + private val fingerprintPropertyInteractor: FingerprintPropertyInteractor, + private val smartspaceSection: SmartspaceSection, + private val clockSection: ClockSection, +) : CoreStartable { /** The current blueprint for the lockscreen. */ val blueprint: StateFlow<KeyguardBlueprint> = keyguardBlueprintRepository.blueprint @@ -75,15 +78,23 @@ constructor( } } - private val refreshEvents: Flow<Unit> = - merge( - configurationInteractor.onAnyConfigurationChange, - fingerprintPropertyInteractor.propertiesInitialized.filter { it }.map {}, - ) - - init { + override fun start() { applicationScope.launch { blueprintId.collect { transitionToBlueprint(it) } } - applicationScope.launch { refreshEvents.collect { refreshBlueprint() } } + applicationScope.launch { + fingerprintPropertyInteractor.propertiesInitialized + .filter { it } + .collect { refreshBlueprint() } + } + applicationScope.launch { + val refreshConfig = + Config( + Type.NoTransition, + rebuildSections = listOf(smartspaceSection), + ) + configurationInteractor.onAnyConfigurationChange.collect { + refreshBlueprint(refreshConfig) + } + } } /** @@ -120,4 +131,8 @@ constructor( fun getCurrentBlueprint(): KeyguardBlueprint { return keyguardBlueprintRepository.blueprint.value } + + companion object { + private val TAG = "KeyguardBlueprintInteractor" + } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt index fb65a6dacbe3..88e6602e56b7 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt @@ -18,6 +18,7 @@ package com.android.systemui.keyguard.domain.interactor +import com.android.compose.animation.scene.ObservableTransitionState import com.android.systemui.dagger.SysUISingleton import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor import com.android.systemui.keyguard.shared.model.BiometricUnlockMode @@ -29,6 +30,7 @@ import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.statusbar.notification.domain.interactor.NotificationLaunchAnimationInteractor import com.android.systemui.util.kotlin.sample +import com.android.systemui.utils.coroutines.flow.flatMapLatestConflated import dagger.Lazy import javax.inject.Inject import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -84,25 +86,52 @@ constructor( } .distinctUntilChanged() + private val isDeviceEntered: Flow<Boolean> by lazy { + deviceEntryInteractor.get().isDeviceEntered + } + + private val isDeviceNotEntered: Flow<Boolean> by lazy { isDeviceEntered.map { !it } } + /** - * Surface visibility, which is either determined by the default visibility in the FINISHED - * KeyguardState, or the transition-specific visibility used during certain RUNNING transitions. + * Surface visibility, which is either determined by the default visibility when not + * transitioning between [KeyguardState]s or [Scenes] or the transition-specific visibility used + * during certain ongoing transitions. */ @OptIn(ExperimentalCoroutinesApi::class) val surfaceBehindVisibility: Flow<Boolean> = - transitionInteractor.isInTransitionToAnyState - .flatMapLatest { isInTransition -> - if (!isInTransition) { - defaultSurfaceBehindVisibility - } else { - combine( - transitionSpecificSurfaceBehindVisibility, - defaultSurfaceBehindVisibility, - ) { transitionVisibility, defaultVisibility -> - // Defer to the transition-specific visibility since we're RUNNING a - // transition, but fall back to the default visibility if the current - // transition's interactor did not specify a visibility. - transitionVisibility ?: defaultVisibility + if (SceneContainerFlag.isEnabled) { + sceneInteractor.get().transitionState.flatMapLatestConflated { transitionState -> + when (transitionState) { + is ObservableTransitionState.Transition -> + when { + transitionState.fromScene == Scenes.Lockscreen && + transitionState.toScene == Scenes.Gone -> flowOf(true) + transitionState.fromScene == Scenes.Bouncer && + transitionState.toScene == Scenes.Gone -> + transitionState.progress.map { progress -> + progress > + FromPrimaryBouncerTransitionInteractor + .TO_GONE_SURFACE_BEHIND_VISIBLE_THRESHOLD + } + else -> isDeviceEntered + } + is ObservableTransitionState.Idle -> isDeviceEntered + } + } + } else { + transitionInteractor.isInTransitionToAnyState.flatMapLatest { isInTransition -> + if (!isInTransition) { + defaultSurfaceBehindVisibility + } else { + combine( + transitionSpecificSurfaceBehindVisibility, + defaultSurfaceBehindVisibility, + ) { transitionVisibility, defaultVisibility -> + // Defer to the transition-specific visibility since we're RUNNING a + // transition, but fall back to the default visibility if the current + // transition's interactor did not specify a visibility. + transitionVisibility ?: defaultVisibility + } } } } @@ -162,7 +191,7 @@ constructor( */ val lockscreenVisibility: Flow<Boolean> = if (SceneContainerFlag.isEnabled) { - deviceEntryInteractor.get().isDeviceEntered.map { !it } + isDeviceNotEntered } else { transitionInteractor.currentKeyguardState .sample(transitionInteractor.startedStepWithPrecedingStep, ::Pair) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardBlueprint.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardBlueprint.kt index 7ca2ebaeab20..6d579f3b2513 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardBlueprint.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardBlueprint.kt @@ -37,16 +37,32 @@ interface KeyguardBlueprint { fun replaceViews( constraintLayout: ConstraintLayout, previousBlueprint: KeyguardBlueprint? = null, + rebuildSections: List<KeyguardSection> = listOf(), bindData: Boolean = true ) { - val prevSections = - previousBlueprint?.let { prev -> - prev.sections.subtract(sections).forEach { it.removeViews(constraintLayout) } - prev.sections + val prevSections = previousBlueprint?.sections ?: listOf() + val skipSections = sections.intersect(prevSections).subtract(rebuildSections) + prevSections.subtract(skipSections).forEach { it.removeViews(constraintLayout) } + sections.subtract(skipSections).forEach { + it.addViews(constraintLayout) + if (bindData) { + it.bindData(constraintLayout) } - ?: listOf() + } + } + + /** Rebuilds views for the target sections, or all of them if unspecified. */ + fun rebuildViews( + constraintLayout: ConstraintLayout, + rebuildSections: List<KeyguardSection> = sections, + bindData: Boolean = true + ) { + if (rebuildSections.isEmpty()) { + return + } - sections.subtract(prevSections).forEach { + rebuildSections.forEach { it.removeViews(constraintLayout) } + rebuildSections.forEach { it.addViews(constraintLayout) if (bindData) { it.bindData(constraintLayout) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinder.kt index 52d7519c2e3c..816033561e94 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinder.kt @@ -95,17 +95,8 @@ constructor( null as KeyguardBlueprint?, ) .collect { (prevBlueprint, blueprint) -> - val cs = - ConstraintSet().apply { - clone(constraintLayout) - val emptyLayout = ConstraintSet.Layout() - knownIds.forEach { - getConstraint(it).layout.copyFrom(emptyLayout) - } - blueprint.applyConstraints(this) - } - - var transition = + val config = Config.DEFAULT + val transition = if ( !KeyguardBottomAreaRefactor.isEnabled && prevBlueprint != null && @@ -114,23 +105,37 @@ constructor( BaseBlueprintTransition(clockViewModel) .addTransition( IntraBlueprintTransition( - Config.DEFAULT, + config, clockViewModel, smartspaceViewModel ) ) } else { IntraBlueprintTransition( - Config.DEFAULT, + config, clockViewModel, smartspaceViewModel ) } - runTransition(constraintLayout, transition, Config.DEFAULT) { - // Add and remove views of sections that are not contained by the - // other. - blueprint.replaceViews(constraintLayout, prevBlueprint) + runTransition(constraintLayout, transition, config) { + // Replace sections from the previous blueprint with the new ones + blueprint.replaceViews( + constraintLayout, + prevBlueprint, + config.rebuildSections + ) + + val cs = + ConstraintSet().apply { + clone(constraintLayout) + val emptyLayout = ConstraintSet.Layout() + knownIds.forEach { + getConstraint(it).layout.copyFrom(emptyLayout) + } + blueprint.applyConstraints(this) + } + logAlphaVisibilityOfAppliedConstraintSet(cs, clockViewModel) cs.applyTo(constraintLayout) } @@ -138,22 +143,21 @@ constructor( } launch("$TAG#viewModel.refreshTransition") { - viewModel.refreshTransition.collect { transition -> - val cs = - ConstraintSet().apply { - clone(constraintLayout) - viewModel.blueprint.value.applyConstraints(this) - } + viewModel.refreshTransition.collect { config -> + val blueprint = viewModel.blueprint.value runTransition( constraintLayout, - IntraBlueprintTransition( - transition, - clockViewModel, - smartspaceViewModel - ), - transition, + IntraBlueprintTransition(config, clockViewModel, smartspaceViewModel), + config, ) { + blueprint.rebuildViews(constraintLayout, config.rebuildSections) + + val cs = + ConstraintSet().apply { + clone(constraintLayout) + blueprint.applyConstraints(this) + } logAlphaVisibilityOfAppliedConstraintSet(cs, clockViewModel) cs.applyTo(constraintLayout) } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/KeyguardBlueprintCommandListener.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/KeyguardBlueprintCommandListener.kt index 962cdf10cf86..c0266567a63f 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/KeyguardBlueprintCommandListener.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/KeyguardBlueprintCommandListener.kt @@ -17,6 +17,7 @@ package com.android.systemui.keyguard.ui.view.layout import androidx.core.text.isDigitsOnly +import com.android.systemui.CoreStartable import com.android.systemui.keyguard.data.repository.KeyguardBlueprintRepository import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor import com.android.systemui.statusbar.commandline.Command @@ -31,10 +32,10 @@ constructor( private val commandRegistry: CommandRegistry, private val keyguardBlueprintRepository: KeyguardBlueprintRepository, private val keyguardBlueprintInteractor: KeyguardBlueprintInteractor, -) { +) : CoreStartable { private val layoutCommand = KeyguardLayoutManagerCommand() - fun start() { + override fun start() { commandRegistry.registerCommand(COMMAND) { layoutCommand } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/KeyguardBlueprintModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/KeyguardBlueprintModule.kt index 04ac7bf1178e..2dc930121a71 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/KeyguardBlueprintModule.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/KeyguardBlueprintModule.kt @@ -17,9 +17,14 @@ package com.android.systemui.keyguard.ui.view.layout.blueprints +import com.android.systemui.CoreStartable +import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor import com.android.systemui.keyguard.shared.model.KeyguardBlueprint +import com.android.systemui.keyguard.ui.view.layout.KeyguardBlueprintCommandListener import dagger.Binds import dagger.Module +import dagger.multibindings.ClassKey +import dagger.multibindings.IntoMap import dagger.multibindings.IntoSet @Module @@ -41,4 +46,18 @@ abstract class KeyguardBlueprintModule { abstract fun bindShortcutsBesideUdfpsLockscreenBlueprint( shortcutsBesideUdfpsLockscreenBlueprint: ShortcutsBesideUdfpsKeyguardBlueprint ): KeyguardBlueprint + + @Binds + @IntoMap + @ClassKey(KeyguardBlueprintInteractor::class) + abstract fun bindsKeyguardBlueprintInteractor( + keyguardBlueprintInteractor: KeyguardBlueprintInteractor + ): CoreStartable + + @Binds + @IntoMap + @ClassKey(KeyguardBlueprintCommandListener::class) + abstract fun bindsKeyguardBlueprintCommandListener( + keyguardBlueprintCommandListener: KeyguardBlueprintCommandListener + ): CoreStartable } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/transitions/IntraBlueprintTransition.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/transitions/IntraBlueprintTransition.kt index c69d868866d0..02e9ca5b6821 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/transitions/IntraBlueprintTransition.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/transitions/IntraBlueprintTransition.kt @@ -17,6 +17,7 @@ package com.android.systemui.keyguard.ui.view.layout.blueprints.transitions import android.transition.TransitionSet +import com.android.systemui.keyguard.shared.model.KeyguardSection import com.android.systemui.keyguard.ui.view.layout.sections.transitions.ClockSizeTransition import com.android.systemui.keyguard.ui.view.layout.sections.transitions.DefaultClockSteppingTransition import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel @@ -46,6 +47,7 @@ class IntraBlueprintTransition( val type: Type, val checkPriority: Boolean = true, val terminatePrevious: Boolean = true, + val rebuildSections: List<KeyguardSection> = listOf(), ) { companion object { val DEFAULT = Config(Type.NoTransition) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt index b367715f529e..34a1da54c123 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt @@ -32,6 +32,7 @@ import androidx.constraintlayout.widget.ConstraintSet.TOP import androidx.constraintlayout.widget.ConstraintSet.VISIBLE import androidx.constraintlayout.widget.ConstraintSet.WRAP_CONTENT import com.android.systemui.customization.R as custR +import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.MigrateClocksToBlueprint import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor @@ -57,6 +58,7 @@ internal fun ConstraintSet.setAlpha( alpha: Float, ) = views.forEach { view -> this.setAlpha(view.id, alpha) } +@SysUISingleton class ClockSection @Inject constructor( @@ -72,6 +74,7 @@ constructor( if (!MigrateClocksToBlueprint.isEnabled) { return } + KeyguardClockViewBinder.bind( this, constraintLayout, @@ -86,6 +89,7 @@ constructor( if (!MigrateClocksToBlueprint.isEnabled) { return } + keyguardClockViewModel.currentClock.value?.let { clock -> constraintSet.applyDeltaFrom(buildConstraints(clock, constraintSet)) } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt index 0b8376af811c..c5fab8f57822 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt @@ -219,5 +219,37 @@ constructor( sensorRect.left ) } + + // This is only intended to be here until the KeyguardBottomAreaRefactor flag is enabled + // Without this logic, the lock icon location changes but the KeyguardBottomAreaView is not + // updated and visible ui layout jank occurs. This is due to AmbientIndicationContainer + // being in NPVC and laying out prior to the KeyguardRootView. + // Remove when both DeviceEntryUdfpsRefactor and KeyguardBottomAreaRefactor are enabled. + if (DeviceEntryUdfpsRefactor.isEnabled && !KeyguardBottomAreaRefactor.isEnabled) { + with(notificationPanelView) { + val isUdfpsSupported = deviceEntryIconViewModel.get().isUdfpsSupported.value + val bottomAreaViewRight = findViewById<View>(R.id.keyguard_bottom_area)?.right ?: 0 + findViewById<View>(R.id.ambient_indication_container)?.let { + val (ambientLeft, ambientTop) = it.locationOnScreen + if (isUdfpsSupported) { + // make top of ambient indication view the bottom of the lock icon + it.layout( + ambientLeft, + sensorRect.bottom, + bottomAreaViewRight - ambientLeft, + ambientTop + it.measuredHeight + ) + } else { + // make bottom of ambient indication view the top of the lock icon + it.layout( + ambientLeft, + sensorRect.top - it.measuredHeight, + bottomAreaViewRight - ambientLeft, + sensorRect.top + ) + } + } + } + } } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt index 487c2e918e5f..2d6690fbbc99 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt @@ -22,6 +22,7 @@ import android.view.ViewTreeObserver.OnGlobalLayoutListener import androidx.constraintlayout.widget.Barrier import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintSet +import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.KeyguardUnlockAnimationController import com.android.systemui.keyguard.MigrateClocksToBlueprint import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor @@ -36,6 +37,7 @@ import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController import dagger.Lazy import javax.inject.Inject +@SysUISingleton open class SmartspaceSection @Inject constructor( diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManager.kt index 486d4d46c767..aa93df7f1474 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManager.kt @@ -23,6 +23,7 @@ import android.graphics.drawable.Drawable import android.media.MediaRouter2Manager import android.media.RoutingSessionInfo import android.media.session.MediaController +import android.media.session.MediaController.PlaybackInfo import android.text.TextUtils import android.util.Log import androidx.annotation.AnyThread @@ -74,6 +75,11 @@ constructor( private val listeners: MutableSet<Listener> = mutableSetOf() private val entries: MutableMap<String, Entry> = mutableMapOf() + companion object { + private val EMPTY_AND_DISABLED_MEDIA_DEVICE_DATA = + MediaDeviceData(enabled = false, icon = null, name = null, showBroadcastButton = false) + } + /** Add a listener for changes to the media route (ie. device). */ fun addListener(listener: Listener) = listeners.add(listener) @@ -333,28 +339,32 @@ constructor( @WorkerThread private fun updateCurrent() { if (isLeAudioBroadcastEnabled()) { - if (enableLeAudioSharing()) { - current = - MediaDeviceData( - enabled = false, - icon = - context.getDrawable( - com.android.settingslib.R.drawable.ic_bt_le_audio_sharing - ), - name = context.getString(R.string.audio_sharing_description), - intent = null, - showBroadcastButton = false - ) + current = getLeAudioBroadcastDeviceData() + } else if (Flags.usePlaybackInfoForRoutingControls()) { + val activeDevice: MediaDeviceData? + + // LocalMediaManager provides the connected device based on PlaybackInfo. + // TODO (b/342197065): Simplify nullability once we make currentConnectedDevice + // non-null. + val connectedDevice = localMediaManager.currentConnectedDevice?.toMediaDeviceData() + + if (controller?.playbackInfo?.playbackType == PlaybackInfo.PLAYBACK_TYPE_REMOTE) { + val routingSession = + mr2manager.get().getRoutingSessionForMediaController(controller) + + activeDevice = + routingSession?.let { + // For a remote session, always use the current device from + // LocalMediaManager. Override with routing session name if available to + // show dynamic group name. + connectedDevice?.copy(name = it.name ?: connectedDevice.name) + } } else { - current = - MediaDeviceData( - /* enabled */ true, - /* icon */ context.getDrawable(R.drawable.settings_input_antenna), - /* name */ broadcastDescription, - /* intent */ null, - /* showBroadcastButton */ showBroadcastButton = true - ) + // Prefer SASS if available when playback is local. + activeDevice = getSassDevice() ?: connectedDevice } + + current = activeDevice ?: EMPTY_AND_DISABLED_MEDIA_DEVICE_DATA } else { val aboutToConnect = aboutToConnectDeviceOverride if ( @@ -389,6 +399,43 @@ constructor( } } + private fun getSassDevice(): MediaDeviceData? { + val sassDevice = aboutToConnectDeviceOverride ?: return null + return sassDevice.fullMediaDevice?.toMediaDeviceData() + ?: sassDevice.backupMediaDeviceData + } + + private fun MediaDevice.toMediaDeviceData() = + MediaDeviceData( + enabled = true, + icon = iconWithoutBackground, + name = name, + id = id, + showBroadcastButton = false + ) + + private fun getLeAudioBroadcastDeviceData(): MediaDeviceData { + return if (enableLeAudioSharing()) { + MediaDeviceData( + enabled = false, + icon = + context.getDrawable( + com.android.settingslib.R.drawable.ic_bt_le_audio_sharing + ), + name = context.getString(R.string.audio_sharing_description), + intent = null, + showBroadcastButton = false + ) + } else { + MediaDeviceData( + enabled = true, + icon = context.getDrawable(R.drawable.settings_input_antenna), + name = broadcastDescription, + intent = null, + showBroadcastButton = true + ) + } + } /** Return a display name for the current device / route, or null if not possible */ private fun getDeviceName( device: MediaDevice?, diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/QSPreferencesRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/QSPreferencesRepository.kt new file mode 100644 index 000000000000..f3e5b8f0c214 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/QSPreferencesRepository.kt @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2024 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.qs.panels.data.repository + +import android.content.Context +import android.content.SharedPreferences +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.settings.UserFileManager +import com.android.systemui.user.data.repository.UserRepository +import com.android.systemui.util.kotlin.SharedPreferencesExt.observe +import com.android.systemui.util.kotlin.emitOnStart +import javax.inject.Inject +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.map + +/** Repository for QS user preferences. */ +@OptIn(ExperimentalCoroutinesApi::class) +@SysUISingleton +class QSPreferencesRepository +@Inject +constructor( + private val userFileManager: UserFileManager, + private val userRepository: UserRepository, + @Background private val backgroundDispatcher: CoroutineDispatcher, +) { + /** Whether to show the labels on icon tiles for the current user. */ + val showLabels: Flow<Boolean> = + userRepository.selectedUserInfo + .flatMapLatest { userInfo -> + val prefs = getSharedPrefs(userInfo.id) + prefs.observe().emitOnStart().map { prefs.getBoolean(ICON_LABELS_KEY, false) } + } + .flowOn(backgroundDispatcher) + + /** Sets for the current user whether to show the labels on icon tiles. */ + fun setShowLabels(showLabels: Boolean) { + with(getSharedPrefs(userRepository.getSelectedUserInfo().id)) { + edit().putBoolean(ICON_LABELS_KEY, showLabels).apply() + } + } + + private fun getSharedPrefs(userId: Int): SharedPreferences { + return userFileManager.getSharedPreferences( + FILE_NAME, + Context.MODE_PRIVATE, + userId, + ) + } + + companion object { + private const val ICON_LABELS_KEY = "show_icon_labels" + const val FILE_NAME = "quick_settings_prefs" + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/IconLabelVisibilityInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/IconLabelVisibilityInteractor.kt index a871531f283a..6a899b07b2a0 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/IconLabelVisibilityInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/IconLabelVisibilityInteractor.kt @@ -20,7 +20,6 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.log.LogBuffer import com.android.systemui.log.core.LogLevel -import com.android.systemui.qs.panels.data.repository.IconLabelVisibilityRepository import com.android.systemui.qs.panels.shared.model.IconLabelVisibilityLog import javax.inject.Inject import kotlinx.coroutines.CoroutineScope @@ -33,17 +32,17 @@ import kotlinx.coroutines.flow.stateIn class IconLabelVisibilityInteractor @Inject constructor( - private val repo: IconLabelVisibilityRepository, + private val preferencesInteractor: QSPreferencesInteractor, @IconLabelVisibilityLog private val logBuffer: LogBuffer, @Application scope: CoroutineScope, ) { val showLabels: StateFlow<Boolean> = - repo.showLabels + preferencesInteractor.showLabels .onEach { logChange(it) } - .stateIn(scope, SharingStarted.WhileSubscribed(), repo.showLabels.value) + .stateIn(scope, SharingStarted.WhileSubscribed(), false) fun setShowLabels(showLabels: Boolean) { - repo.setShowLabels(showLabels) + preferencesInteractor.setShowLabels(showLabels) } private fun logChange(showLabels: Boolean) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/IconLabelVisibilityRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/QSPreferencesInteractor.kt index 686e5f49442b..811be80d23fa 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/IconLabelVisibilityRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/QSPreferencesInteractor.kt @@ -14,22 +14,18 @@ * limitations under the License. */ -package com.android.systemui.qs.panels.data.repository +package com.android.systemui.qs.panels.domain.interactor import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.qs.panels.data.repository.QSPreferencesRepository import javax.inject.Inject -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.Flow -/** Repository for whether to show the labels of icon tiles. */ @SysUISingleton -class IconLabelVisibilityRepository @Inject constructor() { - // TODO(b/341735914): Persist and back up showLabels - private val _showLabels = MutableStateFlow(false) - val showLabels: StateFlow<Boolean> = _showLabels.asStateFlow() +class QSPreferencesInteractor @Inject constructor(private val repo: QSPreferencesRepository) { + val showLabels: Flow<Boolean> = repo.showLabels fun setShowLabels(showLabels: Boolean) { - _showLabels.value = showLabels + repo.setShowLabels(showLabels) } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/IconLabelVisibilityViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/IconLabelVisibilityViewModel.kt index 5d4b8f1773f2..12cbde2cbc91 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/IconLabelVisibilityViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/IconLabelVisibilityViewModel.kt @@ -30,7 +30,9 @@ interface IconLabelVisibilityViewModel { @SysUISingleton class IconLabelVisibilityViewModelImpl @Inject -constructor(private val interactor: IconLabelVisibilityInteractor) : IconLabelVisibilityViewModel { +constructor( + private val interactor: IconLabelVisibilityInteractor, +) : IconLabelVisibilityViewModel { override val showLabels: StateFlow<Boolean> = interactor.showLabels override fun setShowLabels(showLabels: Boolean) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/A11yShortcutAutoAddableList.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/A11yShortcutAutoAddableList.kt index 08e39204386e..a0c9737de0ee 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/A11yShortcutAutoAddableList.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/A11yShortcutAutoAddableList.kt @@ -22,6 +22,7 @@ import com.android.systemui.qs.pipeline.domain.model.AutoAddable import com.android.systemui.qs.pipeline.shared.TileSpec import com.android.systemui.qs.tiles.ColorCorrectionTile import com.android.systemui.qs.tiles.ColorInversionTile +import com.android.systemui.qs.tiles.HearingDevicesTile import com.android.systemui.qs.tiles.OneHandedModeTile import com.android.systemui.qs.tiles.ReduceBrightColorsTile @@ -50,6 +51,10 @@ object A11yShortcutAutoAddableList { TileSpec.create(ReduceBrightColorsTile.TILE_SPEC), AccessibilityShortcutController.REDUCE_BRIGHT_COLORS_COMPONENT_NAME ), + factory.create( + TileSpec.create(HearingDevicesTile.TILE_SPEC), + AccessibilityShortcutController.ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME + ) ) } else { emptySet() diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java index 7bc76af68c6b..c091ac3dea50 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java @@ -936,6 +936,10 @@ public class InternetDialogController implements AccessPointController.AccessPoi mHasActiveSubIdOnDds = false; Log.e(TAG, "Can't get DDS subscriptionInfo"); return; + } else if (ddsSubInfo.isOnlyNonTerrestrialNetwork()) { + mHasActiveSubIdOnDds = false; + Log.d(TAG, "This is NTN, so do not show mobile data"); + return; } mHasActiveSubIdOnDds = isEmbeddedSubscriptionVisible(ddsSubInfo); diff --git a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt index 22aa492dbfe8..1d8b7e5b6155 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt @@ -43,6 +43,7 @@ import com.android.systemui.communal.ui.compose.CommunalContainer import com.android.systemui.communal.ui.compose.CommunalContent import com.android.systemui.communal.ui.viewmodel.CommunalViewModel import com.android.systemui.communal.util.CommunalColors +import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.KeyguardState @@ -64,6 +65,7 @@ import kotlinx.coroutines.launch * * This will be used until the glanceable hub is integrated into Flexiglass. */ +@SysUISingleton class GlanceableHubContainerController @Inject constructor( diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java index 0d8030f02948..526800954427 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java @@ -19,9 +19,14 @@ package com.android.systemui.statusbar; import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES; import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG; +import static com.android.systemui.Flags.validateKeyboardShortcutHelperIconUri; + import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.ActivityManager; import android.app.AppGlobals; +import android.app.SynchronousUserSwitchObserver; +import android.app.UserSwitchObserver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -37,6 +42,7 @@ import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; import android.hardware.input.InputManagerGlobal; import android.os.Handler; +import android.os.HandlerThread; import android.os.Looper; import android.os.RemoteException; import android.text.Editable; @@ -136,6 +142,8 @@ public final class KeyboardShortcutListSearch { }; private final Handler mHandler = new Handler(Looper.getMainLooper()); + private final HandlerThread mHandlerThread = new HandlerThread("KeyboardShortcutHelper"); + @VisibleForTesting Handler mBackgroundHandler; @VisibleForTesting public Context mContext; private final IPackageManager mPackageManager; @@ -143,6 +151,13 @@ public final class KeyboardShortcutListSearch { private KeyCharacterMap mKeyCharacterMap; private KeyCharacterMap mBackupKeyCharacterMap; + private final UserSwitchObserver mUserSwitchObserver = new SynchronousUserSwitchObserver() { + @Override + public void onUserSwitching(int newUserId) throws RemoteException { + dismiss(); + } + }; + @VisibleForTesting KeyboardShortcutListSearch(Context context, WindowManager windowManager) { this.mContext = new ContextThemeWrapper( @@ -413,36 +428,75 @@ public final class KeyboardShortcutListSearch { private boolean mAppShortcutsReceived; private boolean mImeShortcutsReceived; - @VisibleForTesting - public void showKeyboardShortcuts(int deviceId) { - retrieveKeyCharacterMap(deviceId); - mAppShortcutsReceived = false; - mImeShortcutsReceived = false; - mWindowManager.requestAppKeyboardShortcuts(result -> { - // Add specific app shortcuts + private void onAppSpecificShortcutsReceived(List<KeyboardShortcutGroup> result) { + // Add specific app shortcuts + if (result != null) { if (result.isEmpty()) { mCurrentAppPackageName = null; mKeySearchResultMap.put(SHORTCUT_SPECIFICAPP_INDEX, false); } else { mCurrentAppPackageName = result.get(0).getPackageName(); - mSpecificAppGroup.addAll(reMapToKeyboardShortcutMultiMappingGroup(result)); + if (validateKeyboardShortcutHelperIconUri()) { + KeyboardShortcuts.sanitiseShortcuts(result); + } + mSpecificAppGroup.addAll( + reMapToKeyboardShortcutMultiMappingGroup(result)); mKeySearchResultMap.put(SHORTCUT_SPECIFICAPP_INDEX, true); } - mAppShortcutsReceived = true; - if (mImeShortcutsReceived) { - mergeAndShowKeyboardShortcutsGroups(); - } - }, deviceId); - mWindowManager.requestImeKeyboardShortcuts(result -> { - // Add specific Ime shortcuts + } + mAppShortcutsReceived = true; + if (mImeShortcutsReceived) { + mergeAndShowKeyboardShortcutsGroups(); + } + } + + private void onImeSpecificShortcutsReceived(List<KeyboardShortcutGroup> result) { + // Add specific Ime shortcuts + if (result != null) { if (!result.isEmpty()) { - mInputGroup.addAll(reMapToKeyboardShortcutMultiMappingGroup(result)); + if (validateKeyboardShortcutHelperIconUri()) { + KeyboardShortcuts.sanitiseShortcuts(result); + } + mInputGroup.addAll( + reMapToKeyboardShortcutMultiMappingGroup(result)); } - mImeShortcutsReceived = true; - if (mAppShortcutsReceived) { - mergeAndShowKeyboardShortcutsGroups(); + } + mImeShortcutsReceived = true; + if (mAppShortcutsReceived) { + mergeAndShowKeyboardShortcutsGroups(); + } + } + + @VisibleForTesting + public void showKeyboardShortcuts(int deviceId) { + if (mBackgroundHandler == null) { + mHandlerThread.start(); + mBackgroundHandler = new Handler(mHandlerThread.getLooper()); + } + + if (validateKeyboardShortcutHelperIconUri()) { + try { + ActivityManager.getService().registerUserSwitchObserver(mUserSwitchObserver, TAG); + } catch (RemoteException e) { + Log.e(TAG, "could not register user switch observer", e); } - }, deviceId); + } + + retrieveKeyCharacterMap(deviceId); + mAppShortcutsReceived = false; + mImeShortcutsReceived = false; + mWindowManager.requestAppKeyboardShortcuts( + result -> { + mBackgroundHandler.post(() -> { + onAppSpecificShortcutsReceived(result); + }); + }, deviceId); + mWindowManager.requestImeKeyboardShortcuts( + result -> { + mBackgroundHandler.post(() -> { + onImeSpecificShortcutsReceived(result); + }); + }, deviceId); } private void mergeAndShowKeyboardShortcutsGroups() { @@ -508,6 +562,14 @@ public final class KeyboardShortcutListSearch { mKeyboardShortcutsBottomSheetDialog.dismiss(); mKeyboardShortcutsBottomSheetDialog = null; } + mHandlerThread.quit(); + if (validateKeyboardShortcutHelperIconUri()) { + try { + ActivityManager.getService().unregisterUserSwitchObserver(mUserSwitchObserver); + } catch (RemoteException e) { + Log.e(TAG, "Could not unregister user switch observer", e); + } + } } private KeyboardShortcutMultiMappingGroup getMultiMappingSystemShortcuts(Context context) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java index 21f608e13f5c..d00916a1c1a8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java @@ -20,11 +20,16 @@ import static android.content.Context.LAYOUT_INFLATER_SERVICE; import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES; import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG; +import static com.android.systemui.Flags.validateKeyboardShortcutHelperIconUri; + import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.ActivityManager; import android.app.AlertDialog; import android.app.AppGlobals; import android.app.Dialog; +import android.app.SynchronousUserSwitchObserver; +import android.app.UserSwitchObserver; import android.content.ComponentName; import android.content.Context; import android.content.DialogInterface; @@ -39,6 +44,7 @@ import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; import android.hardware.input.InputManager; import android.os.Handler; +import android.os.HandlerThread; import android.os.Looper; import android.os.RemoteException; import android.util.Log; @@ -93,6 +99,8 @@ public final class KeyboardShortcuts { }; private final Handler mHandler = new Handler(Looper.getMainLooper()); + private final HandlerThread mHandlerThread = new HandlerThread("KeyboardShortcutHelper"); + @VisibleForTesting Handler mBackgroundHandler; @VisibleForTesting public Context mContext; private final IPackageManager mPackageManager; private final OnClickListener mDialogCloseListener = new DialogInterface.OnClickListener() { @@ -129,6 +137,13 @@ public final class KeyboardShortcuts { @Nullable private List<KeyboardShortcutGroup> mReceivedAppShortcutGroups = null; @Nullable private List<KeyboardShortcutGroup> mReceivedImeShortcutGroups = null; + private final UserSwitchObserver mUserSwitchObserver = new SynchronousUserSwitchObserver() { + @Override + public void onUserSwitching(int newUserId) throws RemoteException { + dismiss(); + } + }; + @VisibleForTesting KeyboardShortcuts(Context context, WindowManager windowManager) { this.mContext = new ContextThemeWrapper( @@ -374,21 +389,68 @@ public final class KeyboardShortcuts { @VisibleForTesting public void showKeyboardShortcuts(int deviceId) { + if (mBackgroundHandler == null) { + mHandlerThread.start(); + mBackgroundHandler = new Handler(mHandlerThread.getLooper()); + } + + if (validateKeyboardShortcutHelperIconUri()) { + try { + ActivityManager.getService().registerUserSwitchObserver(mUserSwitchObserver, TAG); + } catch (RemoteException e) { + Log.e(TAG, "could not register user switch observer", e); + } + } + retrieveKeyCharacterMap(deviceId); + mReceivedAppShortcutGroups = null; mReceivedImeShortcutGroups = null; + mWindowManager.requestAppKeyboardShortcuts( result -> { - mReceivedAppShortcutGroups = result; - maybeMergeAndShowKeyboardShortcuts(); + mBackgroundHandler.post(() -> { + onAppSpecificShortcutsReceived(result); + }); }, deviceId); mWindowManager.requestImeKeyboardShortcuts( result -> { - mReceivedImeShortcutGroups = result; - maybeMergeAndShowKeyboardShortcuts(); + mBackgroundHandler.post(() -> { + onImeSpecificShortcutsReceived(result); + }); }, deviceId); } + private void onAppSpecificShortcutsReceived(List<KeyboardShortcutGroup> result) { + mReceivedAppShortcutGroups = + result == null ? Collections.emptyList() : result; + + if (validateKeyboardShortcutHelperIconUri()) { + sanitiseShortcuts(mReceivedAppShortcutGroups); + } + + maybeMergeAndShowKeyboardShortcuts(); + } + + private void onImeSpecificShortcutsReceived(List<KeyboardShortcutGroup> result) { + mReceivedImeShortcutGroups = + result == null ? Collections.emptyList() : result; + + if (validateKeyboardShortcutHelperIconUri()) { + sanitiseShortcuts(mReceivedImeShortcutGroups); + } + + maybeMergeAndShowKeyboardShortcuts(); + } + + static void sanitiseShortcuts(List<KeyboardShortcutGroup> shortcutGroups) { + for (KeyboardShortcutGroup group : shortcutGroups) { + for (KeyboardShortcutInfo info : group.getItems()) { + info.clearIcon(); + } + } + } + private void maybeMergeAndShowKeyboardShortcuts() { if (mReceivedAppShortcutGroups == null || mReceivedImeShortcutGroups == null) { return; @@ -413,6 +475,14 @@ public final class KeyboardShortcuts { mKeyboardShortcutsDialog.dismiss(); mKeyboardShortcutsDialog = null; } + mHandlerThread.quit(); + if (validateKeyboardShortcutHelperIconUri()) { + try { + ActivityManager.getService().unregisterUserSwitchObserver(mUserSwitchObserver); + } catch (RemoteException e) { + Log.e(TAG, "Could not unregister user switch observer", e); + } + } } private KeyboardShortcutGroup getSystemShortcuts() { 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 edd2961fe119..99ce454126cf 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 @@ -2843,14 +2843,10 @@ public class ExpandableNotificationRow extends ActivatableNotificationView mIsSystemChildExpanded = expanded; } - public void setLayoutListener(LayoutListener listener) { + public void setLayoutListener(@Nullable LayoutListener listener) { mLayoutListener = listener; } - public void removeListener() { - mLayoutListener = null; - } - @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { Trace.beginSection(appendTraceStyleTag("ExpNotRow#onLayout")); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java index c10c09c49c6b..bdfbc4b53943 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java @@ -242,7 +242,7 @@ public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnCl public void onLayout() { mIconsPlaced = false; // Force icons to be re-placed setMenuLocation(); - mParent.removeListener(); + mParent.setLayoutListener(null); } private void createMenuViews(boolean resetState) { 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 a9d7cc003b79..fe22cc628b5f 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 @@ -24,7 +24,6 @@ import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_ import static com.android.internal.jank.InteractionJankMonitor.CUJ_SHADE_CLEAR_ALL; import static com.android.systemui.Flags.newAodTransition; import static com.android.systemui.Flags.notificationOverExpansionClippingFix; -import static com.android.systemui.flags.Flags.UNCLEARED_TRANSIENT_HUN_FIX; import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_SILENT; import static com.android.systemui.statusbar.notification.stack.StackStateAnimator.ANIMATION_DURATION_SWIPE; import static com.android.systemui.util.DumpUtilsKt.println; @@ -255,7 +254,8 @@ public class NotificationStackScrollLayout * The raw amount of the overScroll on the bottom, which is not rubber-banded. */ private float mOverScrolledBottomPixels; - private ListenerSet<Runnable> mStackHeightChangedListeners = new ListenerSet<>(); + private final ListenerSet<Runnable> mStackHeightChangedListeners = new ListenerSet<>(); + private final ListenerSet<Runnable> mHeadsUpHeightChangedListeners = new ListenerSet<>(); private NotificationLogger.OnChildLocationsChangedListener mListener; private OnNotificationLocationsChangedListener mLocationsChangedListener; private OnOverscrollTopChangedListener mOverscrollTopChangedListener; @@ -1114,6 +1114,28 @@ public class NotificationStackScrollLayout mStackHeightChangedListeners.remove(runnable); } + private void notifyHeadsUpHeightChangedForView(View view) { + if (mTopHeadsUpRow == view) { + notifyHeadsUpHeightChangedListeners(); + } + } + + private void notifyHeadsUpHeightChangedListeners() { + for (Runnable listener : mHeadsUpHeightChangedListeners) { + listener.run(); + } + } + + @Override + public void addHeadsUpHeightChangedListener(@NonNull Runnable runnable) { + mHeadsUpHeightChangedListeners.addIfAbsent(runnable); + } + + @Override + public void removeHeadsUpHeightChangedListener(@NonNull Runnable runnable) { + mHeadsUpHeightChangedListeners.remove(runnable); + } + @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { if (!mSuppressChildrenMeasureAndLayout) { @@ -2444,6 +2466,11 @@ public class NotificationStackScrollLayout return mScrollViewFields.getIntrinsicStackHeight(); } + @Override + public int getTopHeadsUpHeight() { + return getTopHeadsUpPinnedHeight(); + } + /** * Calculate the gap height between two different views * @@ -2816,23 +2843,15 @@ public class NotificationStackScrollLayout mAddedHeadsUpChildren.remove(child); return false; } - if (mFeatureFlags.isEnabled(UNCLEARED_TRANSIENT_HUN_FIX)) { - // Skip adding animation for clicked heads up notifications when the - // Shade is closed, because the animation event is generated in - // generateHeadsUpAnimationEvents. Only report that an animation was - // actually generated (thus requesting the transient view be added) - // if a removal animation is in progress. - if (!isExpanded() && isClickedHeadsUp(child)) { - // An animation is already running, add it transiently - mClearTransientViewsWhenFinished.add(child); - return child.inRemovalAnimation(); - } - } else { - if (isClickedHeadsUp(child)) { - // An animation is already running, add it transiently - mClearTransientViewsWhenFinished.add(child); - return true; - } + // Skip adding animation for clicked heads up notifications when the + // Shade is closed, because the animation event is generated in + // generateHeadsUpAnimationEvents. Only report that an animation was + // actually generated (thus requesting the transient view be added) + // if a removal animation is in progress. + if (!isExpanded() && isClickedHeadsUp(child)) { + // An animation is already running, add it transiently + mClearTransientViewsWhenFinished.add(child); + return child.inRemovalAnimation(); } if (mDebugRemoveAnimation) { Log.d(TAG, "generateRemove " + key @@ -4193,12 +4212,14 @@ public class NotificationStackScrollLayout requestAnimationOnViewResize(row); } requestChildrenUpdate(); + notifyHeadsUpHeightChangedForView(view); mAnimateStackYForContentHeightChange = previouslyNeededAnimation; } void onChildHeightReset(ExpandableView view) { updateAnimationState(view); updateChronometerForChild(view); + notifyHeadsUpHeightChangedForView(view); } private void updateScrollPositionOnExpandInBottom(ExpandableView view) { @@ -5573,6 +5594,7 @@ public class NotificationStackScrollLayout */ public void setTopHeadsUpRow(@Nullable ExpandableNotificationRow topHeadsUpRow) { mTopHeadsUpRow = topHeadsUpRow; + notifyHeadsUpHeightChangedListeners(); } public boolean getIsExpanded() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationViewHeightRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationViewHeightRepository.kt index 463c631db32f..f6d9351952f1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationViewHeightRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationViewHeightRepository.kt @@ -27,9 +27,6 @@ import kotlinx.coroutines.flow.MutableStateFlow @SysUISingleton class NotificationViewHeightRepository @Inject constructor() { - /** The height in px of the current heads up notification. */ - val headsUpHeight = MutableStateFlow(0f) - /** * The amount in px that the notification stack should scroll due to internal expansion. This * should only happen when a notification expansion hits the bottom of the screen, so it is diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractor.kt index e7acbe3ab0b0..afcf3ae7d5b2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractor.kt @@ -65,9 +65,6 @@ constructor( } .distinctUntilChanged() - /** The height in px of the contents of the HUN. */ - val headsUpHeight: StateFlow<Float> = viewHeightRepository.headsUpHeight.asStateFlow() - /** The alpha of the Notification Stack for the brightness mirror */ val alphaForBrightnessMirror: StateFlow<Float> = placeholderRepository.alphaForBrightnessMirror.asStateFlow() @@ -110,11 +107,6 @@ constructor( placeholderRepository.shadeScrimBounds.value = bounds } - /** Sets the height of heads up notification. */ - fun setHeadsUpHeight(height: Float) { - viewHeightRepository.headsUpHeight.value = height - } - /** Sets whether the notification stack is scrolled to the top. */ fun setScrolledToTop(scrolledToTop: Boolean) { placeholderRepository.scrolledToTop.value = scrolledToTop diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationScrollView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationScrollView.kt index 14b882f974d2..eaaa9a1523c2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationScrollView.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationScrollView.kt @@ -32,6 +32,9 @@ interface NotificationScrollView { */ val intrinsicStackHeight: Int + /** Height in pixels required to display the top HeadsUp Notification. */ + val topHeadsUpHeight: Int + /** * Since this is an interface rather than a literal View, this provides cast-like access to the * underlying view. @@ -72,9 +75,18 @@ interface NotificationScrollView { /** Sets whether the view is displayed in doze mode. */ fun setDozing(dozing: Boolean) - /** Sets a listener to be notified, when the stack height might have changed. */ + /** Adds a listener to be notified, when the stack height might have changed. */ fun addStackHeightChangedListener(runnable: Runnable) /** @see addStackHeightChangedListener */ fun removeStackHeightChangedListener(runnable: Runnable) + + /** + * Adds a listener to be notified, when the height of the top heads up notification might have + * changed. + */ + fun addHeadsUpHeightChangedListener(runnable: Runnable) + + /** @see addHeadsUpHeightChangedListener */ + fun removeHeadsUpHeightChangedListener(runnable: Runnable) } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt index 622d8e7b2307..fd08e898fce3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt @@ -80,7 +80,6 @@ constructor( launch { viewModel.maxAlpha.collect { view.setMaxAlpha(it) } } launch { viewModel.scrolledToTop.collect { view.setScrolledToTop(it) } } - launch { viewModel.headsUpTop.collect { view.setHeadsUpTop(it) } } launch { viewModel.expandFraction.collect { view.setExpandFraction(it.coerceIn(0f, 1f)) } } launch { viewModel.isScrollable.collect { view.setScrollingEnabled(it) } } launch { viewModel.isDozing.collect { isDozing -> view.setDozing(isDozing) } } @@ -88,11 +87,9 @@ constructor( launchAndDispose { view.setSyntheticScrollConsumer(viewModel.syntheticScrollConsumer) view.setCurrentGestureOverscrollConsumer(viewModel.currentGestureOverscrollConsumer) - view.setHeadsUpHeightConsumer(viewModel.headsUpHeightConsumer) DisposableHandle { view.setSyntheticScrollConsumer(null) view.setCurrentGestureOverscrollConsumer(null) - view.setHeadsUpHeightConsumer(null) } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt index c2ce1144fe1b..a99fbfcc7907 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt @@ -150,8 +150,6 @@ constructor( */ val currentGestureOverscrollConsumer: (Boolean) -> Unit = stackAppearanceInteractor::setCurrentGestureOverscroll - /** Receives the height of the heads up notification. */ - val headsUpHeightConsumer: (Float) -> Unit = stackAppearanceInteractor::setHeadsUpHeight /** Whether the notification stack is scrollable or not. */ val isScrollable: Flow<Boolean> = diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModel.kt index 97b86e3371f5..ea33be0ea4ed 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModel.kt @@ -29,7 +29,6 @@ import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrim import com.android.systemui.util.kotlin.FlowDumperImpl import javax.inject.Inject import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.StateFlow /** * ViewModel used by the Notification placeholders inside the scene container to update the @@ -74,9 +73,6 @@ constructor( val shadeScrimRounding: Flow<ShadeScrimRounding> = interactor.shadeScrimRounding.dumpWhileCollecting("shadeScrimRounding") - /** The height in px of the contents of the HUN. */ - val headsUpHeight: StateFlow<Float> = interactor.headsUpHeight.dumpValue("headsUpHeight") - /** * The amount [0-1] that the shade or quick settings has been opened. At 0, the shade is closed; * at 1, either the shade or quick settings is open. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java index 7b7a35b4928f..05a43917f7e0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java @@ -327,6 +327,11 @@ public interface CentralSurfaces extends Dumpable, LifecycleOwner, CoreStartable @Deprecated float getDisplayDensity(); + /** + * Forwards touch events to communal hub + */ + void handleCommunalHubTouch(MotionEvent event); + public static class KeyboardShortcutsMessage { final int mDeviceId; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesEmptyImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesEmptyImpl.kt index 5ab56ae4be4d..a7b54847cdf9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesEmptyImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesEmptyImpl.kt @@ -81,6 +81,7 @@ abstract class CentralSurfacesEmptyImpl : CentralSurfaces { override fun shouldIgnoreTouch() = false override fun isDeviceInteractive() = false override fun handleDreamTouch(event: MotionEvent?) {} + override fun handleCommunalHubTouch(event: MotionEvent?) {} override fun awakenDreams() {} override fun isBouncerShowing() = false override fun isBouncerShowingScrimmed() = false 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 e0da2fe584b6..78a803618c8b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java @@ -172,6 +172,7 @@ import com.android.systemui.settings.UserTracker; import com.android.systemui.settings.brightness.BrightnessSliderController; import com.android.systemui.settings.brightness.domain.interactor.BrightnessMirrorShowingInteractor; import com.android.systemui.shade.CameraLauncher; +import com.android.systemui.shade.GlanceableHubContainerController; import com.android.systemui.shade.NotificationShadeWindowView; import com.android.systemui.shade.NotificationShadeWindowViewController; import com.android.systemui.shade.QuickSettingsController; @@ -595,6 +596,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { private final ColorExtractor.OnColorsChangedListener mOnColorsChangedListener = (extractor, which) -> updateTheme(); private final BrightnessMirrorShowingInteractor mBrightnessMirrorShowingInteractor; + private final GlanceableHubContainerController mGlanceableHubContainerController; /** * Public constructor for CentralSurfaces. @@ -707,7 +709,8 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { UserTracker userTracker, Provider<FingerprintManager> fingerprintManager, ActivityStarter activityStarter, - BrightnessMirrorShowingInteractor brightnessMirrorShowingInteractor + BrightnessMirrorShowingInteractor brightnessMirrorShowingInteractor, + GlanceableHubContainerController glanceableHubContainerController ) { mContext = context; mNotificationsController = notificationsController; @@ -802,6 +805,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { mFingerprintManager = fingerprintManager; mActivityStarter = activityStarter; mBrightnessMirrorShowingInteractor = brightnessMirrorShowingInteractor; + mGlanceableHubContainerController = glanceableHubContainerController; mLockscreenShadeTransitionController = lockscreenShadeTransitionController; mStartingSurfaceOptional = startingSurfaceOptional; @@ -2951,6 +2955,11 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { } @Override + public void handleCommunalHubTouch(MotionEvent event) { + mGlanceableHubContainerController.onTouchEvent(event); + } + + @Override public void awakenDreams() { mUiBgExecutor.execute(() -> { try { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java index ffc859eb9197..4bf122dd3b6a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java @@ -86,6 +86,8 @@ public class HeadsUpManagerPhone extends BaseHeadsUpManager implements private final List<OnHeadsUpPhoneListenerChange> mHeadsUpPhoneListeners = new ArrayList<>(); private final VisualStabilityProvider mVisualStabilityProvider; + private final AvalancheController mAvalancheController; + // TODO(b/328393698) move the topHeadsUpRow logic to an interactor private final MutableStateFlow<HeadsUpRowRepository> mTopHeadsUpRow = StateFlowKt.MutableStateFlow(null); @@ -155,6 +157,7 @@ public class HeadsUpManagerPhone extends BaseHeadsUpManager implements mBypassController = bypassController; mGroupMembershipManager = groupMembershipManager; mVisualStabilityProvider = visualStabilityProvider; + mAvalancheController = avalancheController; updateResources(); configurationController.addCallback(new ConfigurationController.ConfigurationListener() { @@ -653,9 +656,10 @@ public class HeadsUpManagerPhone extends BaseHeadsUpManager implements boolean wasKeyguard = mStatusBarState == StatusBarState.KEYGUARD; boolean isKeyguard = newState == StatusBarState.KEYGUARD; mStatusBarState = newState; + if (wasKeyguard && !isKeyguard && mBypassController.getBypassEnabled()) { ArrayList<String> keysToRemove = new ArrayList<>(); - for (HeadsUpEntry entry : mHeadsUpEntryMap.values()) { + for (HeadsUpEntry entry : getHeadsUpEntryList()) { if (entry.mEntry != null && entry.mEntry.isBubble() && !entry.isSticky()) { keysToRemove.add(entry.mEntry.getKey()); } @@ -671,7 +675,7 @@ public class HeadsUpManagerPhone extends BaseHeadsUpManager implements if (!isDozing) { // Let's make sure all huns we got while dozing time out within the normal timeout // duration. Otherwise they could get stuck for a very long time - for (HeadsUpEntry entry : mHeadsUpEntryMap.values()) { + for (HeadsUpEntry entry : getHeadsUpEntryList()) { entry.updateEntry(true /* updatePostTime */, "onDozingChanged(false)"); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt index 21691540fc56..eb09e6ef39cb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt @@ -254,6 +254,13 @@ constructor( return null } + fun getWaitingEntryList(): List<HeadsUpEntry> { + if (!NotificationThrottleHun.isEnabled) { + return mutableListOf() + } + return nextMap.keys.toList() + } + private fun isShowing(entry: HeadsUpEntry): Boolean { return headsUpEntryShowing != null && entry.mEntry?.key == headsUpEntryShowing?.mEntry?.key } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java index 2ee98bb61d80..4bd868179faf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java @@ -279,7 +279,6 @@ public abstract class BaseHeadsUpManager implements HeadsUpManager { * Returns the entry if it is managed by this manager. * @param key key of notification * @return the entry - * TODO(b/315362456) See if caller needs to check AvalancheController waiting entries */ @Nullable public NotificationEntry getEntry(@NonNull String key) { @@ -294,8 +293,13 @@ public abstract class BaseHeadsUpManager implements HeadsUpManager { @NonNull @Override public Stream<NotificationEntry> getAllEntries() { - // TODO(b/315362456) See if callers need to check AvalancheController - return mHeadsUpEntryMap.values().stream().map(headsUpEntry -> headsUpEntry.mEntry); + return getHeadsUpEntryList().stream().map(headsUpEntry -> headsUpEntry.mEntry); + } + + public List<HeadsUpEntry> getHeadsUpEntryList() { + List<HeadsUpEntry> entryList = new ArrayList<>(mHeadsUpEntryMap.values()); + entryList.addAll(mAvalancheController.getWaitingEntryList()); + return entryList; } /** @@ -304,7 +308,8 @@ public abstract class BaseHeadsUpManager implements HeadsUpManager { */ @Override public boolean hasNotifications() { - return !mHeadsUpEntryMap.isEmpty(); + return !mHeadsUpEntryMap.isEmpty() + || !mAvalancheController.getWaitingEntryList().isEmpty(); } /** @@ -507,8 +512,10 @@ public abstract class BaseHeadsUpManager implements HeadsUpManager { @Nullable protected HeadsUpEntry getHeadsUpEntry(@NonNull String key) { - // TODO(b/315362456) See if callers need to check AvalancheController - return mHeadsUpEntryMap.get(key); + if (mHeadsUpEntryMap.containsKey(key)) { + return mHeadsUpEntryMap.get(key); + } + return mAvalancheController.getWaitingEntry(key); } /** @@ -688,8 +695,7 @@ public abstract class BaseHeadsUpManager implements HeadsUpManager { */ @Override public boolean isSticky(String key) { - // TODO(b/315362456) See if callers need to check AvalancheController - HeadsUpEntry headsUpEntry = mHeadsUpEntryMap.get(key); + HeadsUpEntry headsUpEntry = getHeadsUpEntry(key); if (headsUpEntry != null) { return headsUpEntry.isSticky(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyControllerImpl.java index 58b82f166623..da928a364984 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyControllerImpl.java @@ -32,6 +32,7 @@ import android.util.SparseBooleanArray; import androidx.annotation.NonNull; import com.android.internal.camera.flags.Flags; +import com.android.systemui.util.ListenerSet; import java.util.Set; @@ -43,7 +44,7 @@ public class IndividualSensorPrivacyControllerImpl implements IndividualSensorPr private final SparseBooleanArray mSoftwareToggleState = new SparseBooleanArray(); private final SparseBooleanArray mHardwareToggleState = new SparseBooleanArray(); private Boolean mRequiresAuthentication; - private final Set<Callback> mCallbacks = new ArraySet<>(); + private final ListenerSet<Callback> mCallbacks = new ListenerSet<>(); public IndividualSensorPrivacyControllerImpl( @NonNull SensorPrivacyManager sensorPrivacyManager) { @@ -115,7 +116,7 @@ public class IndividualSensorPrivacyControllerImpl implements IndividualSensorPr @Override public void addCallback(@NonNull Callback listener) { - mCallbacks.add(listener); + mCallbacks.addIfAbsent(listener); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/volume/ui/navigation/VolumeNavigator.kt b/packages/SystemUI/src/com/android/systemui/volume/ui/navigation/VolumeNavigator.kt index 03c8af9020e1..99f956489bc3 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/ui/navigation/VolumeNavigator.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/ui/navigation/VolumeNavigator.kt @@ -97,7 +97,14 @@ constructor( } private fun showNewVolumePanel() { - volumePanelGlobalStateInteractor.setVisible(true) + activityStarter.dismissKeyguardThenExecute( + { + volumePanelGlobalStateInteractor.setVisible(true) + false + }, + {}, + true + ) } private fun createNewVolumePanelDialog(): Dialog { diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/data/repository/AccessibilityQsShortcutsRepositoryImplForDeviceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/accessibility/data/repository/AccessibilityQsShortcutsRepositoryImplForDeviceTest.kt index bd446b9ed190..1d1329ac550c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/data/repository/AccessibilityQsShortcutsRepositoryImplForDeviceTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/data/repository/AccessibilityQsShortcutsRepositoryImplForDeviceTest.kt @@ -29,6 +29,7 @@ import com.android.systemui.qs.pipeline.shared.TileSpec import com.android.systemui.qs.tiles.ColorCorrectionTile import com.android.systemui.qs.tiles.ColorInversionTile import com.android.systemui.qs.tiles.FontScalingTile +import com.android.systemui.qs.tiles.HearingDevicesTile import com.android.systemui.qs.tiles.OneHandedModeTile import com.android.systemui.qs.tiles.ReduceBrightColorsTile import com.android.systemui.util.mockito.whenever @@ -94,7 +95,7 @@ class AccessibilityQsShortcutsRepositoryImplForDeviceTest : SysuiTestCase() { fun testTileSpecToComponentMappingContent() { val mapping = AccessibilityQsShortcutsRepositoryImpl.TILE_SPEC_TO_COMPONENT_MAPPING - assertThat(mapping.size).isEqualTo(5) + assertThat(mapping.size).isEqualTo(6) assertThat(mapping[ColorCorrectionTile.TILE_SPEC]) .isEqualTo(AccessibilityShortcutController.DALTONIZER_TILE_COMPONENT_NAME) assertThat(mapping[ColorInversionTile.TILE_SPEC]) @@ -107,6 +108,10 @@ class AccessibilityQsShortcutsRepositoryImplForDeviceTest : SysuiTestCase() { ) assertThat(mapping[FontScalingTile.TILE_SPEC]) .isEqualTo(AccessibilityShortcutController.FONT_SIZE_TILE_COMPONENT_NAME) + assertThat(mapping[HearingDevicesTile.TILE_SPEC]) + .isEqualTo( + AccessibilityShortcutController.ACCESSIBILITY_HEARING_AIDS_TILE_COMPONENT_NAME + ) } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java index 8895a5e1a97c..0db0de2bcd7e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java @@ -16,6 +16,7 @@ package com.android.systemui.accessibility.hearingaid; +import static com.android.systemui.accessibility.hearingaid.HearingDevicesDialogDelegate.LIVE_CAPTION_INTENT; import static com.android.systemui.statusbar.phone.SystemUIDialog.DEFAULT_DISMISS_ON_DEVICE_LOCK; import static com.google.common.truth.Truth.assertThat; @@ -24,16 +25,24 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.content.ComponentName; import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.graphics.drawable.Drawable; import android.media.AudioManager; import android.os.Handler; +import android.platform.test.annotations.EnableFlags; import android.provider.Settings; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.view.View; +import android.widget.LinearLayout; import androidx.test.filters.SmallTest; @@ -44,6 +53,7 @@ import com.android.settingslib.bluetooth.HapClientProfile; import com.android.settingslib.bluetooth.LocalBluetoothAdapter; import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.bluetooth.LocalBluetoothProfileManager; +import com.android.systemui.Flags; import com.android.systemui.SysuiTestCase; import com.android.systemui.animation.DialogTransitionAnimator; import com.android.systemui.bluetooth.qsdialog.DeviceItem; @@ -54,6 +64,7 @@ import com.android.systemui.res.R; import com.android.systemui.statusbar.phone.SystemUIDialog; import com.android.systemui.statusbar.phone.SystemUIDialogManager; +import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -75,6 +86,10 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase { public MockitoRule mockito = MockitoJUnit.rule(); private static final String DEVICE_ADDRESS = "AA:BB:CC:DD:EE:FF"; + private static final String TEST_PKG = "pkg"; + private static final String TEST_CLS = "cls"; + private static final ComponentName TEST_COMPONENT = new ComponentName(TEST_PKG, TEST_CLS); + private static final String TEST_LABEL = "label"; @Mock private SystemUIDialog.Factory mSystemUIDialogFactory; @@ -104,6 +119,12 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase { private CachedBluetoothDevice mCachedDevice; @Mock private DeviceItem mHearingDeviceItem; + @Mock + private PackageManager mPackageManager; + @Mock + private ActivityInfo mActivityInfo; + @Mock + private Drawable mDrawable; private SystemUIDialog mDialog; private HearingDevicesDialogDelegate mDialogDelegate; private TestableLooper mTestableLooper; @@ -122,6 +143,7 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase { when(mSysUiState.setFlag(anyLong(), anyBoolean())).thenReturn(mSysUiState); when(mCachedDevice.getAddress()).thenReturn(DEVICE_ADDRESS); when(mHearingDeviceItem.getCachedBluetoothDevice()).thenReturn(mCachedDevice); + mContext.setMockPackageManager(mPackageManager); setUpPairNewDeviceDialog(); @@ -170,6 +192,45 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase { verify(mCachedDevice).disconnect(); } + @Test + @EnableFlags(Flags.FLAG_HEARING_DEVICES_DIALOG_RELATED_TOOLS) + public void showDialog_hasLiveCaption_noRelatedToolsInConfig_showOneRelatedTool() { + when(mPackageManager.queryIntentActivities( + eq(LIVE_CAPTION_INTENT), anyInt())).thenReturn( + List.of(new ResolveInfo())); + mContext.getOrCreateTestableResources().addOverride( + R.array.config_quickSettingsHearingDevicesRelatedToolName, new String[]{}); + + setUpPairNewDeviceDialog(); + mDialog.show(); + + LinearLayout relatedToolsView = (LinearLayout) getRelatedToolsView(mDialog); + assertThat(relatedToolsView.getChildCount()).isEqualTo(1); + } + + @Test + @EnableFlags(Flags.FLAG_HEARING_DEVICES_DIALOG_RELATED_TOOLS) + public void showDialog_hasLiveCaption_oneRelatedToolInConfig_showTwoRelatedTools() + throws PackageManager.NameNotFoundException { + when(mPackageManager.queryIntentActivities( + eq(LIVE_CAPTION_INTENT), anyInt())).thenReturn( + List.of(new ResolveInfo())); + mContext.getOrCreateTestableResources().addOverride( + R.array.config_quickSettingsHearingDevicesRelatedToolName, + new String[]{TEST_PKG + "/" + TEST_CLS}); + when(mPackageManager.getActivityInfo(eq(TEST_COMPONENT), anyInt())).thenReturn( + mActivityInfo); + when(mActivityInfo.loadLabel(mPackageManager)).thenReturn(TEST_LABEL); + when(mActivityInfo.loadIcon(mPackageManager)).thenReturn(mDrawable); + when(mActivityInfo.getComponentName()).thenReturn(TEST_COMPONENT); + + setUpPairNewDeviceDialog(); + mDialog.show(); + + LinearLayout relatedToolsView = (LinearLayout) getRelatedToolsView(mDialog); + assertThat(relatedToolsView.getChildCount()).isEqualTo(2); + } + private void setUpPairNewDeviceDialog() { mDialogDelegate = new HearingDevicesDialogDelegate( mContext, @@ -219,4 +280,18 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase { private View getPairNewDeviceButton(SystemUIDialog dialog) { return dialog.requireViewById(R.id.pair_new_device_button); } + + private View getRelatedToolsView(SystemUIDialog dialog) { + return dialog.requireViewById(R.id.related_tools_container); + } + + @After + public void reset() { + if (mDialogDelegate != null) { + mDialogDelegate = null; + } + if (mDialog != null) { + mDialog.dismiss(); + } + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesToolItemParserTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesToolItemParserTest.java new file mode 100644 index 000000000000..717292378913 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesToolItemParserTest.java @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2024 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.accessibility.hearingaid; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +import static java.util.Collections.emptyList; + +import android.content.ComponentName; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; +import android.graphics.drawable.Drawable; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.SysuiTestCase; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +import java.util.List; + +/** + * Tests for {@link HearingDevicesToolItemParser}. + */ +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper(setAsMainLooper = true) +@SmallTest +public class HearingDevicesToolItemParserTest extends SysuiTestCase { + @Rule + public MockitoRule mockito = MockitoJUnit.rule(); + + @Mock + private PackageManager mPackageManager; + @Mock + private ActivityInfo mActivityInfo; + @Mock + private Drawable mDrawable; + private static final String TEST_PKG = "pkg"; + private static final String TEST_CLS = "cls"; + private static final ComponentName TEST_COMPONENT = new ComponentName(TEST_PKG, TEST_CLS); + private static final String TEST_NO_EXIST_PKG = "NoPkg"; + private static final String TEST_NO_EXIST_CLS = "NoCls"; + private static final ComponentName TEST_NO_EXIST_COMPONENT = new ComponentName( + TEST_NO_EXIST_PKG, TEST_NO_EXIST_CLS); + + private static final String TEST_LABEL = "label"; + + @Before + public void setUp() throws PackageManager.NameNotFoundException { + mContext.setMockPackageManager(mPackageManager); + + when(mPackageManager.getActivityInfo(eq(TEST_COMPONENT), anyInt())).thenReturn( + mActivityInfo); + when(mPackageManager.getActivityInfo(eq(TEST_NO_EXIST_COMPONENT), anyInt())).thenThrow( + new PackageManager.NameNotFoundException()); + when(mActivityInfo.loadLabel(mPackageManager)).thenReturn(TEST_LABEL); + when(mActivityInfo.loadIcon(mPackageManager)).thenReturn(mDrawable); + when(mActivityInfo.getComponentName()).thenReturn(TEST_COMPONENT); + } + + @Test + public void parseStringArray_noString_emptyResult() { + assertThat(HearingDevicesToolItemParser.parseStringArray(mContext, new String[]{}, + new String[]{})).isEqualTo(emptyList()); + } + + @Test + public void parseStringArray_oneToolName_oneExpectedToolItem() { + String[] toolName = new String[]{TEST_PKG + "/" + TEST_CLS}; + + List<ToolItem> toolItemList = HearingDevicesToolItemParser.parseStringArray(mContext, + toolName, new String[]{}); + + assertThat(toolItemList.size()).isEqualTo(1); + assertThat(toolItemList.get(0).getToolName()).isEqualTo(TEST_LABEL); + assertThat(toolItemList.get(0).getToolIntent().getComponent()).isEqualTo(TEST_COMPONENT); + } + + @Test + public void parseStringArray_fourToolName_maxThreeToolItem() { + String componentNameString = TEST_PKG + "/" + TEST_CLS; + String[] fourToolName = + new String[]{componentNameString, componentNameString, componentNameString, + componentNameString}; + + List<ToolItem> toolItemList = HearingDevicesToolItemParser.parseStringArray(mContext, + fourToolName, new String[]{}); + assertThat(toolItemList.size()).isEqualTo(HearingDevicesToolItemParser.MAX_NUM); + } + + @Test + public void parseStringArray_oneWrongFormatToolName_noToolItem() { + String[] wrongFormatToolName = new String[]{TEST_PKG}; + + List<ToolItem> toolItemList = HearingDevicesToolItemParser.parseStringArray(mContext, + wrongFormatToolName, new String[]{}); + assertThat(toolItemList.size()).isEqualTo(0); + } + + @Test + public void parseStringArray_oneNotExistToolName_noToolItem() { + String[] notExistToolName = new String[]{TEST_NO_EXIST_PKG + "/" + TEST_NO_EXIST_CLS}; + + List<ToolItem> toolItemList = HearingDevicesToolItemParser.parseStringArray(mContext, + notExistToolName, new String[]{}); + assertThat(toolItemList.size()).isEqualTo(0); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/complication/DreamHomeControlsComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/complication/DreamHomeControlsComplicationTest.java index 07c980bb6656..18bd960b30a5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/complication/DreamHomeControlsComplicationTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/complication/DreamHomeControlsComplicationTest.java @@ -132,7 +132,7 @@ public class DreamHomeControlsComplicationTest extends SysuiTestCase { public void complicationAvailability_serviceNotAvailable_noFavorites_doNotAddComplication() { final DreamHomeControlsComplication.Registrant registrant = new DreamHomeControlsComplication.Registrant(mComplication, - mDreamOverlayStateController, mControlsComponent, mMonitor); + mDreamOverlayStateController, mControlsComponent, mMonitor, false); registrant.start(); setHaveFavorites(false); @@ -145,7 +145,7 @@ public class DreamHomeControlsComplicationTest extends SysuiTestCase { public void complicationAvailability_serviceAvailable_noFavorites_doNotAddComplication() { final DreamHomeControlsComplication.Registrant registrant = new DreamHomeControlsComplication.Registrant(mComplication, - mDreamOverlayStateController, mControlsComponent, mMonitor); + mDreamOverlayStateController, mControlsComponent, mMonitor, false); registrant.start(); setHaveFavorites(false); @@ -158,7 +158,7 @@ public class DreamHomeControlsComplicationTest extends SysuiTestCase { public void complicationAvailability_serviceAvailable_noFavorites_panel_addComplication() { final DreamHomeControlsComplication.Registrant registrant = new DreamHomeControlsComplication.Registrant(mComplication, - mDreamOverlayStateController, mControlsComponent, mMonitor); + mDreamOverlayStateController, mControlsComponent, mMonitor, false); registrant.start(); setHaveFavorites(false); @@ -171,7 +171,7 @@ public class DreamHomeControlsComplicationTest extends SysuiTestCase { public void complicationAvailability_serviceNotAvailable_haveFavorites_doNotAddComplication() { final DreamHomeControlsComplication.Registrant registrant = new DreamHomeControlsComplication.Registrant(mComplication, - mDreamOverlayStateController, mControlsComponent, mMonitor); + mDreamOverlayStateController, mControlsComponent, mMonitor, false); registrant.start(); setHaveFavorites(true); @@ -184,7 +184,7 @@ public class DreamHomeControlsComplicationTest extends SysuiTestCase { public void complicationAvailability_serviceAvailable_haveFavorites_addComplication() { final DreamHomeControlsComplication.Registrant registrant = new DreamHomeControlsComplication.Registrant(mComplication, - mDreamOverlayStateController, mControlsComponent, mMonitor); + mDreamOverlayStateController, mControlsComponent, mMonitor, false); registrant.start(); setHaveFavorites(true); @@ -197,7 +197,7 @@ public class DreamHomeControlsComplicationTest extends SysuiTestCase { public void complicationAvailability_checkAvailabilityWhenDreamOverlayBecomesActive() { final DreamHomeControlsComplication.Registrant registrant = new DreamHomeControlsComplication.Registrant(mComplication, - mDreamOverlayStateController, mControlsComponent, mMonitor); + mDreamOverlayStateController, mControlsComponent, mMonitor, false); registrant.start(); setServiceAvailable(true); diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt index 36bfa092c042..90ac05fc1b2e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt @@ -135,6 +135,7 @@ class CustomizationProviderTest : SysuiTestCase() { .thenReturn(FakeSharedPreferences()) }, userTracker = userTracker, + systemSettings = FakeSettings(), broadcastDispatcher = fakeBroadcastDispatcher, ) val remoteUserSelectionManager = diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorTest.kt index 0bdf47a51670..f0ad5103e9a6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorTest.kt @@ -38,6 +38,7 @@ import com.android.systemui.plugins.clocks.ClockController import com.android.systemui.shade.data.repository.shadeRepository import com.android.systemui.shade.shared.model.ShadeMode import com.android.systemui.testKosmos +import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -48,6 +49,9 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock +import org.mockito.Mockito.reset +import org.mockito.Mockito.times +import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations @ExperimentalCoroutinesApi @@ -57,6 +61,7 @@ class KeyguardBlueprintInteractorTest : SysuiTestCase() { private val kosmos = testKosmos() private val testScope = kosmos.testScope private val underTest = kosmos.keyguardBlueprintInteractor + private val keyguardBlueprintRepository = kosmos.keyguardBlueprintRepository private val clockRepository by lazy { kosmos.fakeKeyguardClockRepository } private val configurationRepository by lazy { kosmos.fakeConfigurationRepository } private val fingerprintPropertyRepository by lazy { kosmos.fakeFingerprintPropertyRepository } @@ -103,44 +108,46 @@ class KeyguardBlueprintInteractorTest : SysuiTestCase() { } @Test - @DisableFlags(Flags.FLAG_COMPOSE_LOCKSCREEN) - fun fingerprintPropertyInitialized_updatesBlueprint() { + @EnableFlags(Flags.FLAG_COMPOSE_LOCKSCREEN) + fun testDoesNotApplySplitShadeBlueprint() { testScope.runTest { - assertThat(kosmos.keyguardBlueprintRepository.targetTransitionConfig).isNull() - - fingerprintPropertyRepository.supportsUdfps() // initialize properties + val blueprintId by collectLastValue(underTest.blueprintId) + kosmos.shadeRepository.setShadeMode(ShadeMode.Split) + clockRepository.setCurrentClock(clockController) + configurationRepository.onConfigurationChange() runCurrent() advanceUntilIdle() - assertThat(kosmos.keyguardBlueprintRepository.targetTransitionConfig).isNotNull() + assertThat(blueprintId).isEqualTo(DefaultKeyguardBlueprint.DEFAULT) } } @Test - @EnableFlags(Flags.FLAG_COMPOSE_LOCKSCREEN) - fun testDoesNotApplySplitShadeBlueprint() { + @DisableFlags(Flags.FLAG_COMPOSE_LOCKSCREEN) + fun fingerprintPropertyInitialized_updatesBlueprint() { testScope.runTest { - val blueprintId by collectLastValue(underTest.blueprintId) - kosmos.shadeRepository.setShadeMode(ShadeMode.Split) - clockRepository.setCurrentClock(clockController) - configurationRepository.onConfigurationChange() + underTest.start() + reset(keyguardBlueprintRepository) + + fingerprintPropertyRepository.supportsUdfps() // initialize properties runCurrent() advanceUntilIdle() - assertThat(blueprintId).isEqualTo(DefaultKeyguardBlueprint.DEFAULT) + verify(keyguardBlueprintRepository, times(2)).refreshBlueprint(any()) } } @Test fun testRefreshFromConfigChange() { testScope.runTest { - assertThat(kosmos.keyguardBlueprintRepository.targetTransitionConfig).isNull() + underTest.start() + reset(keyguardBlueprintRepository) configurationRepository.onConfigurationChange() runCurrent() advanceUntilIdle() - assertThat(kosmos.keyguardBlueprintRepository.targetTransitionConfig).isNotNull() + verify(keyguardBlueprintRepository, times(2)).refreshBlueprint(any()) } } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt index 35659c12fad5..14d954873f0f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt @@ -281,6 +281,7 @@ class KeyguardQuickAffordanceInteractorParameterizedTest : SysuiTestCase() { .thenReturn(FakeSharedPreferences()) }, userTracker = userTracker, + systemSettings = FakeSettings(), broadcastDispatcher = fakeBroadcastDispatcher, ) val remoteUserSelectionManager = diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorSceneContainerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorSceneContainerTest.kt index ef3183a8891f..ced3526f40be 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorSceneContainerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorSceneContainerTest.kt @@ -281,6 +281,7 @@ class KeyguardQuickAffordanceInteractorSceneContainerTest : SysuiTestCase() { .thenReturn(FakeSharedPreferences()) }, userTracker = userTracker, + systemSettings = FakeSettings(), broadcastDispatcher = fakeBroadcastDispatcher, ) val remoteUserSelectionManager = diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt index 616aac7ce460..344e0fc2bc6a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt @@ -44,6 +44,7 @@ import com.android.systemui.keyguard.ui.view.layout.sections.SmartspaceSection import com.android.systemui.keyguard.ui.view.layout.sections.SplitShadeGuidelines import com.android.systemui.util.mockito.whenever import java.util.Optional +import kotlinx.coroutines.ExperimentalCoroutinesApi import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -55,6 +56,7 @@ import org.mockito.MockitoAnnotations @RunWith(AndroidTestingRunner::class) @RunWithLooper(setAsMainLooper = true) +@ExperimentalCoroutinesApi @SmallTest class DefaultKeyguardBlueprintTest : SysuiTestCase() { private lateinit var underTest: DefaultKeyguardBlueprint @@ -112,17 +114,66 @@ class DefaultKeyguardBlueprintTest : SysuiTestCase() { @Test fun replaceViews_withPrevBlueprint() { val prevBlueprint = mock(KeyguardBlueprint::class.java) - val someSection = mock(KeyguardSection::class.java) - whenever(prevBlueprint.sections) - .thenReturn(underTest.sections.minus(mDefaultDeviceEntrySection).plus(someSection)) + val removedSection = mock(KeyguardSection::class.java) + val addedSection = mDefaultDeviceEntrySection + val rebuildSection = clockSection + val prevSections = underTest.sections.minus(addedSection).plus(removedSection) + val unchangedSections = underTest.sections.subtract(listOf(addedSection, rebuildSection)) + whenever(prevBlueprint.sections).thenReturn(prevSections) + val constraintLayout = ConstraintLayout(context, null) underTest.replaceViews(constraintLayout, prevBlueprint) - underTest.sections.minus(mDefaultDeviceEntrySection).forEach { - verify(it, never())?.addViews(constraintLayout) + + unchangedSections.forEach { + verify(it, never()).addViews(constraintLayout) + verify(it, never()).removeViews(constraintLayout) + } + + verify(addedSection).addViews(constraintLayout) + verify(removedSection).removeViews(constraintLayout) + } + + @Test + fun replaceViews_withPrevBlueprint_withRebuildTargets() { + val prevBlueprint = mock(KeyguardBlueprint::class.java) + val removedSection = mock(KeyguardSection::class.java) + val addedSection = mDefaultDeviceEntrySection + val rebuildSection = clockSection + val prevSections = underTest.sections.minus(addedSection).plus(removedSection) + val unchangedSections = underTest.sections.subtract(listOf(addedSection, rebuildSection)) + whenever(prevBlueprint.sections).thenReturn(prevSections) + + val constraintLayout = ConstraintLayout(context, null) + underTest.replaceViews(constraintLayout, prevBlueprint, listOf(rebuildSection)) + + unchangedSections.forEach { + verify(it, never()).addViews(constraintLayout) + verify(it, never()).removeViews(constraintLayout) + } + + verify(addedSection).addViews(constraintLayout) + verify(rebuildSection).addViews(constraintLayout) + verify(rebuildSection).removeViews(constraintLayout) + verify(removedSection).removeViews(constraintLayout) + } + + @Test + fun rebuildViews() { + val rebuildSections = listOf(mDefaultDeviceEntrySection, clockSection) + val unchangedSections = underTest.sections.subtract(rebuildSections) + + val constraintLayout = ConstraintLayout(context, null) + underTest.rebuildViews(constraintLayout, rebuildSections) + + unchangedSections.forEach { + verify(it, never()).addViews(constraintLayout) + verify(it, never()).removeViews(constraintLayout) } - verify(mDefaultDeviceEntrySection).addViews(constraintLayout) - verify(someSection).removeViews(constraintLayout) + rebuildSections.forEach { + verify(it).addViews(constraintLayout) + verify(it).removeViews(constraintLayout) + } } @Test 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 16421a0f83b4..bdc5fc34158f 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 @@ -178,6 +178,7 @@ class KeyguardBottomAreaViewModelTest(flags: FlagsParameterization) : SysuiTestC .thenReturn(FakeSharedPreferences()) }, userTracker = userTracker, + systemSettings = FakeSettings(), broadcastDispatcher = fakeBroadcastDispatcher, ) val remoteUserSelectionManager = diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModelTest.kt index 833822076620..8a12a90efc4c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModelTest.kt @@ -221,6 +221,7 @@ class KeyguardQuickAffordancesCombinedViewModelTest : SysuiTestCase() { .thenReturn(FakeSharedPreferences()) }, userTracker = userTracker, + systemSettings = FakeSettings(), broadcastDispatcher = fakeBroadcastDispatcher, ) val remoteUserSelectionManager = diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManagerTest.kt index d2701dd0d3a3..16d8819f13fb 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManagerTest.kt @@ -29,6 +29,7 @@ import android.media.session.MediaController.PlaybackInfo import android.media.session.MediaSession import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags +import android.platform.test.annotations.RequiresFlagsDisabled import android.platform.test.flag.junit.DeviceFlagsValueProvider import android.testing.AndroidTestingRunner import android.testing.TestableLooper @@ -40,6 +41,7 @@ import com.android.settingslib.flags.Flags import com.android.settingslib.media.LocalMediaManager import com.android.settingslib.media.MediaDevice import com.android.settingslib.media.PhoneMediaDevice +import com.android.settingslib.media.flags.Flags.FLAG_USE_PLAYBACK_INFO_FOR_ROUTING_CONTROLS import com.android.systemui.SysuiTestCase import com.android.systemui.media.controls.MediaTestUtils import com.android.systemui.media.controls.shared.model.MediaData @@ -101,7 +103,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() { @Mock private lateinit var listener: MediaDeviceManager.Listener @Mock private lateinit var device: MediaDevice @Mock private lateinit var icon: Drawable - @Mock private lateinit var route: RoutingSessionInfo + @Mock private lateinit var routingSession: RoutingSessionInfo @Mock private lateinit var selectedRoute: MediaRoute2Info @Mock private lateinit var controller: MediaController @Mock private lateinit var playbackInfo: PlaybackInfo @@ -141,7 +143,10 @@ public class MediaDeviceManagerTest : SysuiTestCase() { whenever(lmmFactory.create(PACKAGE)).thenReturn(lmm) whenever(muteAwaitFactory.create(lmm)).thenReturn(muteAwaitManager) whenever(lmm.getCurrentConnectedDevice()).thenReturn(device) - whenever(mr2.getRoutingSessionForMediaController(any())).thenReturn(route) + whenever(mr2.getRoutingSessionForMediaController(any())).thenReturn(routingSession) + + whenever(playbackInfo.playbackType).thenReturn(PlaybackInfo.PLAYBACK_TYPE_LOCAL) + whenever(controller.playbackInfo).thenReturn(playbackInfo) // Create a media sesssion and notification for testing. session = MediaSession(context, SESSION_KEY) @@ -235,6 +240,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() { reset(listener) // WHEN media data is loaded with a different token // AND that token results in a null route + whenever(playbackInfo.playbackType).thenReturn(PlaybackInfo.PLAYBACK_TYPE_REMOTE) whenever(mr2.getRoutingSessionForMediaController(any())).thenReturn(null) manager.onMediaDataLoaded(KEY, null, mediaData) fakeBgExecutor.runAllReady() @@ -394,9 +400,10 @@ public class MediaDeviceManagerTest : SysuiTestCase() { } @Test - fun deviceNameFromMR2RouteInfo() { + fun onMediaDataLoaded_withRemotePlaybackType_usesNonNullRoutingSessionName() { // GIVEN that MR2Manager returns a valid routing session - whenever(route.name).thenReturn(REMOTE_DEVICE_NAME) + whenever(routingSession.name).thenReturn(REMOTE_DEVICE_NAME) + whenever(playbackInfo.playbackType).thenReturn(PlaybackInfo.PLAYBACK_TYPE_REMOTE) // WHEN a notification is added manager.onMediaDataLoaded(KEY, null, mediaData) fakeBgExecutor.runAllReady() @@ -408,8 +415,9 @@ public class MediaDeviceManagerTest : SysuiTestCase() { } @Test - fun deviceDisabledWhenMR2ReturnsNullRouteInfo() { + fun onMediaDataLoaded_withRemotePlaybackInfo_noMatchingRoutingSession_setsDisabledDevice() { // GIVEN that MR2Manager returns null for routing session + whenever(playbackInfo.playbackType).thenReturn(PlaybackInfo.PLAYBACK_TYPE_REMOTE) whenever(mr2.getRoutingSessionForMediaController(any())).thenReturn(null) // WHEN a notification is added manager.onMediaDataLoaded(KEY, null, mediaData) @@ -422,13 +430,14 @@ public class MediaDeviceManagerTest : SysuiTestCase() { } @Test - fun deviceDisabledWhenMR2ReturnsNullRouteInfoOnDeviceChanged() { + fun onSelectedDeviceStateChanged_withRemotePlaybackInfo_noMatchingRoutingSession_setsDisabledDevice() { // GIVEN a notif is added manager.onMediaDataLoaded(KEY, null, mediaData) fakeBgExecutor.runAllReady() fakeFgExecutor.runAllReady() reset(listener) // AND MR2Manager returns null for routing session + whenever(playbackInfo.playbackType).thenReturn(PlaybackInfo.PLAYBACK_TYPE_REMOTE) whenever(mr2.getRoutingSessionForMediaController(any())).thenReturn(null) // WHEN the selected device changes state val deviceCallback = captureCallback() @@ -442,13 +451,14 @@ public class MediaDeviceManagerTest : SysuiTestCase() { } @Test - fun deviceDisabledWhenMR2ReturnsNullRouteInfoOnDeviceListUpdate() { + fun onDeviceListUpdate_withRemotePlaybackInfo_noMatchingRoutingSession_setsDisabledDevice() { // GIVEN a notif is added manager.onMediaDataLoaded(KEY, null, mediaData) fakeBgExecutor.runAllReady() fakeFgExecutor.runAllReady() reset(listener) // GIVEN that MR2Manager returns null for routing session + whenever(playbackInfo.playbackType).thenReturn(PlaybackInfo.PLAYBACK_TYPE_REMOTE) whenever(mr2.getRoutingSessionForMediaController(any())).thenReturn(null) // WHEN the selected device changes state val deviceCallback = captureCallback() @@ -461,15 +471,17 @@ public class MediaDeviceManagerTest : SysuiTestCase() { assertThat(data.name).isNull() } + // With the flag enabled, MediaDeviceManager no longer gathers device name information directly. + @RequiresFlagsDisabled(FLAG_USE_PLAYBACK_INFO_FOR_ROUTING_CONTROLS) @Test fun mr2ReturnsSystemRouteWithNullName_isPhone_usePhoneName() { // When the routing session name is null, and is a system session for a PhoneMediaDevice val phoneDevice = mock(PhoneMediaDevice::class.java) whenever(phoneDevice.iconWithoutBackground).thenReturn(icon) whenever(lmm.currentConnectedDevice).thenReturn(phoneDevice) - whenever(route.isSystemSession).thenReturn(true) + whenever(routingSession.isSystemSession).thenReturn(true) - whenever(route.name).thenReturn(null) + whenever(routingSession.name).thenReturn(null) whenever(mr2.getSelectedRoutes(any())).thenReturn(listOf(selectedRoute)) whenever(selectedRoute.name).thenReturn(REMOTE_DEVICE_NAME) whenever(selectedRoute.type).thenReturn(MediaRoute2Info.TYPE_BUILTIN_SPEAKER) @@ -483,13 +495,15 @@ public class MediaDeviceManagerTest : SysuiTestCase() { assertThat(data.name).isEqualTo(PhoneMediaDevice.getMediaTransferThisDeviceName(context)) } + // With the flag enabled, MediaDeviceManager no longer gathers device name information directly. + @RequiresFlagsDisabled(FLAG_USE_PLAYBACK_INFO_FOR_ROUTING_CONTROLS) @Test fun mr2ReturnsSystemRouteWithNullName_useSelectedRouteName() { // When the routing session does not have a name, and is a system session - whenever(route.name).thenReturn(null) + whenever(routingSession.name).thenReturn(null) whenever(mr2.getSelectedRoutes(any())).thenReturn(listOf(selectedRoute)) whenever(selectedRoute.name).thenReturn(REMOTE_DEVICE_NAME) - whenever(route.isSystemSession).thenReturn(true) + whenever(routingSession.isSystemSession).thenReturn(true) manager.onMediaDataLoaded(KEY, null, mediaData) fakeBgExecutor.runAllReady() @@ -503,8 +517,8 @@ public class MediaDeviceManagerTest : SysuiTestCase() { @Test fun mr2ReturnsNonSystemRouteWithNullName_useLocalDeviceName() { // GIVEN that MR2Manager returns a routing session that does not have a name - whenever(route.name).thenReturn(null) - whenever(route.isSystemSession).thenReturn(false) + whenever(routingSession.name).thenReturn(null) + whenever(routingSession.isSystemSession).thenReturn(false) // WHEN a notification is added manager.onMediaDataLoaded(KEY, null, mediaData) fakeBgExecutor.runAllReady() @@ -534,7 +548,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() { } @Test - fun audioInfoVolumeControlIdChanged() { + fun onAudioInfoChanged_withRemotePlaybackInfo_queriesRoutingSession() { whenever(playbackInfo.getPlaybackType()).thenReturn(PlaybackInfo.PLAYBACK_TYPE_LOCAL) whenever(playbackInfo.getVolumeControlId()).thenReturn(null) whenever(controller.getPlaybackInfo()).thenReturn(playbackInfo) @@ -545,10 +559,11 @@ public class MediaDeviceManagerTest : SysuiTestCase() { reset(mr2) // WHEN onAudioInfoChanged fires with a volume control id change whenever(playbackInfo.getVolumeControlId()).thenReturn("placeholder id") + whenever(playbackInfo.playbackType).thenReturn(PlaybackInfo.PLAYBACK_TYPE_REMOTE) val captor = ArgumentCaptor.forClass(MediaController.Callback::class.java) verify(controller).registerCallback(captor.capture()) captor.value.onAudioInfoChanged(playbackInfo) - // THEN the route is checked + // THEN the routing session is checked verify(mr2).getRoutingSessionForMediaController(eq(controller)) } @@ -654,7 +669,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() { @Test fun testRemotePlaybackDeviceOverride() { - whenever(route.name).thenReturn(DEVICE_NAME) + whenever(routingSession.name).thenReturn(DEVICE_NAME) val deviceData = MediaDeviceData(false, null, REMOTE_DEVICE_NAME, null, showBroadcastButton = false) val mediaDataWithDevice = mediaData.copy(device = deviceData) diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/panels/data/QSPreferencesRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/data/QSPreferencesRepositoryTest.kt new file mode 100644 index 000000000000..b0aa6ddf44ce --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/data/QSPreferencesRepositoryTest.kt @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2024 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.qs.panels.data + +import android.content.Context +import android.content.SharedPreferences +import android.content.pm.UserInfo +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.kosmos.testScope +import com.android.systemui.qs.panels.data.repository.QSPreferencesRepository +import com.android.systemui.qs.panels.data.repository.qsPreferencesRepository +import com.android.systemui.settings.userFileManager +import com.android.systemui.testKosmos +import com.android.systemui.user.data.repository.fakeUserRepository +import com.android.systemui.user.data.repository.userRepository +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.test.runTest +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidTestingRunner::class) +class QSPreferencesRepositoryTest : SysuiTestCase() { + private val kosmos = testKosmos() + private val underTest = with(kosmos) { qsPreferencesRepository } + + @Test + fun showLabels_updatesFromSharedPreferences() = + with(kosmos) { + testScope.runTest { + val latest by collectLastValue(underTest.showLabels) + assertThat(latest).isFalse() + + setShowLabelsInSharedPreferences(true) + assertThat(latest).isTrue() + + setShowLabelsInSharedPreferences(false) + assertThat(latest).isFalse() + } + } + + @Test + fun showLabels_updatesFromUserChange() = + with(kosmos) { + testScope.runTest { + fakeUserRepository.setUserInfos(USERS) + val latest by collectLastValue(underTest.showLabels) + + fakeUserRepository.setSelectedUserInfo(PRIMARY_USER) + setShowLabelsInSharedPreferences(false) + + fakeUserRepository.setSelectedUserInfo(ANOTHER_USER) + setShowLabelsInSharedPreferences(true) + + fakeUserRepository.setSelectedUserInfo(PRIMARY_USER) + assertThat(latest).isFalse() + } + } + + @Test + fun setShowLabels_inSharedPreferences() { + underTest.setShowLabels(false) + assertThat(getShowLabelsFromSharedPreferences(true)).isFalse() + + underTest.setShowLabels(true) + assertThat(getShowLabelsFromSharedPreferences(false)).isTrue() + } + + @Test + fun setShowLabels_forDifferentUser() = + with(kosmos) { + testScope.runTest { + fakeUserRepository.setUserInfos(USERS) + + fakeUserRepository.setSelectedUserInfo(PRIMARY_USER) + underTest.setShowLabels(false) + assertThat(getShowLabelsFromSharedPreferences(true)).isFalse() + + fakeUserRepository.setSelectedUserInfo(ANOTHER_USER) + underTest.setShowLabels(true) + assertThat(getShowLabelsFromSharedPreferences(false)).isTrue() + + fakeUserRepository.setSelectedUserInfo(PRIMARY_USER) + assertThat(getShowLabelsFromSharedPreferences(true)).isFalse() + } + } + + private fun getSharedPreferences(): SharedPreferences = + with(kosmos) { + return userFileManager.getSharedPreferences( + QSPreferencesRepository.FILE_NAME, + Context.MODE_PRIVATE, + userRepository.getSelectedUserInfo().id, + ) + } + + private fun setShowLabelsInSharedPreferences(value: Boolean) { + getSharedPreferences().edit().putBoolean(ICON_LABELS_KEY, value).apply() + } + + private fun getShowLabelsFromSharedPreferences(defaultValue: Boolean): Boolean { + return getSharedPreferences().getBoolean(ICON_LABELS_KEY, defaultValue) + } + + companion object { + private const val ICON_LABELS_KEY = "show_icon_labels" + private const val PRIMARY_USER_ID = 0 + private val PRIMARY_USER = UserInfo(PRIMARY_USER_ID, "user 0", UserInfo.FLAG_MAIN) + private const val ANOTHER_USER_ID = 1 + private val ANOTHER_USER = UserInfo(ANOTHER_USER_ID, "user 1", UserInfo.FLAG_FULL) + private val USERS = listOf(PRIMARY_USER, ANOTHER_USER) + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/panels/domain/interactor/IconLabelVisibilityInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/domain/interactor/IconLabelVisibilityInteractorTest.kt new file mode 100644 index 000000000000..9b08432e290f --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/domain/interactor/IconLabelVisibilityInteractorTest.kt @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2024 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.qs.panels.domain.interactor + +import android.content.pm.UserInfo +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.kosmos.testScope +import com.android.systemui.testKosmos +import com.android.systemui.user.data.repository.fakeUserRepository +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +@OptIn(ExperimentalCoroutinesApi::class) +@SmallTest +@RunWith(AndroidTestingRunner::class) +class IconLabelVisibilityInteractorTest : SysuiTestCase() { + private val kosmos = testKosmos() + private val underTest = with(kosmos) { iconLabelVisibilityInteractor } + + @Before + fun setUp() { + with(kosmos) { fakeUserRepository.setUserInfos(USERS) } + } + + @Test + fun changingShowLabels_receivesCorrectShowLabels() = + with(kosmos) { + testScope.runTest { + val showLabels by collectLastValue(underTest.showLabels) + + underTest.setShowLabels(false) + runCurrent() + assertThat(showLabels).isFalse() + + underTest.setShowLabels(true) + runCurrent() + assertThat(showLabels).isTrue() + } + } + + @Test + fun changingUser_receivesCorrectShowLabels() = + with(kosmos) { + testScope.runTest { + val showLabels by collectLastValue(underTest.showLabels) + + fakeUserRepository.setSelectedUserInfo(PRIMARY_USER) + underTest.setShowLabels(false) + runCurrent() + assertThat(showLabels).isFalse() + + fakeUserRepository.setSelectedUserInfo(ANOTHER_USER) + underTest.setShowLabels(true) + runCurrent() + assertThat(showLabels).isTrue() + + fakeUserRepository.setSelectedUserInfo(PRIMARY_USER) + runCurrent() + assertThat(showLabels).isFalse() + } + } + + companion object { + private val PRIMARY_USER = UserInfo(0, "user 0", UserInfo.FLAG_MAIN) + private val ANOTHER_USER = UserInfo(1, "user 1", UserInfo.FLAG_FULL) + private val USERS = listOf(PRIMARY_USER, ANOTHER_USER) + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java index 9798562ab5a8..29487cdace2d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java @@ -1116,6 +1116,34 @@ public class InternetDialogDelegateControllerTest extends SysuiTestCase { assertThat(mInternetDialogController.hasActiveSubIdOnDds()).isFalse(); } + @Test + public void hasActiveSubIdOnDds_activeDdsAndIsOnlyNonTerrestrialNetwork_returnFalse() { + when(SubscriptionManager.getDefaultDataSubscriptionId()) + .thenReturn(SUB_ID); + SubscriptionInfo info = mock(SubscriptionInfo.class); + when(info.isEmbedded()).thenReturn(true); + when(info.isOnlyNonTerrestrialNetwork()).thenReturn(true); + when(mSubscriptionManager.getActiveSubscriptionInfo(SUB_ID)).thenReturn(info); + + mInternetDialogController.mOnSubscriptionsChangedListener.onSubscriptionsChanged(); + + assertFalse(mInternetDialogController.hasActiveSubIdOnDds()); + } + + @Test + public void hasActiveSubIdOnDds_activeDdsAndIsNotOnlyNonTerrestrialNetwork_returnTrue() { + when(SubscriptionManager.getDefaultDataSubscriptionId()) + .thenReturn(SUB_ID); + SubscriptionInfo info = mock(SubscriptionInfo.class); + when(info.isEmbedded()).thenReturn(true); + when(info.isOnlyNonTerrestrialNetwork()).thenReturn(false); + when(mSubscriptionManager.getActiveSubscriptionInfo(SUB_ID)).thenReturn(info); + + mInternetDialogController.mOnSubscriptionsChangedListener.onSubscriptionsChanged(); + + assertTrue(mInternetDialogController.hasActiveSubIdOnDds()); + } + private String getResourcesString(String name) { return mContext.getResources().getString(getResourcesId(name)); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutListSearchTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutListSearchTest.java index 22c9e45d48af..6985a27a59c8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutListSearchTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutListSearchTest.java @@ -20,14 +20,21 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.graphics.drawable.Icon; +import android.os.Handler; +import android.platform.test.annotations.EnableFlags; +import android.view.KeyboardShortcutGroup; +import android.view.KeyboardShortcutInfo; import android.view.WindowManager; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.systemui.Flags; import com.android.systemui.SysuiTestCase; import com.google.android.material.bottomsheet.BottomSheetDialog; @@ -36,10 +43,14 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; +import java.util.Arrays; +import java.util.Collections; + @SmallTest @RunWith(AndroidJUnit4.class) public class KeyboardShortcutListSearchTest extends SysuiTestCase { @@ -51,6 +62,7 @@ public class KeyboardShortcutListSearchTest extends SysuiTestCase { @Mock private BottomSheetDialog mBottomSheetDialog; @Mock WindowManager mWindowManager; + @Mock Handler mHandler; @Before public void setUp() { @@ -58,6 +70,7 @@ public class KeyboardShortcutListSearchTest extends SysuiTestCase { mKeyboardShortcutListSearch.sInstance = mKeyboardShortcutListSearch; mKeyboardShortcutListSearch.mKeyboardShortcutsBottomSheetDialog = mBottomSheetDialog; mKeyboardShortcutListSearch.mContext = mContext; + mKeyboardShortcutListSearch.mBackgroundHandler = mHandler; } @Test @@ -78,4 +91,59 @@ public class KeyboardShortcutListSearchTest extends SysuiTestCase { verify(mWindowManager).requestAppKeyboardShortcuts(any(), anyInt()); verify(mWindowManager).requestImeKeyboardShortcuts(any(), anyInt()); } + + @Test + @EnableFlags(Flags.FLAG_VALIDATE_KEYBOARD_SHORTCUT_HELPER_ICON_URI) + public void requestAppKeyboardShortcuts_callback_sanitisesIcons() { + KeyboardShortcutGroup group = createKeyboardShortcutGroupForIconTests(); + + mKeyboardShortcutListSearch.toggle(mContext, DEVICE_ID); + + ArgumentCaptor<WindowManager.KeyboardShortcutsReceiver> callbackCaptor = + ArgumentCaptor.forClass(WindowManager.KeyboardShortcutsReceiver.class); + ArgumentCaptor<Runnable> handlerRunnableCaptor = ArgumentCaptor.forClass(Runnable.class); + verify(mWindowManager).requestAppKeyboardShortcuts(callbackCaptor.capture(), anyInt()); + callbackCaptor.getValue().onKeyboardShortcutsReceived(Collections.singletonList(group)); + verify(mHandler).post(handlerRunnableCaptor.capture()); + handlerRunnableCaptor.getValue().run(); + + verify(group.getItems().get(0)).clearIcon(); + verify(group.getItems().get(1)).clearIcon(); + } + + @Test + @EnableFlags(Flags.FLAG_VALIDATE_KEYBOARD_SHORTCUT_HELPER_ICON_URI) + public void requestImeKeyboardShortcuts_callback_sanitisesIcons() { + KeyboardShortcutGroup group = createKeyboardShortcutGroupForIconTests(); + + mKeyboardShortcutListSearch.toggle(mContext, DEVICE_ID); + + ArgumentCaptor<WindowManager.KeyboardShortcutsReceiver> callbackCaptor = + ArgumentCaptor.forClass(WindowManager.KeyboardShortcutsReceiver.class); + ArgumentCaptor<Runnable> handlerRunnableCaptor = ArgumentCaptor.forClass(Runnable.class); + verify(mWindowManager).requestImeKeyboardShortcuts(callbackCaptor.capture(), anyInt()); + callbackCaptor.getValue().onKeyboardShortcutsReceived(Collections.singletonList(group)); + verify(mHandler).post(handlerRunnableCaptor.capture()); + handlerRunnableCaptor.getValue().run(); + + verify(group.getItems().get(0)).clearIcon(); + verify(group.getItems().get(1)).clearIcon(); + + } + + private KeyboardShortcutGroup createKeyboardShortcutGroupForIconTests() { + Icon icon = mock(Icon.class); + + KeyboardShortcutInfo info1 = mock(KeyboardShortcutInfo.class); + KeyboardShortcutInfo info2 = mock(KeyboardShortcutInfo.class); + when(info1.getIcon()).thenReturn(icon); + when(info2.getIcon()).thenReturn(icon); + when(info1.getLabel()).thenReturn("label"); + when(info2.getLabel()).thenReturn("label"); + + KeyboardShortcutGroup group = new KeyboardShortcutGroup("label", + Arrays.asList(new KeyboardShortcutInfo[]{ info1, info2})); + group.setPackageName("com.example"); + return group; + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutsTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutsTest.java index a3ecde0fe976..2b3f13986113 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutsTest.java @@ -20,25 +20,36 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.Dialog; +import android.graphics.drawable.Icon; +import android.os.Handler; +import android.platform.test.annotations.EnableFlags; +import android.view.KeyboardShortcutGroup; +import android.view.KeyboardShortcutInfo; import android.view.WindowManager; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.systemui.Flags; import com.android.systemui.SysuiTestCase; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; +import java.util.Arrays; +import java.util.Collections; + @SmallTest @RunWith(AndroidJUnit4.class) public class KeyboardShortcutsTest extends SysuiTestCase { @@ -50,6 +61,7 @@ public class KeyboardShortcutsTest extends SysuiTestCase { @Mock private Dialog mDialog; @Mock WindowManager mWindowManager; + @Mock Handler mHandler; @Before public void setUp() { @@ -57,6 +69,7 @@ public class KeyboardShortcutsTest extends SysuiTestCase { mKeyboardShortcuts.sInstance = mKeyboardShortcuts; mKeyboardShortcuts.mKeyboardShortcutsDialog = mDialog; mKeyboardShortcuts.mContext = mContext; + mKeyboardShortcuts.mBackgroundHandler = mHandler; } @Test @@ -77,4 +90,78 @@ public class KeyboardShortcutsTest extends SysuiTestCase { verify(mWindowManager).requestAppKeyboardShortcuts(any(), anyInt()); verify(mWindowManager).requestImeKeyboardShortcuts(any(), anyInt()); } + + @Test + public void sanitiseShortcuts_clearsIcons() { + KeyboardShortcutGroup group = createKeyboardShortcutGroupForIconTests(); + + KeyboardShortcuts.sanitiseShortcuts(Collections.singletonList(group)); + + verify(group.getItems().get(0)).clearIcon(); + verify(group.getItems().get(1)).clearIcon(); + } + + @Test + public void sanitiseShortcuts_nullPackage_clearsIcons() { + KeyboardShortcutGroup group = createKeyboardShortcutGroupForIconTests(); + group.setPackageName(null); + + KeyboardShortcuts.sanitiseShortcuts(Collections.singletonList(group)); + + verify(group.getItems().get(0)).clearIcon(); + verify(group.getItems().get(1)).clearIcon(); + } + + @Test + @EnableFlags(Flags.FLAG_VALIDATE_KEYBOARD_SHORTCUT_HELPER_ICON_URI) + public void requestAppKeyboardShortcuts_callback_sanitisesIcons() { + KeyboardShortcutGroup group = createKeyboardShortcutGroupForIconTests(); + + mKeyboardShortcuts.toggle(mContext, DEVICE_ID); + + ArgumentCaptor<WindowManager.KeyboardShortcutsReceiver> callbackCaptor = + ArgumentCaptor.forClass(WindowManager.KeyboardShortcutsReceiver.class); + ArgumentCaptor<Runnable> handlerRunnableCaptor = ArgumentCaptor.forClass(Runnable.class); + verify(mWindowManager).requestAppKeyboardShortcuts(callbackCaptor.capture(), anyInt()); + callbackCaptor.getValue().onKeyboardShortcutsReceived(Collections.singletonList(group)); + verify(mHandler).post(handlerRunnableCaptor.capture()); + handlerRunnableCaptor.getValue().run(); + + verify(group.getItems().get(0)).clearIcon(); + verify(group.getItems().get(1)).clearIcon(); + } + + @Test + @EnableFlags(Flags.FLAG_VALIDATE_KEYBOARD_SHORTCUT_HELPER_ICON_URI) + public void requestImeKeyboardShortcuts_callback_sanitisesIcons() { + KeyboardShortcutGroup group = createKeyboardShortcutGroupForIconTests(); + + mKeyboardShortcuts.toggle(mContext, DEVICE_ID); + + ArgumentCaptor<WindowManager.KeyboardShortcutsReceiver> callbackCaptor = + ArgumentCaptor.forClass(WindowManager.KeyboardShortcutsReceiver.class); + ArgumentCaptor<Runnable> handlerRunnableCaptor = ArgumentCaptor.forClass(Runnable.class); + verify(mWindowManager).requestImeKeyboardShortcuts(callbackCaptor.capture(), anyInt()); + callbackCaptor.getValue().onKeyboardShortcutsReceived(Collections.singletonList(group)); + verify(mHandler).post(handlerRunnableCaptor.capture()); + handlerRunnableCaptor.getValue().run(); + + verify(group.getItems().get(0)).clearIcon(); + verify(group.getItems().get(1)).clearIcon(); + + } + + private KeyboardShortcutGroup createKeyboardShortcutGroupForIconTests() { + Icon icon = mock(Icon.class); + + KeyboardShortcutInfo info1 = mock(KeyboardShortcutInfo.class); + KeyboardShortcutInfo info2 = mock(KeyboardShortcutInfo.class); + when(info1.getIcon()).thenReturn(icon); + when(info2.getIcon()).thenReturn(icon); + + KeyboardShortcutGroup group = new KeyboardShortcutGroup("label", + Arrays.asList(new KeyboardShortcutInfo[]{ info1, info2})); + group.setPackageName("com.example"); + return group; + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java index f461e2f67d20..12f3ef3cf553 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java @@ -171,7 +171,6 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { // and then we would test both configurations, but currently they are all read // in the constructor. mSetFlagsRule.enableFlags(FLAG_NEW_AOD_TRANSITION); - mFeatureFlags.setDefault(Flags.UNCLEARED_TRANSIENT_HUN_FIX); // Inject dependencies before initializing the layout mDependency.injectTestDependency(FeatureFlags.class, mFeatureFlags); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java index 62804ed1412e..cb9790b2495a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java @@ -138,6 +138,7 @@ import com.android.systemui.settings.UserTracker; import com.android.systemui.settings.brightness.BrightnessSliderController; import com.android.systemui.settings.brightness.domain.interactor.BrightnessMirrorShowingInteractor; import com.android.systemui.shade.CameraLauncher; +import com.android.systemui.shade.GlanceableHubContainerController; import com.android.systemui.shade.NotificationPanelView; import com.android.systemui.shade.NotificationPanelViewController; import com.android.systemui.shade.NotificationShadeWindowViewController; @@ -337,6 +338,7 @@ public class CentralSurfacesImplTest extends SysuiTestCase { @Mock private KeyboardShortcuts mKeyboardShortcuts; @Mock private KeyboardShortcutListSearch mKeyboardShortcutListSearch; @Mock private PackageManager mPackageManager; + @Mock private GlanceableHubContainerController mGlanceableHubContainerController; private ShadeController mShadeController; private final FakeSystemClock mFakeSystemClock = new FakeSystemClock(); @@ -590,7 +592,8 @@ public class CentralSurfacesImplTest extends SysuiTestCase { mUserTracker, () -> mFingerprintManager, mActivityStarter, - mBrightnessMirrorShowingInteractor + mBrightnessMirrorShowingInteractor, + mGlanceableHubContainerController ); mScreenLifecycle.addObserver(mCentralSurfaces.mScreenObserver); mCentralSurfaces.initShadeVisibilityListener(); diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryKosmos.kt index a6b40df8e81b..fb12897ead19 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryKosmos.kt @@ -23,12 +23,14 @@ import com.android.systemui.keyguard.domain.interactor.keyguardClockInteractor import com.android.systemui.keyguard.ui.view.layout.blueprints.DefaultKeyguardBlueprint import com.android.systemui.keyguard.ui.view.layout.blueprints.SplitShadeKeyguardBlueprint import com.android.systemui.keyguard.ui.view.layout.sections.ClockSection +import com.android.systemui.keyguard.ui.view.layout.sections.SmartspaceSection import com.android.systemui.keyguard.ui.viewmodel.keyguardClockViewModel import com.android.systemui.keyguard.ui.viewmodel.keyguardRootViewModel import com.android.systemui.keyguard.ui.viewmodel.keyguardSmartspaceViewModel import com.android.systemui.kosmos.Kosmos import com.android.systemui.util.mockito.mock import java.util.Optional +import org.mockito.Mockito.spy val Kosmos.keyguardClockSection: ClockSection by Kosmos.Fixture { @@ -42,6 +44,9 @@ val Kosmos.keyguardClockSection: ClockSection by ) } +val Kosmos.keyguardSmartspaceSection: SmartspaceSection by + Kosmos.Fixture { mock<SmartspaceSection>() } + val Kosmos.defaultKeyguardBlueprint by Kosmos.Fixture { DefaultKeyguardBlueprint( @@ -57,7 +62,7 @@ val Kosmos.defaultKeyguardBlueprint by aodBurnInSection = mock(), communalTutorialIndicatorSection = mock(), clockSection = keyguardClockSection, - smartspaceSection = mock(), + smartspaceSection = keyguardSmartspaceSection, keyguardSliceViewSection = mock(), udfpsAccessibilityOverlaySection = mock(), accessibilityActionsSection = mock(), @@ -80,7 +85,7 @@ val Kosmos.splitShadeBlueprint by aodBurnInSection = mock(), communalTutorialIndicatorSection = mock(), clockSection = keyguardClockSection, - smartspaceSection = mock(), + smartspaceSection = keyguardSmartspaceSection, mediaSection = mock(), accessibilityActionsSection = mock(), ) @@ -88,13 +93,15 @@ val Kosmos.splitShadeBlueprint by val Kosmos.keyguardBlueprintRepository by Kosmos.Fixture { - KeyguardBlueprintRepository( - blueprints = - setOf( - defaultKeyguardBlueprint, - splitShadeBlueprint, - ), - handler = fakeExecutorHandler, - assert = mock(), + spy( + KeyguardBlueprintRepository( + blueprints = + setOf( + defaultKeyguardBlueprint, + splitShadeBlueprint, + ), + handler = fakeExecutorHandler, + assert = mock(), + ) ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorKosmos.kt index 5256ce4b9adf..4328ca153374 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorKosmos.kt @@ -20,6 +20,8 @@ import android.content.applicationContext import com.android.systemui.biometrics.domain.interactor.fingerprintPropertyInteractor import com.android.systemui.common.ui.domain.interactor.configurationInteractor import com.android.systemui.keyguard.data.repository.keyguardBlueprintRepository +import com.android.systemui.keyguard.data.repository.keyguardClockSection +import com.android.systemui.keyguard.data.repository.keyguardSmartspaceSection import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.shade.domain.interactor.shadeInteractor @@ -34,5 +36,7 @@ val Kosmos.keyguardBlueprintInteractor by clockInteractor = keyguardClockInteractor, configurationInteractor = configurationInteractor, fingerprintPropertyInteractor = fingerprintPropertyInteractor, + clockSection = keyguardClockSection, + smartspaceSection = keyguardSmartspaceSection, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/QSPreferencesRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/QSPreferencesRepositoryKosmos.kt new file mode 100644 index 000000000000..39ae5eb44c65 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/QSPreferencesRepositoryKosmos.kt @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2024 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.qs.panels.data.repository + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.testDispatcher +import com.android.systemui.settings.userFileManager +import com.android.systemui.user.data.repository.userRepository + +val Kosmos.qsPreferencesRepository by + Kosmos.Fixture { QSPreferencesRepository(userFileManager, userRepository, testDispatcher) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/IconLabelVisibilityInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/IconLabelVisibilityInteractorKosmos.kt index 7b9e4a17e998..954084b874a0 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/IconLabelVisibilityInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/IconLabelVisibilityInteractorKosmos.kt @@ -19,12 +19,11 @@ package com.android.systemui.qs.panels.domain.interactor import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.log.core.FakeLogBuffer -import com.android.systemui.qs.panels.data.repository.iconLabelVisibilityRepository val Kosmos.iconLabelVisibilityInteractor by Kosmos.Fixture { IconLabelVisibilityInteractor( - iconLabelVisibilityRepository, + qsPreferencesInteractor, FakeLogBuffer.Factory.create(), applicationCoroutineScope ) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/IconLabelVisibilityRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/QSPreferencesInteractorKosmos.kt index 277dbb7016ad..eb83e325d79b 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/IconLabelVisibilityRepositoryKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/QSPreferencesInteractorKosmos.kt @@ -14,8 +14,10 @@ * limitations under the License. */ -package com.android.systemui.qs.panels.data.repository +package com.android.systemui.qs.panels.domain.interactor import com.android.systemui.kosmos.Kosmos +import com.android.systemui.qs.panels.data.repository.qsPreferencesRepository -val Kosmos.iconLabelVisibilityRepository by Kosmos.Fixture { IconLabelVisibilityRepository() } +val Kosmos.qsPreferencesInteractor by + Kosmos.Fixture { QSPreferencesInteractor(qsPreferencesRepository) } diff --git a/services/accessibility/accessibility.aconfig b/services/accessibility/accessibility.aconfig index 1c57dd3f5d5a..93531508b3eb 100644 --- a/services/accessibility/accessibility.aconfig +++ b/services/accessibility/accessibility.aconfig @@ -220,3 +220,13 @@ flag { description: "Feature allows users to change color correction saturation for daltonizer." bug: "322829049" } + +flag { + name: "skip_package_change_before_user_switch" + namespace: "accessibility" + description: "Skip onSomePackageChanged callback if the SwitchUser signal is not received yet." + bug: "340927041" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index 053a1a7c4ae9..20b727cd6f09 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -588,6 +588,15 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub return Thread.holdsLock(mLock); } + /** + * Returns if the service is initialized. + * + * The service is considered initialized when the user switch happened. + */ + private boolean isServiceInitializedLocked() { + return mInitialized; + } + @Override public int getCurrentUserIdLocked() { return mCurrentUserId; @@ -6234,6 +6243,15 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub if (userId != mManagerService.getCurrentUserIdLocked()) { return; } + + // Only continue setting up the packages if the service has been initialized. + // See: b/340927041 + if (Flags.skipPackageChangeBeforeUserSwitch() + && !mManagerService.isServiceInitializedLocked()) { + Slog.w(LOG_TAG, + "onSomePackagesChanged: service not initialized, skip the callback."); + return; + } mManagerService.onSomePackagesChangedLocked(parsedAccessibilityServiceInfos, parsedAccessibilityShortcutInfos); } diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java index dc1cfb92c3b8..ddccb3731cc1 100644 --- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java +++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java @@ -4008,20 +4008,10 @@ public class UserBackupManagerService { } private PackageInfo getPackageInfoForBMMLogging(String packageName) { - try { - return mPackageManager.getPackageInfoAsUser(packageName, 0, mUserId); - } catch (NameNotFoundException e) { - Slog.w( - TAG, - addUserIdToLogMessage( - mUserId, "Asked to get PackageInfo for BMM logging of nonexistent pkg " - + packageName)); - - PackageInfo packageInfo = new PackageInfo(); - packageInfo.packageName = packageName; + PackageInfo packageInfo = new PackageInfo(); + packageInfo.packageName = packageName; - return packageInfo; - } + return packageInfo; } /** Hand off a restore session. */ diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java index 30e4a3eb77e6..0d0c21dcf49c 100644 --- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java +++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java @@ -34,7 +34,6 @@ import static com.android.internal.util.function.pooled.PooledLambda.obtainMessa import static com.android.server.companion.utils.PackageUtils.enforceUsesCompanionDeviceFeature; import static com.android.server.companion.utils.PackageUtils.getPackageInfo; import static com.android.server.companion.utils.PackageUtils.isRestrictedSettingsAllowed; -import static com.android.server.companion.utils.PermissionsUtils.checkCallerCanManageCompanionDevice; import static com.android.server.companion.utils.PermissionsUtils.enforceCallerCanManageAssociationsForPackage; import static com.android.server.companion.utils.PermissionsUtils.enforceCallerIsSystemOr; import static com.android.server.companion.utils.PermissionsUtils.enforceCallerIsSystemOrCanInteractWithUserId; @@ -335,12 +334,6 @@ public class CompanionDeviceManagerService extends SystemService { enforceCallerCanManageAssociationsForPackage(getContext(), userId, packageName, "get associations"); - if (!checkCallerCanManageCompanionDevice(getContext())) { - // If the caller neither is system nor holds MANAGE_COMPANION_DEVICES: it needs to - // request the feature (also: the caller is the app itself). - enforceUsesCompanionDeviceFeature(getContext(), userId, packageName); - } - return mAssociationStore.getActiveAssociationsByPackage(userId, packageName); } diff --git a/services/companion/java/com/android/server/companion/association/AssociationRequestsProcessor.java b/services/companion/java/com/android/server/companion/association/AssociationRequestsProcessor.java index d09d7e672f9d..3fbd8560b82c 100644 --- a/services/companion/java/com/android/server/companion/association/AssociationRequestsProcessor.java +++ b/services/companion/java/com/android/server/companion/association/AssociationRequestsProcessor.java @@ -347,6 +347,8 @@ public class AssociationRequestsProcessor { * Set association tag. */ public void setAssociationTag(int associationId, String tag) { + Slog.i(TAG, "Setting association tag=[" + tag + "] to id=[" + associationId + "]..."); + AssociationInfo association = mAssociationStore.getAssociationWithCallerChecks( associationId); association = (new AssociationInfo.Builder(association)).setTag(tag).build(); diff --git a/services/companion/java/com/android/server/companion/association/AssociationStore.java b/services/companion/java/com/android/server/companion/association/AssociationStore.java index 29e8095f8680..757abd927ac8 100644 --- a/services/companion/java/com/android/server/companion/association/AssociationStore.java +++ b/services/companion/java/com/android/server/companion/association/AssociationStore.java @@ -18,7 +18,7 @@ package com.android.server.companion.association; import static com.android.server.companion.utils.MetricUtils.logCreateAssociation; import static com.android.server.companion.utils.MetricUtils.logRemoveAssociation; -import static com.android.server.companion.utils.PermissionsUtils.checkCallerCanManageAssociationsForPackage; +import static com.android.server.companion.utils.PermissionsUtils.enforceCallerCanManageAssociationsForPackage; import android.annotation.IntDef; import android.annotation.NonNull; @@ -457,6 +457,10 @@ public class AssociationStore { /** * Get association by id with caller checks. + * + * If the association is not found, an IllegalArgumentException would be thrown. + * + * If the caller can't access the association, a SecurityException would be thrown. */ @NonNull public AssociationInfo getAssociationWithCallerChecks(int associationId) { @@ -466,13 +470,9 @@ public class AssociationStore { "getAssociationWithCallerChecks() Association id=[" + associationId + "] doesn't exist."); } - if (checkCallerCanManageAssociationsForPackage(mContext, association.getUserId(), - association.getPackageName())) { - return association; - } - - throw new IllegalArgumentException( - "The caller can't interact with the association id=[" + associationId + "]."); + enforceCallerCanManageAssociationsForPackage(mContext, association.getUserId(), + association.getPackageName(), null); + return association; } /** diff --git a/services/companion/java/com/android/server/companion/association/DisassociationProcessor.java b/services/companion/java/com/android/server/companion/association/DisassociationProcessor.java index 8c1116b7a612..6f0baef019b3 100644 --- a/services/companion/java/com/android/server/companion/association/DisassociationProcessor.java +++ b/services/companion/java/com/android/server/companion/association/DisassociationProcessor.java @@ -98,7 +98,6 @@ public class DisassociationProcessor { Slog.i(TAG, "Disassociating id=[" + id + "]..."); final AssociationInfo association = mAssociationStore.getAssociationWithCallerChecks(id); - final int userId = association.getUserId(); final String packageName = association.getPackageName(); final String deviceProfile = association.getDeviceProfile(); diff --git a/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java index 026d29c9f821..00e049c1e1ff 100644 --- a/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java +++ b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java @@ -122,7 +122,6 @@ public class SystemDataTransferProcessor { */ public boolean isPermissionTransferUserConsented(int associationId) { mAssociationStore.getAssociationWithCallerChecks(associationId); - PermissionSyncRequest request = getPermissionSyncRequest(associationId); if (request == null) { return false; @@ -147,12 +146,12 @@ public class SystemDataTransferProcessor { return null; } - final AssociationInfo association = mAssociationStore.getAssociationWithCallerChecks( - associationId); - Slog.i(LOG_TAG, "Creating permission sync intent for userId [" + userId + "] associationId [" + associationId + "]"); + final AssociationInfo association = mAssociationStore.getAssociationWithCallerChecks( + associationId); + // Create an internal intent to launch the user consent dialog final Bundle extras = new Bundle(); PermissionSyncRequest request = new PermissionSyncRequest(associationId); @@ -220,7 +219,9 @@ public class SystemDataTransferProcessor { * Enable perm sync for the association */ public void enablePermissionsSync(int associationId) { - int userId = mAssociationStore.getAssociationWithCallerChecks(associationId).getUserId(); + AssociationInfo association = mAssociationStore.getAssociationWithCallerChecks( + associationId); + int userId = association.getUserId(); PermissionSyncRequest request = new PermissionSyncRequest(associationId); request.setUserConsented(true); mSystemDataTransferRequestStore.writeRequest(userId, request); @@ -230,7 +231,9 @@ public class SystemDataTransferProcessor { * Disable perm sync for the association */ public void disablePermissionsSync(int associationId) { - int userId = mAssociationStore.getAssociationWithCallerChecks(associationId).getUserId(); + AssociationInfo association = mAssociationStore.getAssociationWithCallerChecks( + associationId); + int userId = association.getUserId(); PermissionSyncRequest request = new PermissionSyncRequest(associationId); request.setUserConsented(false); mSystemDataTransferRequestStore.writeRequest(userId, request); @@ -241,8 +244,9 @@ public class SystemDataTransferProcessor { */ @Nullable public PermissionSyncRequest getPermissionSyncRequest(int associationId) { - int userId = mAssociationStore.getAssociationWithCallerChecks(associationId) - .getUserId(); + AssociationInfo association = mAssociationStore.getAssociationWithCallerChecks( + associationId); + int userId = association.getUserId(); List<SystemDataTransferRequest> requests = mSystemDataTransferRequestStore.readRequestsByAssociationId(userId, associationId); @@ -259,7 +263,9 @@ public class SystemDataTransferProcessor { */ public void removePermissionSyncRequest(int associationId) { Binder.withCleanCallingIdentity(() -> { - int userId = mAssociationStore.getAssociationById(associationId).getUserId(); + AssociationInfo association = mAssociationStore.getAssociationWithCallerChecks( + associationId); + int userId = association.getUserId(); mSystemDataTransferRequestStore.removeRequestsByAssociationId(userId, associationId); }); } diff --git a/services/companion/java/com/android/server/companion/devicepresence/BleDeviceProcessor.java b/services/companion/java/com/android/server/companion/devicepresence/BleDeviceProcessor.java index 6cdc02ec67a2..0a1bc0fdf4b8 100644 --- a/services/companion/java/com/android/server/companion/devicepresence/BleDeviceProcessor.java +++ b/services/companion/java/com/android/server/companion/devicepresence/BleDeviceProcessor.java @@ -241,7 +241,8 @@ class BleDeviceProcessor implements AssociationStore.OnChangeListener { final BroadcastReceiver receiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - checkBleState(); + // Post to the main thread to make sure it is a Non-Blocking call. + new Handler(Looper.getMainLooper()).post(() -> checkBleState()); } }; diff --git a/services/companion/java/com/android/server/companion/utils/PermissionsUtils.java b/services/companion/java/com/android/server/companion/utils/PermissionsUtils.java index f397814f7ad7..796d2851760f 100644 --- a/services/companion/java/com/android/server/companion/utils/PermissionsUtils.java +++ b/services/companion/java/com/android/server/companion/utils/PermissionsUtils.java @@ -149,21 +149,6 @@ public final class PermissionsUtils { } /** - * Check if the caller is system UID or the provided user. - */ - public static boolean checkCallerIsSystemOr(@UserIdInt int userId, - @NonNull String packageName) { - final int callingUid = getCallingUid(); - if (callingUid == SYSTEM_UID) return true; - - if (getCallingUserId() != userId) return false; - - if (!checkPackage(callingUid, packageName)) return false; - - return true; - } - - /** * Check if the calling user id matches the userId, and if the package belongs to * the calling uid. */ @@ -184,21 +169,30 @@ public final class PermissionsUtils { } /** - * Check if the caller holds the necessary permission to manage companion devices. - */ - public static boolean checkCallerCanManageCompanionDevice(@NonNull Context context) { - if (getCallingUid() == SYSTEM_UID) return true; - - return context.checkCallingPermission(MANAGE_COMPANION_DEVICES) == PERMISSION_GRANTED; - } - - /** * Require the caller to be able to manage the associations for the package. */ public static void enforceCallerCanManageAssociationsForPackage(@NonNull Context context, @UserIdInt int userId, @NonNull String packageName, @Nullable String actionDescription) { - if (checkCallerCanManageAssociationsForPackage(context, userId, packageName)) return; + final int callingUid = getCallingUid(); + + // If the caller is the system + if (callingUid == SYSTEM_UID) { + return; + } + + // If caller can manage the package or has the permissions to manage companion devices + boolean canInteractAcrossUsers = context.checkCallingPermission(INTERACT_ACROSS_USERS) + == PERMISSION_GRANTED; + boolean canManageCompanionDevices = context.checkCallingPermission(MANAGE_COMPANION_DEVICES) + == PERMISSION_GRANTED; + if (getCallingUserId() == userId) { + if (checkPackage(callingUid, packageName) || canManageCompanionDevices) { + return; + } + } else if (canInteractAcrossUsers && canManageCompanionDevices) { + return; + } throw new SecurityException("Caller (uid=" + getCallingUid() + ") does not have " + "permissions to " @@ -219,25 +213,6 @@ public final class PermissionsUtils { } } - /** - * Check if the caller is either: - * <ul> - * <li> the package itself - * <li> the System ({@link android.os.Process#SYSTEM_UID}) - * <li> holds {@link Manifest.permission#MANAGE_COMPANION_DEVICES} and, if belongs to a - * different user, also holds {@link Manifest.permission#INTERACT_ACROSS_USERS}. - * </ul> - * @return whether the caller is one of the above. - */ - public static boolean checkCallerCanManageAssociationsForPackage(@NonNull Context context, - @UserIdInt int userId, @NonNull String packageName) { - if (checkCallerIsSystemOr(userId, packageName)) return true; - - if (!checkCallerCanInteractWithUserId(context, userId)) return false; - - return checkCallerCanManageCompanionDevice(context); - } - private static boolean checkPackage(@UserIdInt int uid, @NonNull String packageName) { try { return getAppOpsService().checkPackage(uid, packageName) == MODE_ALLOWED; diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index 4dd3a8f67b0d..b35959f1a6e8 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -3980,7 +3980,7 @@ class StorageManagerService extends IStorageManager.Stub if (resUuids.contains(rec.fsUuid)) continue; // Treat as recent if mounted within the last week - if (rec.lastSeenMillis > 0 && rec.lastSeenMillis < lastWeek) { + if (rec.lastSeenMillis > 0 && rec.lastSeenMillis >= lastWeek) { final StorageVolume userVol = rec.buildStorageVolume(mContext); res.add(userVol); resUuids.add(userVol.getUuid()); diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 72c52544a44a..2addf6f9ec96 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -16,7 +16,20 @@ package com.android.server.audio; +import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; +import static android.Manifest.permission.BLUETOOTH_STACK; +import static android.Manifest.permission.CALL_AUDIO_INTERCEPTION; +import static android.Manifest.permission.CAPTURE_AUDIO_HOTWORD; +import static android.Manifest.permission.CAPTURE_AUDIO_OUTPUT; +import static android.Manifest.permission.CAPTURE_MEDIA_OUTPUT; +import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; +import static android.Manifest.permission.MODIFY_AUDIO_ROUTING; +import static android.Manifest.permission.MODIFY_AUDIO_SETTINGS; import static android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED; +import static android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS; +import static android.Manifest.permission.MODIFY_PHONE_STATE; +import static android.Manifest.permission.QUERY_AUDIO_STATE; +import static android.Manifest.permission.WRITE_SETTINGS; import static android.app.BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT; import static android.media.AudioDeviceInfo.TYPE_BLE_HEADSET; import static android.media.AudioDeviceInfo.TYPE_BLE_SPEAKER; @@ -1888,7 +1901,6 @@ public class AudioService extends IAudioService.Stub } mSpatializerHelper.reset(/* featureEnabled */ mHasSpatializerEffect); - mSoundDoseHelper.reset(); // Restore rotation information. if (mMonitorRotation) { @@ -1899,6 +1911,8 @@ public class AudioService extends IAudioService.Stub // indicate the end of reconfiguration phase to audio HAL AudioSystem.setParameters("restarting=false"); + mSoundDoseHelper.reset(/*resetISoundDose=*/true); + sendMsg(mAudioHandler, MSG_DISPATCH_AUDIO_SERVER_STATE, SENDMSG_QUEUE, 1, 0, null, 0); @@ -2075,7 +2089,7 @@ public class AudioService extends IAudioService.Stub } } - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + @android.annotation.EnforcePermission(MODIFY_AUDIO_ROUTING) /** * @see AudioManager#setSupportedSystemUsages(int[]) */ @@ -2090,7 +2104,7 @@ public class AudioService extends IAudioService.Stub } } - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + @android.annotation.EnforcePermission(MODIFY_AUDIO_ROUTING) /** * @see AudioManager#getSupportedSystemUsages() */ @@ -2110,7 +2124,7 @@ public class AudioService extends IAudioService.Stub } } - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + @android.annotation.EnforcePermission(MODIFY_AUDIO_ROUTING) /** * @return the {@link android.media.audiopolicy.AudioProductStrategy} discovered from the * platform configuration file. @@ -2124,9 +2138,7 @@ public class AudioService extends IAudioService.Stub } @android.annotation.EnforcePermission(anyOf = { - MODIFY_AUDIO_SETTINGS_PRIVILEGED, - android.Manifest.permission.MODIFY_AUDIO_ROUTING - }) + MODIFY_AUDIO_SETTINGS_PRIVILEGED, MODIFY_AUDIO_ROUTING }) /** * @return the List of {@link android.media.audiopolicy.AudioVolumeGroup} discovered from the * platform configuration file. @@ -2584,7 +2596,7 @@ public class AudioService extends IAudioService.Stub Log.w(TAG, "audioFormat to enable is not a surround format."); return false; } - if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.WRITE_SETTINGS) + if (mContext.checkCallingOrSelfPermission(WRITE_SETTINGS) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Missing WRITE_SETTINGS permission"); } @@ -2608,7 +2620,7 @@ public class AudioService extends IAudioService.Stub return true; } - @android.annotation.EnforcePermission(android.Manifest.permission.WRITE_SETTINGS) + @android.annotation.EnforcePermission(WRITE_SETTINGS) /** @see AudioManager#setEncodedSurroundMode(int) */ @Override public boolean setEncodedSurroundMode(@AudioManager.EncodedSurroundOutputMode int mode) { @@ -2786,7 +2798,7 @@ public class AudioService extends IAudioService.Stub if (!TextUtils.isEmpty(packageName)) { PackageManager pm = mContext.getPackageManager(); - if (pm.checkPermission(Manifest.permission.CAPTURE_AUDIO_HOTWORD, packageName) + if (pm.checkPermission(CAPTURE_AUDIO_HOTWORD, packageName) == PackageManager.PERMISSION_GRANTED) { try { assistantUid = pm.getPackageUidAsUser(packageName, getCurrentUserId()); @@ -2973,7 +2985,7 @@ public class AudioService extends IAudioService.Stub * @see AudioManager#setPreferredDevicesForStrategy(AudioProductStrategy, * List<AudioDeviceAttributes>) */ - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + @android.annotation.EnforcePermission(MODIFY_AUDIO_ROUTING) public int setPreferredDevicesForStrategy(int strategy, List<AudioDeviceAttributes> devices) { super.setPreferredDevicesForStrategy_enforcePermission(); if (devices == null) { @@ -3001,7 +3013,7 @@ public class AudioService extends IAudioService.Stub return status; } - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + @android.annotation.EnforcePermission(MODIFY_AUDIO_ROUTING) /** @see AudioManager#removePreferredDeviceForStrategy(AudioProductStrategy) */ public int removePreferredDevicesForStrategy(int strategy) { super.removePreferredDevicesForStrategy_enforcePermission(); @@ -3017,7 +3029,7 @@ public class AudioService extends IAudioService.Stub return status; } - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + @android.annotation.EnforcePermission(MODIFY_AUDIO_ROUTING) /** * @see AudioManager#getPreferredDeviceForStrategy(AudioProductStrategy) * @see AudioManager#getPreferredDevicesForStrategy(AudioProductStrategy) @@ -3049,7 +3061,7 @@ public class AudioService extends IAudioService.Stub * @see AudioManager#setDeviceAsNonDefaultForStrategy(AudioProductStrategy, * List<AudioDeviceAttributes>) */ - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + @android.annotation.EnforcePermission(MODIFY_AUDIO_ROUTING) public int setDeviceAsNonDefaultForStrategy(int strategy, @NonNull AudioDeviceAttributes device) { super.setDeviceAsNonDefaultForStrategy_enforcePermission(); @@ -3078,7 +3090,7 @@ public class AudioService extends IAudioService.Stub * @see AudioManager#removeDeviceAsNonDefaultForStrategy(AudioProductStrategy, * AudioDeviceAttributes) */ - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + @android.annotation.EnforcePermission(MODIFY_AUDIO_ROUTING) public int removeDeviceAsNonDefaultForStrategy(int strategy, AudioDeviceAttributes device) { super.removeDeviceAsNonDefaultForStrategy_enforcePermission(); @@ -3104,7 +3116,7 @@ public class AudioService extends IAudioService.Stub /** * @see AudioManager#getNonDefaultDevicesForStrategy(AudioProductStrategy) */ - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + @android.annotation.EnforcePermission(MODIFY_AUDIO_ROUTING) public List<AudioDeviceAttributes> getNonDefaultDevicesForStrategy(int strategy) { super.getNonDefaultDevicesForStrategy_enforcePermission(); List<AudioDeviceAttributes> devices = new ArrayList<>(); @@ -3205,7 +3217,7 @@ public class AudioService extends IAudioService.Stub return status; } - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + @android.annotation.EnforcePermission(MODIFY_AUDIO_ROUTING) /** @see AudioManager#clearPreferredDevicesForCapturePreset(int) */ public int clearPreferredDevicesForCapturePreset(int capturePreset) { super.clearPreferredDevicesForCapturePreset_enforcePermission(); @@ -3221,7 +3233,7 @@ public class AudioService extends IAudioService.Stub return status; } - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + @android.annotation.EnforcePermission(MODIFY_AUDIO_ROUTING) /** * @see AudioManager#getPreferredDevicesForCapturePreset(int) */ @@ -3555,7 +3567,7 @@ public class AudioService extends IAudioService.Stub if (isMuteAdjust && (streamType == AudioSystem.STREAM_VOICE_CALL || streamType == AudioSystem.STREAM_BLUETOOTH_SCO) && - mContext.checkPermission(android.Manifest.permission.MODIFY_PHONE_STATE, pid, uid) + mContext.checkPermission(MODIFY_PHONE_STATE, pid, uid) != PackageManager.PERMISSION_GRANTED) { Log.w(TAG, "MODIFY_PHONE_STATE Permission Denial: adjustStreamVolume from pid=" + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()); @@ -3566,7 +3578,7 @@ public class AudioService extends IAudioService.Stub // make sure that the calling app have the MODIFY_AUDIO_ROUTING permission. if (streamType == AudioSystem.STREAM_ASSISTANT && mContext.checkPermission( - android.Manifest.permission.MODIFY_AUDIO_ROUTING, pid, uid) + MODIFY_AUDIO_ROUTING, pid, uid) != PackageManager.PERMISSION_GRANTED) { Log.w(TAG, "MODIFY_AUDIO_ROUTING Permission Denial: adjustStreamVolume from pid=" + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()); @@ -3997,50 +4009,25 @@ public class AudioService extends IAudioService.Stub } private void enforceModifyAudioRoutingPermission() { - if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + if (mContext.checkCallingOrSelfPermission(MODIFY_AUDIO_ROUTING) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Missing MODIFY_AUDIO_ROUTING permission"); } } - private void enforceAccessUltrasoundPermission() { - if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.ACCESS_ULTRASOUND) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Missing ACCESS_ULTRASOUND permission"); - } - } - - private void enforceQueryStatePermission() { - if (mContext.checkCallingOrSelfPermission(Manifest.permission.QUERY_AUDIO_STATE) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Missing QUERY_AUDIO_STATE permissions"); - } - } - private void enforceQueryStateOrModifyRoutingPermission() { - if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + if (mContext.checkCallingOrSelfPermission(MODIFY_AUDIO_ROUTING) != PackageManager.PERMISSION_GRANTED - && mContext.checkCallingOrSelfPermission(Manifest.permission.QUERY_AUDIO_STATE) + && mContext.checkCallingOrSelfPermission(QUERY_AUDIO_STATE) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException( "Missing MODIFY_AUDIO_ROUTING or QUERY_AUDIO_STATE permissions"); } } - private void enforceCallAudioInterceptionPermission() { - if (mContext.checkCallingOrSelfPermission( - android.Manifest.permission.CALL_AUDIO_INTERCEPTION) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Missing CALL_AUDIO_INTERCEPTION permission"); - } - } - - @Override @android.annotation.EnforcePermission(anyOf = { - MODIFY_AUDIO_SETTINGS_PRIVILEGED, - android.Manifest.permission.MODIFY_AUDIO_ROUTING - }) + MODIFY_AUDIO_SETTINGS_PRIVILEGED, MODIFY_AUDIO_ROUTING }) /** @see AudioManager#setVolumeGroupVolumeIndex(int, int, int) */ public void setVolumeGroupVolumeIndex(int groupId, int index, int flags, String callingPackage, String attributionTag) { @@ -4074,9 +4061,7 @@ public class AudioService extends IAudioService.Stub @Override @android.annotation.EnforcePermission(anyOf = { - MODIFY_AUDIO_SETTINGS_PRIVILEGED, - android.Manifest.permission.MODIFY_AUDIO_ROUTING - }) + MODIFY_AUDIO_SETTINGS_PRIVILEGED, MODIFY_AUDIO_ROUTING }) /** @see AudioManager#getVolumeGroupVolumeIndex(int) */ public int getVolumeGroupVolumeIndex(int groupId) { super.getVolumeGroupVolumeIndex_enforcePermission(); @@ -4093,9 +4078,7 @@ public class AudioService extends IAudioService.Stub /** @see AudioManager#getVolumeGroupMaxVolumeIndex(int) */ @android.annotation.EnforcePermission(anyOf = { - MODIFY_AUDIO_SETTINGS_PRIVILEGED, - android.Manifest.permission.MODIFY_AUDIO_ROUTING - }) + MODIFY_AUDIO_SETTINGS_PRIVILEGED, MODIFY_AUDIO_ROUTING }) public int getVolumeGroupMaxVolumeIndex(int groupId) { super.getVolumeGroupMaxVolumeIndex_enforcePermission(); synchronized (VolumeStreamState.class) { @@ -4109,9 +4092,7 @@ public class AudioService extends IAudioService.Stub /** @see AudioManager#getVolumeGroupMinVolumeIndex(int) */ @android.annotation.EnforcePermission(anyOf = { - MODIFY_AUDIO_SETTINGS_PRIVILEGED, - android.Manifest.permission.MODIFY_AUDIO_ROUTING - }) + MODIFY_AUDIO_SETTINGS_PRIVILEGED, MODIFY_AUDIO_ROUTING }) public int getVolumeGroupMinVolumeIndex(int groupId) { super.getVolumeGroupMinVolumeIndex_enforcePermission(); synchronized (VolumeStreamState.class) { @@ -4125,9 +4106,7 @@ public class AudioService extends IAudioService.Stub @Override @android.annotation.EnforcePermission(anyOf = { - android.Manifest.permission.MODIFY_AUDIO_ROUTING, - android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED - }) + MODIFY_AUDIO_ROUTING, MODIFY_AUDIO_SETTINGS_PRIVILEGED }) /** @see AudioDeviceVolumeManager#setDeviceVolume(VolumeInfo, AudioDeviceAttributes) * Part of service interface, check permissions and parameters here * Note calling package is for logging purposes only, not to be trusted @@ -4253,7 +4232,7 @@ public class AudioService extends IAudioService.Stub } /** @see AudioManager#getLastAudibleVolumeForVolumeGroup(int) */ - @android.annotation.EnforcePermission(android.Manifest.permission.QUERY_AUDIO_STATE) + @android.annotation.EnforcePermission(QUERY_AUDIO_STATE) public int getLastAudibleVolumeForVolumeGroup(int groupId) { super.getLastAudibleVolumeForVolumeGroup_enforcePermission(); synchronized (VolumeStreamState.class) { @@ -4318,16 +4297,14 @@ public class AudioService extends IAudioService.Stub return; } if ((streamType == AudioManager.STREAM_VOICE_CALL) && (index == 0) - && (mContext.checkCallingOrSelfPermission( - android.Manifest.permission.MODIFY_PHONE_STATE) + && (mContext.checkCallingOrSelfPermission(MODIFY_PHONE_STATE) != PackageManager.PERMISSION_GRANTED)) { Log.w(TAG, "Trying to call setStreamVolume() for STREAM_VOICE_CALL and index 0 without" + " MODIFY_PHONE_STATE callingPackage=" + callingPackage); return; } if ((streamType == AudioManager.STREAM_ASSISTANT) - && (mContext.checkCallingOrSelfPermission( - android.Manifest.permission.MODIFY_AUDIO_ROUTING) + && (mContext.checkCallingOrSelfPermission(MODIFY_AUDIO_ROUTING) != PackageManager.PERMISSION_GRANTED)) { Log.w(TAG, "Trying to call setStreamVolume() for STREAM_ASSISTANT without" + " MODIFY_AUDIO_ROUTING callingPackage=" + callingPackage); @@ -4348,7 +4325,7 @@ public class AudioService extends IAudioService.Stub canChangeMuteAndUpdateController); } - @android.annotation.EnforcePermission(android.Manifest.permission.ACCESS_ULTRASOUND) + @android.annotation.EnforcePermission(Manifest.permission.ACCESS_ULTRASOUND) /** @see AudioManager#isUltrasoundSupported() */ public boolean isUltrasoundSupported() { super.isUltrasoundSupported_enforcePermission(); @@ -4356,8 +4333,8 @@ public class AudioService extends IAudioService.Stub return AudioSystem.isUltrasoundSupported(); } - /** @see AudioManager#isHotwordStreamSupported() */ - @android.annotation.EnforcePermission(android.Manifest.permission.CAPTURE_AUDIO_HOTWORD) + /** @see AudioManager#isHotwordStreamSupported(boolean) */ + @android.annotation.EnforcePermission(CAPTURE_AUDIO_HOTWORD) public boolean isHotwordStreamSupported(boolean lookbackAudio) { super.isHotwordStreamSupported_enforcePermission(); try { @@ -4373,7 +4350,7 @@ public class AudioService extends IAudioService.Stub private boolean canChangeAccessibilityVolume() { synchronized (mAccessibilityServiceUidsLock) { if (PackageManager.PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission( - android.Manifest.permission.CHANGE_ACCESSIBILITY_VOLUME)) { + Manifest.permission.CHANGE_ACCESSIBILITY_VOLUME)) { return true; } if (mAccessibilityServiceUids != null) { @@ -4874,7 +4851,7 @@ public class AudioService extends IAudioService.Stub /** @see AudioManager#forceVolumeControlStream(int) */ public void forceVolumeControlStream(int streamType, IBinder cb) { - if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + if (mContext.checkCallingOrSelfPermission(MODIFY_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) { return; } @@ -5127,7 +5104,7 @@ public class AudioService extends IAudioService.Stub return; } if ((PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission( - android.Manifest.permission.CAPTURE_AUDIO_OUTPUT))) { + CAPTURE_AUDIO_OUTPUT))) { Log.w(TAG, "Trying to call forceRemoteSubmixFullVolume() without CAPTURE_AUDIO_OUTPUT"); return; } @@ -5174,8 +5151,7 @@ public class AudioService extends IAudioService.Stub return; } if (userId != UserHandle.getCallingUserId() && - mContext.checkPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, - pid, uid) + mContext.checkPermission(INTERACT_ACROSS_USERS_FULL, pid, uid) != PackageManager.PERMISSION_GRANTED) { return; } @@ -5216,7 +5192,7 @@ public class AudioService extends IAudioService.Stub return mMasterMute.get(); } - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + @android.annotation.EnforcePermission(MODIFY_AUDIO_ROUTING) /** @see AudioManager#setMasterMute(boolean, int) */ public void setMasterMute(boolean mute, int flags, String callingPackage, int userId, String attributionTag) { @@ -5252,9 +5228,7 @@ public class AudioService extends IAudioService.Stub @Override @android.annotation.EnforcePermission(anyOf = { - android.Manifest.permission.MODIFY_AUDIO_ROUTING, - android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED - }) + MODIFY_AUDIO_ROUTING, MODIFY_AUDIO_SETTINGS_PRIVILEGED }) /** * @see AudioDeviceVolumeManager#getDeviceVolume(VolumeInfo, AudioDeviceAttributes) */ @@ -5302,12 +5276,12 @@ public class AudioService extends IAudioService.Stub final boolean isPrivileged = Binder.getCallingUid() == Process.SYSTEM_UID || callingHasAudioSettingsPermission() - || (mContext.checkCallingPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) + || (mContext.checkCallingPermission(MODIFY_AUDIO_ROUTING) == PackageManager.PERMISSION_GRANTED); return (mStreamStates[streamType].getMinIndex(isPrivileged) + 5) / 10; } - @android.annotation.EnforcePermission(android.Manifest.permission.QUERY_AUDIO_STATE) + @android.annotation.EnforcePermission(QUERY_AUDIO_STATE) /** Get last audible volume before stream was muted. */ public int getLastAudibleStreamVolume(int streamType) { super.getLastAudibleStreamVolume_enforcePermission(); @@ -5469,8 +5443,7 @@ public class AudioService extends IAudioService.Stub return; } if (userId != UserHandle.getCallingUserId() && - mContext.checkCallingOrSelfPermission( - android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) + mContext.checkCallingOrSelfPermission(INTERACT_ACROSS_USERS_FULL) != PackageManager.PERMISSION_GRANTED) { mmi.set(MediaMetrics.Property.EARLY_RETURN, "permission").record(); return; @@ -6060,7 +6033,7 @@ public class AudioService extends IAudioService.Stub } final boolean hasModifyPhoneStatePermission = mContext.checkCallingOrSelfPermission( - android.Manifest.permission.MODIFY_PHONE_STATE) + MODIFY_PHONE_STATE) == PackageManager.PERMISSION_GRANTED; if ((mode == AudioSystem.MODE_IN_CALL || mode == AudioSystem.MODE_CALL_REDIRECT @@ -6267,7 +6240,7 @@ public class AudioService extends IAudioService.Stub mModeDispatchers.unregister(dispatcher); } - @android.annotation.EnforcePermission(android.Manifest.permission.CALL_AUDIO_INTERCEPTION) + @android.annotation.EnforcePermission(CALL_AUDIO_INTERCEPTION) /** @see AudioManager#isPstnCallAudioInterceptable() */ public boolean isPstnCallAudioInterceptable() { @@ -6293,7 +6266,7 @@ public class AudioService extends IAudioService.Stub @Override public void setRttEnabled(boolean rttEnabled) { if (mContext.checkCallingOrSelfPermission( - android.Manifest.permission.MODIFY_PHONE_STATE) + MODIFY_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) { Log.w(TAG, "MODIFY_PHONE_STATE Permission Denial: setRttEnabled from pid=" + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()); @@ -6585,8 +6558,7 @@ public class AudioService extends IAudioService.Stub ? MediaMetrics.Value.CONNECTED : MediaMetrics.Value.DISCONNECTED) .record(); } - final boolean isPrivileged = mContext.checkCallingOrSelfPermission( - android.Manifest.permission.MODIFY_PHONE_STATE) + final boolean isPrivileged = mContext.checkCallingOrSelfPermission(MODIFY_PHONE_STATE) == PackageManager.PERMISSION_GRANTED; final long ident = Binder.clearCallingIdentity(); try { @@ -6636,8 +6608,7 @@ public class AudioService extends IAudioService.Stub if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) { return; } - final boolean isPrivileged = mContext.checkCallingOrSelfPermission( - android.Manifest.permission.MODIFY_PHONE_STATE) + final boolean isPrivileged = mContext.checkCallingOrSelfPermission(MODIFY_PHONE_STATE) == PackageManager.PERMISSION_GRANTED; // for logging only @@ -6704,7 +6675,7 @@ public class AudioService extends IAudioService.Stub } /** @see AudioManager#setA2dpSuspended(boolean) */ - @android.annotation.EnforcePermission(android.Manifest.permission.BLUETOOTH_STACK) + @android.annotation.EnforcePermission(BLUETOOTH_STACK) public void setA2dpSuspended(boolean enable) { super.setA2dpSuspended_enforcePermission(); final String eventSource = new StringBuilder("setA2dpSuspended(").append(enable) @@ -6714,7 +6685,7 @@ public class AudioService extends IAudioService.Stub } /** @see AudioManager#setA2dpSuspended(boolean) */ - @android.annotation.EnforcePermission(android.Manifest.permission.BLUETOOTH_STACK) + @android.annotation.EnforcePermission(BLUETOOTH_STACK) public void setLeAudioSuspended(boolean enable) { super.setLeAudioSuspended_enforcePermission(); final String eventSource = new StringBuilder("setLeAudioSuspended(").append(enable) @@ -6819,8 +6790,7 @@ public class AudioService extends IAudioService.Stub mmi.set(MediaMetrics.Property.EARLY_RETURN, "permission or systemReady").record(); return; } - final boolean isPrivileged = mContext.checkCallingOrSelfPermission( - android.Manifest.permission.MODIFY_PHONE_STATE) + final boolean isPrivileged = mContext.checkCallingOrSelfPermission(MODIFY_PHONE_STATE) == PackageManager.PERMISSION_GRANTED; final long ident = Binder.clearCallingIdentity(); try { @@ -6843,8 +6813,7 @@ public class AudioService extends IAudioService.Stub final String eventSource = new StringBuilder("stopBluetoothSco()") .append(") from u/pid:").append(uid).append("/") .append(pid).toString(); - final boolean isPrivileged = mContext.checkCallingOrSelfPermission( - android.Manifest.permission.MODIFY_PHONE_STATE) + final boolean isPrivileged = mContext.checkCallingOrSelfPermission(MODIFY_PHONE_STATE) == PackageManager.PERMISSION_GRANTED; final long ident = Binder.clearCallingIdentity(); try { @@ -7325,17 +7294,17 @@ public class AudioService extends IAudioService.Stub } private boolean callingOrSelfHasAudioSettingsPermission() { - return mContext.checkCallingOrSelfPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS) + return mContext.checkCallingOrSelfPermission(MODIFY_AUDIO_SETTINGS) == PackageManager.PERMISSION_GRANTED; } private boolean callingHasAudioSettingsPermission() { - return mContext.checkCallingPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS) + return mContext.checkCallingPermission(MODIFY_AUDIO_SETTINGS) == PackageManager.PERMISSION_GRANTED; } private boolean hasAudioSettingsPermission(int uid, int pid) { - return mContext.checkPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS, pid, uid) + return mContext.checkPermission(MODIFY_AUDIO_SETTINGS, pid, uid) == PackageManager.PERMISSION_GRANTED; } @@ -7527,17 +7496,16 @@ public class AudioService extends IAudioService.Stub * @param register Whether the listener is to be registered or unregistered. If false, the * device adopts variable volume behavior. */ - @RequiresPermission(anyOf = { android.Manifest.permission.MODIFY_AUDIO_ROUTING, - android.Manifest.permission.BLUETOOTH_PRIVILEGED }) + @RequiresPermission(anyOf = { MODIFY_AUDIO_ROUTING, BLUETOOTH_PRIVILEGED }) public void registerDeviceVolumeDispatcherForAbsoluteVolume(boolean register, IAudioDeviceVolumeDispatcher cb, String packageName, AudioDeviceAttributes device, List<VolumeInfo> volumes, boolean handlesVolumeAdjustment, @AudioManager.AbsoluteDeviceVolumeBehavior int deviceVolumeBehavior) { // verify permissions - if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + if (mContext.checkCallingOrSelfPermission(MODIFY_AUDIO_ROUTING) != PackageManager.PERMISSION_GRANTED - && mContext.checkCallingOrSelfPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + && mContext.checkCallingOrSelfPermission(BLUETOOTH_PRIVILEGED) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException( "Missing MODIFY_AUDIO_ROUTING or BLUETOOTH_PRIVILEGED permissions"); @@ -7595,9 +7563,7 @@ public class AudioService extends IAudioService.Stub * @param deviceVolumeBehavior one of the device behaviors */ @android.annotation.EnforcePermission(anyOf = { - android.Manifest.permission.MODIFY_AUDIO_ROUTING, - android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED - }) + MODIFY_AUDIO_ROUTING, MODIFY_AUDIO_SETTINGS_PRIVILEGED }) public void setDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device, @AudioManager.DeviceVolumeBehavior int deviceVolumeBehavior, @Nullable String pkgName) { // verify permissions @@ -7680,9 +7646,7 @@ public class AudioService extends IAudioService.Stub * @return the volume behavior for the device */ @android.annotation.EnforcePermission(anyOf = { - android.Manifest.permission.MODIFY_AUDIO_ROUTING, - android.Manifest.permission.QUERY_AUDIO_STATE, - android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED + MODIFY_AUDIO_ROUTING, QUERY_AUDIO_STATE, MODIFY_AUDIO_SETTINGS_PRIVILEGED }) public @AudioManager.DeviceVolumeBehavior int getDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device) { @@ -7770,7 +7734,7 @@ public class AudioService extends IAudioService.Stub */ private static final byte[] DEFAULT_ARC_AUDIO_DESCRIPTOR = new byte[]{0x09, 0x7f, 0x07}; - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + @android.annotation.EnforcePermission(MODIFY_AUDIO_ROUTING) /** * see AudioManager.setWiredDeviceConnectionState() */ @@ -7880,7 +7844,7 @@ public class AudioService extends IAudioService.Stub public @interface BtProfile {} - @android.annotation.EnforcePermission(android.Manifest.permission.BLUETOOTH_STACK) + @android.annotation.EnforcePermission(BLUETOOTH_STACK) /** * See AudioManager.handleBluetoothActiveDeviceChanged(...) */ @@ -10156,8 +10120,8 @@ public class AudioService extends IAudioService.Stub if (AudioAttributes.isSystemUsage(usage)) { if ((usage == AudioAttributes.USAGE_CALL_ASSISTANT && (audioAttributes.getAllFlags() & AudioAttributes.FLAG_CALL_REDIRECTION) != 0 - && callerHasPermission(Manifest.permission.CALL_AUDIO_INTERCEPTION)) - || callerHasPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)) { + && callerHasPermission(CALL_AUDIO_INTERCEPTION)) + || callerHasPermission(MODIFY_AUDIO_ROUTING)) { if (!isSupportedSystemUsage(usage)) { throw new IllegalArgumentException( "Unsupported usage " + AudioAttributes.usageToString(usage)); @@ -10175,8 +10139,8 @@ public class AudioService extends IAudioService.Stub && ((usage == AudioAttributes.USAGE_CALL_ASSISTANT && (audioAttributes.getAllFlags() & AudioAttributes.FLAG_CALL_REDIRECTION) != 0 - && callerHasPermission(Manifest.permission.CALL_AUDIO_INTERCEPTION)) - || callerHasPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)); + && callerHasPermission(CALL_AUDIO_INTERCEPTION)) + || callerHasPermission(MODIFY_AUDIO_ROUTING)); } return true; } @@ -10207,7 +10171,7 @@ public class AudioService extends IAudioService.Stub if ((flags & AudioManager.AUDIOFOCUS_FLAG_LOCK) == AudioManager.AUDIOFOCUS_FLAG_LOCK) { if (AudioSystem.IN_VOICE_COMM_FOCUS_ID.equals(clientId)) { if (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission( - android.Manifest.permission.MODIFY_PHONE_STATE)) { + MODIFY_PHONE_STATE)) { final String reason = "Invalid permission to (un)lock audio focus"; Log.e(TAG, reason, new Exception()); mmi.set(MediaMetrics.Property.EARLY_RETURN, reason) @@ -10239,10 +10203,9 @@ public class AudioService extends IAudioService.Stub // does caller have system privileges to bypass HardeningEnforcer boolean permissionOverridesCheck = false; - if ((mContext.checkCallingOrSelfPermission( - Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) + if ((mContext.checkCallingOrSelfPermission(MODIFY_AUDIO_SETTINGS_PRIVILEGED) == PackageManager.PERMISSION_GRANTED) - || (mContext.checkCallingOrSelfPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) + || (mContext.checkCallingOrSelfPermission(MODIFY_AUDIO_ROUTING) == PackageManager.PERMISSION_GRANTED)) { permissionOverridesCheck = true; } else if (uid < UserHandle.AID_APP_START) { @@ -10376,7 +10339,7 @@ public class AudioService extends IAudioService.Stub * such as another freeze currently used. */ @Override - @EnforcePermission("android.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED") + @EnforcePermission(MODIFY_AUDIO_SETTINGS_PRIVILEGED) public boolean enterAudioFocusFreezeForTest(IBinder cb, int[] exemptedUids) { super.enterAudioFocusFreezeForTest_enforcePermission(); Objects.requireNonNull(exemptedUids); @@ -10392,7 +10355,7 @@ public class AudioService extends IAudioService.Stub * such as the freeze already having ended, or not started. */ @Override - @EnforcePermission("android.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED") + @EnforcePermission(MODIFY_AUDIO_SETTINGS_PRIVILEGED) public boolean exitAudioFocusFreezeForTest(IBinder cb) { super.exitAudioFocusFreezeForTest_enforcePermission(); Objects.requireNonNull(cb); @@ -10438,8 +10401,7 @@ public class AudioService extends IAudioService.Stub private static final boolean SPATIAL_AUDIO_ENABLED_DEFAULT = true; private void enforceModifyDefaultAudioEffectsPermission() { - if (mContext.checkCallingOrSelfPermission( - android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS) + if (mContext.checkCallingOrSelfPermission(MODIFY_DEFAULT_AUDIO_EFFECTS) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Missing MODIFY_DEFAULT_AUDIO_EFFECTS permission"); } @@ -10463,7 +10425,7 @@ public class AudioService extends IAudioService.Stub return mSpatializerHelper.isAvailable(); } - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS) + @android.annotation.EnforcePermission(MODIFY_DEFAULT_AUDIO_EFFECTS) /** @see Spatializer#isAvailableForDevice(AudioDeviceAttributes) */ public boolean isSpatializerAvailableForDevice(@NonNull AudioDeviceAttributes device) { super.isSpatializerAvailableForDevice_enforcePermission(); @@ -10471,7 +10433,7 @@ public class AudioService extends IAudioService.Stub return mSpatializerHelper.isAvailableForDevice(Objects.requireNonNull(device)); } - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS) + @android.annotation.EnforcePermission(MODIFY_DEFAULT_AUDIO_EFFECTS) /** @see Spatializer#hasHeadTracker(AudioDeviceAttributes) */ public boolean hasHeadTracker(@NonNull AudioDeviceAttributes device) { super.hasHeadTracker_enforcePermission(); @@ -10479,7 +10441,7 @@ public class AudioService extends IAudioService.Stub return mSpatializerHelper.hasHeadTracker(Objects.requireNonNull(device)); } - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS) + @android.annotation.EnforcePermission(MODIFY_DEFAULT_AUDIO_EFFECTS) /** @see Spatializer#setHeadTrackerEnabled(boolean, AudioDeviceAttributes) */ public void setHeadTrackerEnabled(boolean enabled, @NonNull AudioDeviceAttributes device) { super.setHeadTrackerEnabled_enforcePermission(); @@ -10487,7 +10449,7 @@ public class AudioService extends IAudioService.Stub mSpatializerHelper.setHeadTrackerEnabled(enabled, Objects.requireNonNull(device)); } - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS) + @android.annotation.EnforcePermission(MODIFY_DEFAULT_AUDIO_EFFECTS) /** @see Spatializer#isHeadTrackerEnabled(AudioDeviceAttributes) */ public boolean isHeadTrackerEnabled(@NonNull AudioDeviceAttributes device) { super.isHeadTrackerEnabled_enforcePermission(); @@ -10500,7 +10462,7 @@ public class AudioService extends IAudioService.Stub return mSpatializerHelper.isHeadTrackerAvailable(); } - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS) + @android.annotation.EnforcePermission(MODIFY_DEFAULT_AUDIO_EFFECTS) /** @see Spatializer#setSpatializerEnabled(boolean) */ public void setSpatializerEnabled(boolean enabled) { super.setSpatializerEnabled_enforcePermission(); @@ -10530,7 +10492,7 @@ public class AudioService extends IAudioService.Stub mSpatializerHelper.unregisterStateCallback(cb); } - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS) + @android.annotation.EnforcePermission(MODIFY_DEFAULT_AUDIO_EFFECTS) /** @see Spatializer#SpatializerHeadTrackingDispatcherStub */ public void registerSpatializerHeadTrackingCallback( @NonNull ISpatializerHeadTrackingModeCallback cb) { @@ -10540,7 +10502,7 @@ public class AudioService extends IAudioService.Stub mSpatializerHelper.registerHeadTrackingModeCallback(cb); } - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS) + @android.annotation.EnforcePermission(MODIFY_DEFAULT_AUDIO_EFFECTS) /** @see Spatializer#SpatializerHeadTrackingDispatcherStub */ public void unregisterSpatializerHeadTrackingCallback( @NonNull ISpatializerHeadTrackingModeCallback cb) { @@ -10557,7 +10519,7 @@ public class AudioService extends IAudioService.Stub mSpatializerHelper.registerHeadTrackerAvailableCallback(cb, register); } - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS) + @android.annotation.EnforcePermission(MODIFY_DEFAULT_AUDIO_EFFECTS) /** @see Spatializer#setOnHeadToSoundstagePoseUpdatedListener */ public void registerHeadToSoundstagePoseCallback( @NonNull ISpatializerHeadToSoundStagePoseCallback cb) { @@ -10567,7 +10529,7 @@ public class AudioService extends IAudioService.Stub mSpatializerHelper.registerHeadToSoundstagePoseCallback(cb); } - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS) + @android.annotation.EnforcePermission(MODIFY_DEFAULT_AUDIO_EFFECTS) /** @see Spatializer#clearOnHeadToSoundstagePoseUpdatedListener */ public void unregisterHeadToSoundstagePoseCallback( @NonNull ISpatializerHeadToSoundStagePoseCallback cb) { @@ -10577,7 +10539,7 @@ public class AudioService extends IAudioService.Stub mSpatializerHelper.unregisterHeadToSoundstagePoseCallback(cb); } - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS) + @android.annotation.EnforcePermission(MODIFY_DEFAULT_AUDIO_EFFECTS) /** @see Spatializer#getSpatializerCompatibleAudioDevices() */ public @NonNull List<AudioDeviceAttributes> getSpatializerCompatibleAudioDevices() { super.getSpatializerCompatibleAudioDevices_enforcePermission(); @@ -10585,7 +10547,7 @@ public class AudioService extends IAudioService.Stub return mSpatializerHelper.getCompatibleAudioDevices(); } - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS) + @android.annotation.EnforcePermission(MODIFY_DEFAULT_AUDIO_EFFECTS) /** @see Spatializer#addSpatializerCompatibleAudioDevice(AudioDeviceAttributes) */ public void addSpatializerCompatibleAudioDevice(@NonNull AudioDeviceAttributes ada) { super.addSpatializerCompatibleAudioDevice_enforcePermission(); @@ -10594,7 +10556,7 @@ public class AudioService extends IAudioService.Stub mSpatializerHelper.addCompatibleAudioDevice(ada); } - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS) + @android.annotation.EnforcePermission(MODIFY_DEFAULT_AUDIO_EFFECTS) /** @see Spatializer#removeSpatializerCompatibleAudioDevice(AudioDeviceAttributes) */ public void removeSpatializerCompatibleAudioDevice(@NonNull AudioDeviceAttributes ada) { super.removeSpatializerCompatibleAudioDevice_enforcePermission(); @@ -10603,7 +10565,7 @@ public class AudioService extends IAudioService.Stub mSpatializerHelper.removeCompatibleAudioDevice(ada); } - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS) + @android.annotation.EnforcePermission(MODIFY_DEFAULT_AUDIO_EFFECTS) /** @see Spatializer#getSupportedHeadTrackingModes() */ public int[] getSupportedHeadTrackingModes() { super.getSupportedHeadTrackingModes_enforcePermission(); @@ -10611,7 +10573,7 @@ public class AudioService extends IAudioService.Stub return mSpatializerHelper.getSupportedHeadTrackingModes(); } - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS) + @android.annotation.EnforcePermission(MODIFY_DEFAULT_AUDIO_EFFECTS) /** @see Spatializer#getHeadTrackingMode() */ public int getActualHeadTrackingMode() { super.getActualHeadTrackingMode_enforcePermission(); @@ -10619,7 +10581,7 @@ public class AudioService extends IAudioService.Stub return mSpatializerHelper.getActualHeadTrackingMode(); } - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS) + @android.annotation.EnforcePermission(MODIFY_DEFAULT_AUDIO_EFFECTS) /** @see Spatializer#getDesiredHeadTrackingMode() */ public int getDesiredHeadTrackingMode() { super.getDesiredHeadTrackingMode_enforcePermission(); @@ -10627,7 +10589,7 @@ public class AudioService extends IAudioService.Stub return mSpatializerHelper.getDesiredHeadTrackingMode(); } - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS) + @android.annotation.EnforcePermission(MODIFY_DEFAULT_AUDIO_EFFECTS) /** @see Spatializer#setGlobalTransform */ public void setSpatializerGlobalTransform(@NonNull float[] transform) { super.setSpatializerGlobalTransform_enforcePermission(); @@ -10636,7 +10598,7 @@ public class AudioService extends IAudioService.Stub mSpatializerHelper.setGlobalTransform(transform); } - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS) + @android.annotation.EnforcePermission(MODIFY_DEFAULT_AUDIO_EFFECTS) /** @see Spatializer#recenterHeadTracker() */ public void recenterHeadTracker() { super.recenterHeadTracker_enforcePermission(); @@ -10644,7 +10606,7 @@ public class AudioService extends IAudioService.Stub mSpatializerHelper.recenterHeadTracker(); } - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS) + @android.annotation.EnforcePermission(MODIFY_DEFAULT_AUDIO_EFFECTS) /** @see Spatializer#setDesiredHeadTrackingMode */ public void setDesiredHeadTrackingMode(@Spatializer.HeadTrackingModeSet int mode) { super.setDesiredHeadTrackingMode_enforcePermission(); @@ -10660,7 +10622,7 @@ public class AudioService extends IAudioService.Stub mSpatializerHelper.setDesiredHeadTrackingMode(mode); } - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS) + @android.annotation.EnforcePermission(MODIFY_DEFAULT_AUDIO_EFFECTS) /** @see Spatializer#setEffectParameter */ public void setSpatializerParameter(int key, @NonNull byte[] value) { super.setSpatializerParameter_enforcePermission(); @@ -10669,7 +10631,7 @@ public class AudioService extends IAudioService.Stub mSpatializerHelper.setEffectParameter(key, value); } - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS) + @android.annotation.EnforcePermission(MODIFY_DEFAULT_AUDIO_EFFECTS) /** @see Spatializer#getEffectParameter */ public void getSpatializerParameter(int key, @NonNull byte[] value) { super.getSpatializerParameter_enforcePermission(); @@ -10678,7 +10640,7 @@ public class AudioService extends IAudioService.Stub mSpatializerHelper.getEffectParameter(key, value); } - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS) + @android.annotation.EnforcePermission(MODIFY_DEFAULT_AUDIO_EFFECTS) /** @see Spatializer#getOutput */ public int getSpatializerOutput() { super.getSpatializerOutput_enforcePermission(); @@ -10686,7 +10648,7 @@ public class AudioService extends IAudioService.Stub return mSpatializerHelper.getOutput(); } - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS) + @android.annotation.EnforcePermission(MODIFY_DEFAULT_AUDIO_EFFECTS) /** @see Spatializer#setOnSpatializerOutputChangedListener */ public void registerSpatializerOutputCallback(ISpatializerOutputCallback cb) { super.registerSpatializerOutputCallback_enforcePermission(); @@ -10695,7 +10657,7 @@ public class AudioService extends IAudioService.Stub mSpatializerHelper.registerSpatializerOutputCallback(cb); } - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS) + @android.annotation.EnforcePermission(MODIFY_DEFAULT_AUDIO_EFFECTS) /** @see Spatializer#clearOnSpatializerOutputChangedListener */ public void unregisterSpatializerOutputCallback(ISpatializerOutputCallback cb) { super.unregisterSpatializerOutputCallback_enforcePermission(); @@ -10742,7 +10704,7 @@ public class AudioService extends IAudioService.Stub private boolean isBluetoothPrividged() { return PackageManager.PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission( - android.Manifest.permission.BLUETOOTH_CONNECT) + Manifest.permission.BLUETOOTH_CONNECT) || Binder.getCallingUid() == Process.SYSTEM_UID; } @@ -10949,7 +10911,7 @@ public class AudioService extends IAudioService.Stub }); } - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + @android.annotation.EnforcePermission(MODIFY_AUDIO_ROUTING) /** @see AudioManager#getMutingExpectedDevice */ public @Nullable AudioDeviceAttributes getMutingExpectedDevice() { super.getMutingExpectedDevice_enforcePermission(); @@ -11000,7 +10962,7 @@ public class AudioService extends IAudioService.Stub final RemoteCallbackList<IMuteAwaitConnectionCallback> mMuteAwaitConnectionDispatchers = new RemoteCallbackList<IMuteAwaitConnectionCallback>(); - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + @android.annotation.EnforcePermission(MODIFY_AUDIO_ROUTING) /** @see AudioManager#registerMuteAwaitConnectionCallback */ public void registerMuteAwaitConnectionDispatcher(@NonNull IMuteAwaitConnectionCallback cb, boolean register) { @@ -11175,7 +11137,7 @@ public class AudioService extends IAudioService.Stub } } - @android.annotation.EnforcePermission(android.Manifest.permission.REMOTE_AUDIO_PLAYBACK) + @android.annotation.EnforcePermission(Manifest.permission.REMOTE_AUDIO_PLAYBACK) @Override public void setRingtonePlayer(IRingtonePlayer player) { setRingtonePlayer_enforcePermission(); @@ -11376,7 +11338,6 @@ public class AudioService extends IAudioService.Stub @Override @android.annotation.EnforcePermission(MODIFY_AUDIO_SETTINGS_PRIVILEGED) - @AudioDeviceCategory public boolean isBluetoothAudioDeviceCategoryFixed(@NonNull String address) { super.isBluetoothAudioDeviceCategoryFixed_enforcePermission(); if (!automaticBtDeviceType()) { @@ -11892,7 +11853,7 @@ public class AudioService extends IAudioService.Stub } private void enforceVolumeController(String action) { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE, + mContext.enforceCallingOrSelfPermission(Manifest.permission.STATUS_BAR_SERVICE, "Only SystemUI can " + action); } @@ -12396,8 +12357,8 @@ public class AudioService extends IAudioService.Stub } if (requireCaptureAudioOrMediaOutputPerm - && !callerHasPermission(android.Manifest.permission.CAPTURE_MEDIA_OUTPUT) - && !callerHasPermission(android.Manifest.permission.CAPTURE_AUDIO_OUTPUT)) { + && !callerHasPermission(CAPTURE_MEDIA_OUTPUT) + && !callerHasPermission(CAPTURE_AUDIO_OUTPUT)) { Log.e(TAG, "Privileged audio capture requires CAPTURE_MEDIA_OUTPUT or " + "CAPTURE_AUDIO_OUTPUT system permission"); return false; @@ -12405,7 +12366,7 @@ public class AudioService extends IAudioService.Stub if (voiceCommunicationCaptureMixes != null && voiceCommunicationCaptureMixes.size() > 0) { if (!callerHasPermission( - android.Manifest.permission.CAPTURE_VOICE_COMMUNICATION_OUTPUT)) { + Manifest.permission.CAPTURE_VOICE_COMMUNICATION_OUTPUT)) { Log.e(TAG, "Audio capture for voice communication requires " + "CAPTURE_VOICE_COMMUNICATION_OUTPUT system permission"); return false; @@ -12422,13 +12383,12 @@ public class AudioService extends IAudioService.Stub } if (requireModifyRouting - && !callerHasPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)) { + && !callerHasPermission(MODIFY_AUDIO_ROUTING)) { Log.e(TAG, "Can not capture audio without MODIFY_AUDIO_ROUTING"); return false; } - if (requireCallAudioInterception - && !callerHasPermission(android.Manifest.permission.CALL_AUDIO_INTERCEPTION)) { + if (requireCallAudioInterception && !callerHasPermission(CALL_AUDIO_INTERCEPTION)) { Log.e(TAG, "Can not capture audio without CALL_AUDIO_INTERCEPTION"); return false; } @@ -12541,7 +12501,7 @@ public class AudioService extends IAudioService.Stub // permission check final boolean hasPermissionForPolicy = (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission( - android.Manifest.permission.MODIFY_AUDIO_ROUTING)); + MODIFY_AUDIO_ROUTING)); if (!hasPermissionForPolicy) { Slog.w(TAG, errorMsg + " for pid " + + Binder.getCallingPid() + " / uid " @@ -12625,7 +12585,7 @@ public class AudioService extends IAudioService.Stub * @return {@link AudioManager#SUCCESS} iff the mixing rules were updated successfully, * {@link AudioManager#ERROR} otherwise. */ - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + @android.annotation.EnforcePermission(MODIFY_AUDIO_ROUTING) public int updateMixingRulesForPolicy( @NonNull AudioMix[] mixesToUpdate, @NonNull AudioMixingRule[] updatedMixingRules, @@ -12753,7 +12713,7 @@ public class AudioService extends IAudioService.Stub return AudioManager.SUCCESS; } - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + @android.annotation.EnforcePermission(MODIFY_AUDIO_ROUTING) /** @see AudioPolicy#getFocusStack() */ public List<AudioFocusInfo> getFocusStack() { super.getFocusStack_enforcePermission(); @@ -12779,8 +12739,7 @@ public class AudioService extends IAudioService.Stub /** * see {@link AudioPolicy#setFadeManagerConfigurationForFocusLoss(FadeManagerConfiguration)} */ - @android.annotation.EnforcePermission( - android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) + @android.annotation.EnforcePermission(MODIFY_AUDIO_SETTINGS_PRIVILEGED) public int setFadeManagerConfigurationForFocusLoss( @NonNull FadeManagerConfiguration fmcForFocusLoss) { super.setFadeManagerConfigurationForFocusLoss_enforcePermission(); @@ -12796,8 +12755,7 @@ public class AudioService extends IAudioService.Stub /** * see {@link AudioPolicy#clearFadeManagerConfigurationForFocusLoss()} */ - @android.annotation.EnforcePermission( - android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) + @android.annotation.EnforcePermission(MODIFY_AUDIO_SETTINGS_PRIVILEGED) public int clearFadeManagerConfigurationForFocusLoss() { super.clearFadeManagerConfigurationForFocusLoss_enforcePermission(); ensureFadeManagerConfigIsEnabled(); @@ -12808,8 +12766,7 @@ public class AudioService extends IAudioService.Stub /** * see {@link AudioPolicy#getFadeManagerConfigurationForFocusLoss()} */ - @android.annotation.EnforcePermission( - android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) + @android.annotation.EnforcePermission(MODIFY_AUDIO_SETTINGS_PRIVILEGED) public FadeManagerConfiguration getFadeManagerConfigurationForFocusLoss() { super.getFadeManagerConfigurationForFocusLoss_enforcePermission(); ensureFadeManagerConfigIsEnabled(); @@ -12970,7 +12927,7 @@ public class AudioService extends IAudioService.Stub /** @see AudioManager#supportsBluetoothVariableLatency() */ - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + @android.annotation.EnforcePermission(MODIFY_AUDIO_ROUTING) public boolean supportsBluetoothVariableLatency() { super.supportsBluetoothVariableLatency_enforcePermission(); try (SafeCloseable ignored = ClearCallingIdentityContext.create()) { @@ -12979,7 +12936,7 @@ public class AudioService extends IAudioService.Stub } /** @see AudioManager#setBluetoothVariableLatencyEnabled(boolean) */ - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + @android.annotation.EnforcePermission(MODIFY_AUDIO_ROUTING) public void setBluetoothVariableLatencyEnabled(boolean enabled) { super.setBluetoothVariableLatencyEnabled_enforcePermission(); try (SafeCloseable ignored = ClearCallingIdentityContext.create()) { @@ -12988,7 +12945,7 @@ public class AudioService extends IAudioService.Stub } /** @see AudioManager#isBluetoothVariableLatencyEnabled(boolean) */ - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + @android.annotation.EnforcePermission(MODIFY_AUDIO_ROUTING) public boolean isBluetoothVariableLatencyEnabled() { super.isBluetoothVariableLatencyEnabled_enforcePermission(); try (SafeCloseable ignored = ClearCallingIdentityContext.create()) { @@ -13075,7 +13032,7 @@ public class AudioService extends IAudioService.Stub public void registerRecordingCallback(IRecordingConfigDispatcher rcdb) { final boolean isPrivileged = (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission( - android.Manifest.permission.MODIFY_AUDIO_ROUTING)); + MODIFY_AUDIO_ROUTING)); mRecordMonitor.registerRecordingCallback(rcdb, isPrivileged); } @@ -13086,7 +13043,7 @@ public class AudioService extends IAudioService.Stub public List<AudioRecordingConfiguration> getActiveRecordingConfigurations() { final boolean isPrivileged = Binder.getCallingUid() == Process.SYSTEM_UID || (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission( - android.Manifest.permission.MODIFY_AUDIO_ROUTING)); + MODIFY_AUDIO_ROUTING)); return mRecordMonitor.getActiveRecordingConfigurations(isPrivileged); } @@ -13122,7 +13079,7 @@ public class AudioService extends IAudioService.Stub public void registerPlaybackCallback(IPlaybackConfigDispatcher pcdb) { final boolean isPrivileged = (PackageManager.PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission( - android.Manifest.permission.MODIFY_AUDIO_ROUTING)); + MODIFY_AUDIO_ROUTING)); mPlaybackMonitor.registerPlaybackCallback(pcdb, isPrivileged); } @@ -13133,7 +13090,7 @@ public class AudioService extends IAudioService.Stub public List<AudioPlaybackConfiguration> getActivePlaybackConfigurations() { final boolean isPrivileged = (PackageManager.PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission( - android.Manifest.permission.MODIFY_AUDIO_ROUTING)); + MODIFY_AUDIO_ROUTING)); return mPlaybackMonitor.getActivePlaybackConfigurations(isPrivileged); } @@ -13724,8 +13681,7 @@ public class AudioService extends IAudioService.Stub * see {@link AudioManager#dispatchAudioFocusChangeWithFade(AudioFocusInfo, int, AudioPolicy, * List, FadeManagerConfiguration)} */ - @android.annotation.EnforcePermission( - android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) + @android.annotation.EnforcePermission(MODIFY_AUDIO_SETTINGS_PRIVILEGED) public int dispatchFocusChangeWithFade(AudioFocusInfo afi, int focusChange, IAudioPolicyCallback pcb, List<AudioFocusInfo> otherActiveAfis, FadeManagerConfiguration transientFadeMgrConfig) { @@ -13762,8 +13718,7 @@ public class AudioService extends IAudioService.Stub /** * @see AudioManager#shouldNotificationSoundPlay(AudioAttributes) */ - @android.annotation.EnforcePermission( - android.Manifest.permission.QUERY_AUDIO_STATE) + @android.annotation.EnforcePermission(QUERY_AUDIO_STATE) public boolean shouldNotificationSoundPlay(@NonNull final AudioAttributes aa) { super.shouldNotificationSoundPlay_enforcePermission(); Objects.requireNonNull(aa); @@ -13823,12 +13778,10 @@ public class AudioService extends IAudioService.Stub new HashMap<IBinder, AsdProxy>(); private void checkMonitorAudioServerStatePermission() { - if (!(mContext.checkCallingOrSelfPermission( - android.Manifest.permission.MODIFY_PHONE_STATE) == - PackageManager.PERMISSION_GRANTED || - mContext.checkCallingOrSelfPermission( - android.Manifest.permission.MODIFY_AUDIO_ROUTING) == - PackageManager.PERMISSION_GRANTED)) { + if (!(mContext.checkCallingOrSelfPermission(MODIFY_PHONE_STATE) + == PackageManager.PERMISSION_GRANTED + || mContext.checkCallingOrSelfPermission(MODIFY_AUDIO_ROUTING) + == PackageManager.PERMISSION_GRANTED)) { throw new SecurityException("Not allowed to monitor audioserver state"); } } @@ -13923,7 +13876,7 @@ public class AudioService extends IAudioService.Stub AudioSystem.setAudioHalPids(pidsArray); } - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + @android.annotation.EnforcePermission(MODIFY_AUDIO_ROUTING) //====================== // Multi Audio Focus //====================== @@ -13964,7 +13917,7 @@ public class AudioService extends IAudioService.Stub * or the delay is not in range of {@link #getMaxAdditionalOutputDeviceDelay()}. */ @Override - //@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + //@RequiresPermission(MODIFY_AUDIO_ROUTING) public boolean setAdditionalOutputDeviceDelay( @NonNull AudioDeviceAttributes device, @IntRange(from = 0) long delayMillis) { Objects.requireNonNull(device, "device must not be null"); @@ -14037,7 +13990,7 @@ public class AudioService extends IAudioService.Stub return delayMillis; } - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + @android.annotation.EnforcePermission(MODIFY_AUDIO_ROUTING) /** @see AudioManager#addAssistantServicesUids(int []) */ @Override public void addAssistantServicesUids(int [] assistantUids) { @@ -14050,7 +14003,7 @@ public class AudioService extends IAudioService.Stub } } - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + @android.annotation.EnforcePermission(MODIFY_AUDIO_ROUTING) /** @see AudioManager#removeAssistantServicesUids(int []) */ @Override public void removeAssistantServicesUids(int [] assistantUids) { @@ -14062,7 +14015,7 @@ public class AudioService extends IAudioService.Stub } } - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + @android.annotation.EnforcePermission(MODIFY_AUDIO_ROUTING) /** @see AudioManager#getAssistantServicesUids() */ @Override public int[] getAssistantServicesUids() { @@ -14075,7 +14028,7 @@ public class AudioService extends IAudioService.Stub return assistantUids; } - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + @android.annotation.EnforcePermission(MODIFY_AUDIO_ROUTING) /** @see AudioManager#setActiveAssistantServiceUids(int []) */ @Override public void setActiveAssistantServiceUids(int [] activeAssistantUids) { @@ -14088,7 +14041,7 @@ public class AudioService extends IAudioService.Stub updateActiveAssistantServiceUids(); } - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + @android.annotation.EnforcePermission(MODIFY_AUDIO_ROUTING) /** @see AudioManager#getActiveAssistantServiceUids() */ @Override public int[] getActiveAssistantServiceUids() { diff --git a/services/core/java/com/android/server/audio/SoundDoseHelper.java b/services/core/java/com/android/server/audio/SoundDoseHelper.java index 9610034caf01..e28ae952e65a 100644 --- a/services/core/java/com/android/server/audio/SoundDoseHelper.java +++ b/services/core/java/com/android/server/audio/SoundDoseHelper.java @@ -856,11 +856,12 @@ public class SoundDoseHelper { pw.println(); } - /*package*/void reset() { + /*package*/void reset(boolean resetISoundDose) { Log.d(TAG, "Reset the sound dose helper"); - mSoundDose.compareAndExchange(/*expectedValue=*/null, - AudioSystem.getSoundDoseInterface(mSoundDoseCallback)); + if (resetISoundDose) { + mSoundDose.set(AudioSystem.getSoundDoseInterface(mSoundDoseCallback)); + } synchronized (mCsdStateLock) { try { @@ -972,7 +973,7 @@ public class SoundDoseHelper { } } - reset(); + reset(/*resetISoundDose=*/false); } private void onConfigureSafeMedia(boolean force, String caller) { diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java index d876a381ca7a..3c3bdd5b69f6 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java @@ -269,8 +269,7 @@ public class HdmiCecMessageValidator { addValidationInfo(Constants.MESSAGE_REQUEST_SHORT_AUDIO_DESCRIPTOR, oneByteValidator, ADDR_NOT_UNREGISTERED, ADDR_DIRECT); addValidationInfo(Constants.MESSAGE_SET_SYSTEM_AUDIO_MODE, - new MinimumOneByteRangeValidator(0x00, 0x01), - ADDR_NOT_UNREGISTERED, ADDR_ALL); + new SingleByteRangeValidator(0x00, 0x01), ADDR_AUDIO_SYSTEM, ADDR_ALL); addValidationInfo(Constants.MESSAGE_SYSTEM_AUDIO_MODE_STATUS, new SingleByteRangeValidator(0x00, 0x01), ADDR_NOT_UNREGISTERED, ADDR_DIRECT); diff --git a/services/core/java/com/android/server/hdmi/HdmiUtils.java b/services/core/java/com/android/server/hdmi/HdmiUtils.java index 5646e1b9a9ef..0688fbf358ad 100644 --- a/services/core/java/com/android/server/hdmi/HdmiUtils.java +++ b/services/core/java/com/android/server/hdmi/HdmiUtils.java @@ -175,14 +175,15 @@ final class HdmiUtils { * * @param logicalAddress the logical address to verify * @param deviceType the device type to check - * @throws IllegalArgumentException */ - static void verifyAddressType(int logicalAddress, int deviceType) { + static boolean verifyAddressType(int logicalAddress, int deviceType) { List<Integer> actualDeviceTypes = getTypeFromAddress(logicalAddress); if (!actualDeviceTypes.contains(deviceType)) { - throw new IllegalArgumentException("Device type missmatch:[Expected:" + deviceType - + ", Actual:" + actualDeviceTypes); + Slog.w(TAG,"Device type mismatch:[Expected:" + deviceType + + ", Actual:" + actualDeviceTypes + "]"); + return false; } + return true; } /** diff --git a/services/core/java/com/android/server/hdmi/RequestArcAction.java b/services/core/java/com/android/server/hdmi/RequestArcAction.java index 54c8c00b8889..58e146ecaa78 100644 --- a/services/core/java/com/android/server/hdmi/RequestArcAction.java +++ b/services/core/java/com/android/server/hdmi/RequestArcAction.java @@ -19,6 +19,7 @@ package com.android.server.hdmi; import android.hardware.hdmi.HdmiControlManager; import android.hardware.hdmi.HdmiDeviceInfo; import android.hardware.hdmi.IHdmiControlCallback; +import android.util.Slog; /** * Base feature action class for <Request ARC Initiation>/<Request ARC Termination>. @@ -38,13 +39,14 @@ abstract class RequestArcAction extends HdmiCecFeatureAction { * @param source {@link HdmiCecLocalDevice} instance * @param avrAddress address of AV receiver. It should be AUDIO_SYSTEM type * @param callback callback to inform about the status of the action - * @throws IllegalArgumentException if device type of sourceAddress and avrAddress - * is invalid */ RequestArcAction(HdmiCecLocalDevice source, int avrAddress, IHdmiControlCallback callback) { super(source, callback); - HdmiUtils.verifyAddressType(getSourceAddress(), HdmiDeviceInfo.DEVICE_TV); - HdmiUtils.verifyAddressType(avrAddress, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); + if (!HdmiUtils.verifyAddressType(getSourceAddress(), HdmiDeviceInfo.DEVICE_TV) || + !HdmiUtils.verifyAddressType(avrAddress, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM)) { + Slog.w(TAG, "Device type mismatch, stop the action."); + finish(); + } mAvrAddress = avrAddress; } diff --git a/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java b/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java index 32e274ece9ab..5ab22e1dcd61 100644 --- a/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java +++ b/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java @@ -47,8 +47,11 @@ final class SetArcTransmissionStateAction extends HdmiCecFeatureAction { SetArcTransmissionStateAction(HdmiCecLocalDevice source, int avrAddress, boolean enabled) { super(source); - HdmiUtils.verifyAddressType(getSourceAddress(), HdmiDeviceInfo.DEVICE_TV); - HdmiUtils.verifyAddressType(avrAddress, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); + if (!HdmiUtils.verifyAddressType(getSourceAddress(), HdmiDeviceInfo.DEVICE_TV) || + !HdmiUtils.verifyAddressType(avrAddress, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM)) { + Slog.w(TAG, "Device type mismatch, stop the action."); + finish(); + } mAvrAddress = avrAddress; mEnabled = enabled; } diff --git a/services/core/java/com/android/server/hdmi/SystemAudioAction.java b/services/core/java/com/android/server/hdmi/SystemAudioAction.java index e96963b9ae3f..f14cda1e6509 100644 --- a/services/core/java/com/android/server/hdmi/SystemAudioAction.java +++ b/services/core/java/com/android/server/hdmi/SystemAudioAction.java @@ -20,6 +20,7 @@ import android.hardware.hdmi.HdmiControlManager; import android.hardware.hdmi.HdmiDeviceInfo; import android.hardware.hdmi.IHdmiControlCallback; import android.hardware.tv.cec.V1_0.SendMessageResult; +import android.util.Slog; import java.util.List; @@ -56,12 +57,14 @@ abstract class SystemAudioAction extends HdmiCecFeatureAction { * @param avrAddress logical address of AVR device * @param targetStatus Whether to enable the system audio mode or not * @param callback callback interface to be notified when it's done - * @throws IllegalArgumentException if device type of sourceAddress and avrAddress is invalid */ SystemAudioAction(HdmiCecLocalDevice source, int avrAddress, boolean targetStatus, IHdmiControlCallback callback) { super(source, callback); - HdmiUtils.verifyAddressType(avrAddress, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); + if (!HdmiUtils.verifyAddressType(avrAddress, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM)) { + Slog.w(TAG, "Device type mismatch, stop the action."); + finish(); + } mAvrLogicalAddress = avrAddress; mTargetAudioStatus = targetStatus; } diff --git a/services/core/java/com/android/server/hdmi/SystemAudioActionFromAvr.java b/services/core/java/com/android/server/hdmi/SystemAudioActionFromAvr.java index 99148c4ea114..08a938731dae 100644 --- a/services/core/java/com/android/server/hdmi/SystemAudioActionFromAvr.java +++ b/services/core/java/com/android/server/hdmi/SystemAudioActionFromAvr.java @@ -19,12 +19,14 @@ package com.android.server.hdmi; import android.hardware.hdmi.HdmiControlManager; import android.hardware.hdmi.HdmiDeviceInfo; import android.hardware.hdmi.IHdmiControlCallback; +import android.util.Slog; /** * Feature action that handles System Audio initiated by AVR devices. */ // Seq #33 final class SystemAudioActionFromAvr extends SystemAudioAction { + private static final String TAG = "SystemAudioActionFromAvr"; /** * Constructor * @@ -32,12 +34,14 @@ final class SystemAudioActionFromAvr extends SystemAudioAction { * @param avrAddress logical address of AVR device * @param targetStatus Whether to enable the system audio mode or not * @param callback callback interface to be notified when it's done - * @throws IllegalArgumentException if device type of tvAddress and avrAddress is invalid */ SystemAudioActionFromAvr(HdmiCecLocalDevice source, int avrAddress, boolean targetStatus, IHdmiControlCallback callback) { super(source, avrAddress, targetStatus, callback); - HdmiUtils.verifyAddressType(getSourceAddress(), HdmiDeviceInfo.DEVICE_TV); + if (!HdmiUtils.verifyAddressType(getSourceAddress(), HdmiDeviceInfo.DEVICE_TV)) { + Slog.w(TAG, "Device type mismatch, stop the action."); + finish(); + } } @Override diff --git a/services/core/java/com/android/server/hdmi/SystemAudioActionFromTv.java b/services/core/java/com/android/server/hdmi/SystemAudioActionFromTv.java index 5c0c272f59e0..675aa3171fbd 100644 --- a/services/core/java/com/android/server/hdmi/SystemAudioActionFromTv.java +++ b/services/core/java/com/android/server/hdmi/SystemAudioActionFromTv.java @@ -18,13 +18,14 @@ package com.android.server.hdmi; import android.hardware.hdmi.HdmiDeviceInfo; import android.hardware.hdmi.IHdmiControlCallback; +import android.util.Slog; /** * Feature action that handles System Audio initiated by TV devices. */ final class SystemAudioActionFromTv extends SystemAudioAction { - + private static final String TAG = "SystemAudioActionFromTv"; /** * Constructor * @@ -32,12 +33,14 @@ final class SystemAudioActionFromTv extends SystemAudioAction { * @param avrAddress logical address of AVR device * @param targetStatus Whether to enable the system audio mode or not * @param callback callback interface to be notified when it's done - * @throws IllegalArgumentException if device type of tvAddress is invalid */ SystemAudioActionFromTv(HdmiCecLocalDevice sourceAddress, int avrAddress, boolean targetStatus, IHdmiControlCallback callback) { super(sourceAddress, avrAddress, targetStatus, callback); - HdmiUtils.verifyAddressType(getSourceAddress(), HdmiDeviceInfo.DEVICE_TV); + if (!HdmiUtils.verifyAddressType(getSourceAddress(), HdmiDeviceInfo.DEVICE_TV)) { + Slog.w(TAG, "Device type mismatch, stop the action."); + finish(); + } } @Override diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 976399d3917a..5843d72f346a 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -4098,17 +4098,17 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. if (additionalSubtypeMap != newAdditionalSubtypeMap) { AdditionalSubtypeMapRepository.putAndSave(userId, newAdditionalSubtypeMap, settings.getMethodMap()); - final InputMethodSettings newSettings = queryInputMethodServicesInternal(mContext, - userId, AdditionalSubtypeMapRepository.get(userId), - DirectBootAwareness.AUTO); - InputMethodSettingsRepository.put(userId, newSettings); - if (isCurrentUser) { - final long ident = Binder.clearCallingIdentity(); - try { + final long ident = Binder.clearCallingIdentity(); + try { + final InputMethodSettings newSettings = queryInputMethodServicesInternal( + mContext, userId, AdditionalSubtypeMapRepository.get(userId), + DirectBootAwareness.AUTO); + InputMethodSettingsRepository.put(userId, newSettings); + if (isCurrentUser) { postInputMethodSettingUpdatedLocked(false /* resetDefaultEnabledIme */); - } finally { - Binder.restoreCallingIdentity(ident); } + } finally { + Binder.restoreCallingIdentity(ident); } } } @@ -4969,6 +4969,12 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. final int flags = PackageManager.GET_META_DATA | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS | directBootAwarenessFlags; + + // Beware that package visibility filtering will be enforced based on the effective calling + // identity (Binder.getCallingUid()), but our use case always expect Binder.getCallingUid() + // to return Process.SYSTEM_UID here. The actual filtering is implemented separately with + // canCallerAccessInputMethod(). + // TODO(b/343108534): Use PackageManagerInternal#queryIntentServices() to pass SYSTEM_UID. final List<ResolveInfo> services = userAwareContext.getPackageManager().queryIntentServices( new Intent(InputMethod.SERVICE_INTERFACE), PackageManager.ResolveInfoFlags.of(flags)); diff --git a/services/core/java/com/android/server/locales/LocaleManagerBackupHelper.java b/services/core/java/com/android/server/locales/LocaleManagerBackupHelper.java index d932bd4e6d20..563f93e96331 100644 --- a/services/core/java/com/android/server/locales/LocaleManagerBackupHelper.java +++ b/services/core/java/com/android/server/locales/LocaleManagerBackupHelper.java @@ -434,7 +434,7 @@ class LocaleManagerBackupHelper { ATTR_PACKAGE_NAME); String languageTags = parser.getAttributeValue(/* namespace= */ null, ATTR_LOCALES); boolean delegateSelector = parser.getAttributeBoolean(/* namespace= */ null, - ATTR_DELEGATE_SELECTOR); + ATTR_DELEGATE_SELECTOR, false); if (!TextUtils.isEmpty(packageName) && !TextUtils.isEmpty(languageTags)) { LocalesInfo localesInfo = new LocalesInfo(languageTags, delegateSelector); diff --git a/services/core/java/com/android/server/media/MediaRoute2Provider.java b/services/core/java/com/android/server/media/MediaRoute2Provider.java index 1bc2a5eb1351..363684f618cc 100644 --- a/services/core/java/com/android/server/media/MediaRoute2Provider.java +++ b/services/core/java/com/android/server/media/MediaRoute2Provider.java @@ -21,6 +21,7 @@ import android.annotation.Nullable; import android.content.ComponentName; import android.media.MediaRoute2Info; import android.media.MediaRoute2ProviderInfo; +import android.media.MediaRouter2; import android.media.RouteDiscoveryPreference; import android.media.RoutingSessionInfo; import android.os.Bundle; @@ -172,4 +173,59 @@ abstract class MediaRoute2Provider { @NonNull RoutingSessionInfo sessionInfo); void onRequestFailed(@NonNull MediaRoute2Provider provider, long requestId, int reason); } + + /** + * Holds session creation or transfer initiation information for a transfer in flight. + * + * <p>The initiator app is typically also the {@link RoutingSessionInfo#getClientPackageName() + * client app}, with the exception of the {@link MediaRouter2#getSystemController() system + * routing session} which is exceptional in that it's shared among all apps. + * + * <p>For the system routing session, the initiator app is the one that programmatically + * triggered the transfer (for example, via {@link MediaRouter2#transferTo}), or the target app + * of the proxy router that did the transfer. + * + * @see MediaRouter2.RoutingController#wasTransferInitiatedBySelf() + * @see RoutingSessionInfo#getTransferInitiatorPackageName() + * @see RoutingSessionInfo#getTransferInitiatorUserHandle() + */ + protected static class SessionCreationOrTransferRequest { + + /** + * The id of the request, or {@link + * android.media.MediaRoute2ProviderService#REQUEST_ID_NONE} if unknown. + */ + public final long mRequestId; + + /** The {@link MediaRoute2Info#getId() id} of the target route. */ + @NonNull public final String mTargetRouteId; + + @RoutingSessionInfo.TransferReason public final int mTransferReason; + + /** The {@link android.os.UserHandle} on which the initiator app is running. */ + @NonNull public final UserHandle mTransferInitiatorUserHandle; + + @NonNull public final String mTransferInitiatorPackageName; + + SessionCreationOrTransferRequest( + long requestId, + @NonNull String routeId, + @RoutingSessionInfo.TransferReason int transferReason, + @NonNull UserHandle transferInitiatorUserHandle, + @NonNull String transferInitiatorPackageName) { + mRequestId = requestId; + mTargetRouteId = routeId; + mTransferReason = transferReason; + mTransferInitiatorUserHandle = transferInitiatorUserHandle; + mTransferInitiatorPackageName = transferInitiatorPackageName; + } + + public boolean isTargetRoute(@Nullable MediaRoute2Info route2Info) { + return route2Info != null && mTargetRouteId.equals(route2Info.getId()); + } + + public boolean isTargetRouteIdInList(@NonNull List<String> routesList) { + return routesList.stream().anyMatch(mTargetRouteId::equals); + } + } } diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java index 6ce3ab4b2d65..76930a003e46 100644 --- a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java +++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java @@ -79,12 +79,15 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { new AudioManagerBroadcastReceiver(); private final Object mRequestLock = new Object(); + @GuardedBy("mRequestLock") - private volatile SessionCreationRequest mPendingSessionCreationRequest; + private volatile SessionCreationOrTransferRequest mPendingSessionCreationOrTransferRequest; private final Object mTransferLock = new Object(); + @GuardedBy("mTransferLock") - @Nullable private volatile SessionCreationRequest mPendingTransferRequest; + @Nullable + private volatile SessionCreationOrTransferRequest mPendingTransferRequest; SystemMediaRoute2Provider(Context context, UserHandle user, Looper looper) { super(COMPONENT_NAME); @@ -180,12 +183,14 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { synchronized (mRequestLock) { // Handle the previous request as a failure if exists. - if (mPendingSessionCreationRequest != null) { - mCallback.onRequestFailed(this, mPendingSessionCreationRequest.mRequestId, + if (mPendingSessionCreationOrTransferRequest != null) { + mCallback.onRequestFailed( + /* provider= */ this, + mPendingSessionCreationOrTransferRequest.mRequestId, MediaRoute2ProviderService.REASON_UNKNOWN_ERROR); } - mPendingSessionCreationRequest = - new SessionCreationRequest( + mPendingSessionCreationOrTransferRequest = + new SessionCreationOrTransferRequest( requestId, routeId, RoutingSessionInfo.TRANSFER_REASON_FALLBACK, @@ -247,7 +252,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { if (Flags.enableBuiltInSpeakerRouteSuitabilityStatuses()) { synchronized (mTransferLock) { mPendingTransferRequest = - new SessionCreationRequest( + new SessionCreationOrTransferRequest( requestId, routeId, transferReason, @@ -438,7 +443,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { boolean isTransferringToTheSelectedRoute = mPendingTransferRequest.isTargetRoute(selectedRoute); boolean canBePotentiallyTransferred = - mPendingTransferRequest.isInsideOfRoutesList(transferableRoutes); + mPendingTransferRequest.isTargetRouteIdInList(transferableRoutes); if (isTransferringToTheSelectedRoute) { transferReason = mPendingTransferRequest.mTransferReason; @@ -492,20 +497,20 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { @GuardedBy("mRequestLock") private void reportPendingSessionRequestResultLockedIfNeeded( RoutingSessionInfo newSessionInfo) { - if (mPendingSessionCreationRequest == null) { + if (mPendingSessionCreationOrTransferRequest == null) { // No pending request, nothing to report. return; } - long pendingRequestId = mPendingSessionCreationRequest.mRequestId; - if (TextUtils.equals(mSelectedRouteId, mPendingSessionCreationRequest.mRouteId)) { + long pendingRequestId = mPendingSessionCreationOrTransferRequest.mRequestId; + if (mPendingSessionCreationOrTransferRequest.mTargetRouteId.equals(mSelectedRouteId)) { if (DEBUG) { Slog.w( TAG, "Session creation success to route " - + mPendingSessionCreationRequest.mRouteId); + + mPendingSessionCreationOrTransferRequest.mTargetRouteId); } - mPendingSessionCreationRequest = null; + mPendingSessionCreationOrTransferRequest = null; mCallback.onSessionCreated(this, pendingRequestId, newSessionInfo); } else { boolean isRequestedRouteConnectedBtRoute = isRequestedRouteConnectedBtRoute(); @@ -515,16 +520,16 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { Slog.w( TAG, "Session creation failed to route " - + mPendingSessionCreationRequest.mRouteId); + + mPendingSessionCreationOrTransferRequest.mTargetRouteId); } - mPendingSessionCreationRequest = null; + mPendingSessionCreationOrTransferRequest = null; mCallback.onRequestFailed( this, pendingRequestId, MediaRoute2ProviderService.REASON_UNKNOWN_ERROR); } else if (DEBUG) { Slog.w( TAG, "Session creation waiting state to route " - + mPendingSessionCreationRequest.mRouteId); + + mPendingSessionCreationOrTransferRequest.mTargetRouteId); } } } @@ -535,7 +540,8 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { // where two BT routes are active so the transferable routes list is empty. // See b/307723189 for context for (MediaRoute2Info btRoute : mBluetoothRouteController.getAllBluetoothRoutes()) { - if (TextUtils.equals(btRoute.getId(), mPendingSessionCreationRequest.mRouteId)) { + if (TextUtils.equals( + btRoute.getId(), mPendingSessionCreationOrTransferRequest.mTargetRouteId)) { return true; } } @@ -585,51 +591,6 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { mBluetoothRouteController.getClass().getSimpleName()); } - private static class SessionCreationRequest { - private final long mRequestId; - @NonNull private final String mRouteId; - - @RoutingSessionInfo.TransferReason private final int mTransferReason; - - @NonNull private final UserHandle mTransferInitiatorUserHandle; - @NonNull private final String mTransferInitiatorPackageName; - - SessionCreationRequest( - long requestId, - @NonNull String routeId, - @RoutingSessionInfo.TransferReason int transferReason, - @NonNull UserHandle transferInitiatorUserHandle, - @NonNull String transferInitiatorPackageName) { - mRequestId = requestId; - mRouteId = routeId; - mTransferReason = transferReason; - mTransferInitiatorUserHandle = transferInitiatorUserHandle; - mTransferInitiatorPackageName = transferInitiatorPackageName; - } - - private boolean isTargetRoute(@Nullable MediaRoute2Info route2Info) { - if (route2Info == null) { - return false; - } - - return isTargetRoute(route2Info.getId()); - } - - private boolean isTargetRoute(@Nullable String routeId) { - return mRouteId.equals(routeId); - } - - private boolean isInsideOfRoutesList(@NonNull List<String> routesList) { - for (String routeId : routesList) { - if (isTargetRoute(routeId)) { - return true; - } - } - - return false; - } - } - void updateVolume() { int devices = mAudioManager.getDevicesForStream(AudioManager.STREAM_MUSIC); int volume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC); diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 57f6d2789dc5..a90473865ce5 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -5153,6 +5153,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } // Okay to proceed synchronized (mLock) { + assertCallerIsOwnerOrRoot(); + assertPreparedAndNotSealedLocked("setPreVerifiedDomains"); mPreVerifiedDomains = preVerifiedDomains; } } diff --git a/services/core/java/com/android/server/wm/AbsAppSnapshotController.java b/services/core/java/com/android/server/wm/AbsAppSnapshotController.java index fd4b06148c5f..0e0b78fb3206 100644 --- a/services/core/java/com/android/server/wm/AbsAppSnapshotController.java +++ b/services/core/java/com/android/server/wm/AbsAppSnapshotController.java @@ -466,17 +466,17 @@ abstract class AbsAppSnapshotController<TYPE extends WindowContainer, } /** - * @return The {@link WindowInsetsController.Appearance} flags for the top fullscreen opaque - * window in the given {@param TYPE}. + * @return The {@link WindowInsetsController.Appearance} flags for the top main app window in + * the given {@param TYPE}. */ @WindowInsetsController.Appearance private int getAppearance(TYPE source) { final ActivityRecord topFullscreenActivity = getTopFullscreenActivity(source); - final WindowState topFullscreenOpaqueWindow = topFullscreenActivity != null - ? topFullscreenActivity.getTopFullscreenOpaqueWindow() + final WindowState topFullscreenWindow = topFullscreenActivity != null + ? topFullscreenActivity.findMainWindow() : null; - if (topFullscreenOpaqueWindow != null) { - return topFullscreenOpaqueWindow.mAttrs.insetsFlags.appearance; + if (topFullscreenWindow != null) { + return topFullscreenWindow.mAttrs.insetsFlags.appearance; } return 0; } diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index eb6262c95d84..434e92f7978a 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -7660,20 +7660,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } } - /** - * @return The to top most child window for which {@link LayoutParams#isFullscreen()} returns - * true and isn't fully transparent. - */ - WindowState getTopFullscreenOpaqueWindow() { - for (int i = mChildren.size() - 1; i >= 0; i--) { - final WindowState win = mChildren.get(i); - if (win != null && win.mAttrs.isFullscreen() && !win.isFullyTransparent()) { - return win; - } - } - return null; - } - WindowState findMainWindow() { return findMainWindow(true); } diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java index 0e4f0335118d..f91ef1d41a0c 100644 --- a/services/core/java/com/android/server/wm/BackNavigationController.java +++ b/services/core/java/com/android/server/wm/BackNavigationController.java @@ -1099,10 +1099,6 @@ class BackNavigationController { } void finishPresentAnimations() { - if (!mComposed) { - return; - } - if (mCloseAdaptor != null) { mCloseAdaptor.mTarget.cancelAnimation(); mCloseAdaptor = null; @@ -1131,8 +1127,10 @@ class BackNavigationController { } void clearBackAnimateTarget() { - finishPresentAnimations(); - mComposed = false; + if (mComposed) { + mComposed = false; + finishPresentAnimations(); + } mWaitTransition = false; mStartingSurfaceTargetMatch = false; mSwitchType = UNKNOWN; @@ -1270,6 +1268,8 @@ class BackNavigationController { .setContainerLayer() .setHidden(false) .setParent(task.getSurfaceControl()) + .setCallsite( + "BackWindowAnimationAdaptorWrapper.getOrCreateAnimationTarget") .build(); mCloseTransaction = new SurfaceControl.Transaction(); mCloseTransaction.reparent(leashSurface, null); diff --git a/services/core/java/com/android/server/wm/InputManagerCallback.java b/services/core/java/com/android/server/wm/InputManagerCallback.java index 22ca82a29d59..1e7de2be87fa 100644 --- a/services/core/java/com/android/server/wm/InputManagerCallback.java +++ b/services/core/java/com/android/server/wm/InputManagerCallback.java @@ -286,6 +286,7 @@ final class InputManagerCallback implements InputManagerService.WindowManagerCal .setName(name) .setCallsite("createSurfaceForGestureMonitor") .setParent(inputOverlay) + .setCallsite("InputManagerCallback.createSurfaceForGestureMonitor") .build(); } } diff --git a/services/core/java/com/android/server/wm/StartingSurfaceController.java b/services/core/java/com/android/server/wm/StartingSurfaceController.java index 05eeeb381d8a..cff40c768381 100644 --- a/services/core/java/com/android/server/wm/StartingSurfaceController.java +++ b/services/core/java/com/android/server/wm/StartingSurfaceController.java @@ -140,23 +140,15 @@ public class StartingSurfaceController { } StartingSurface createTaskSnapshotSurface(ActivityRecord activity, TaskSnapshot taskSnapshot) { - final WindowState topFullscreenOpaqueWindow; final Task task = activity.getTask(); if (task == null) { Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find task for activity=" + activity); return null; } - final ActivityRecord topFullscreenActivity = task.getTopFullscreenActivity(); - if (topFullscreenActivity == null) { - Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find top fullscreen for task=" - + task); - return null; - } - topFullscreenOpaqueWindow = topFullscreenActivity.getTopFullscreenOpaqueWindow(); - if (topFullscreenOpaqueWindow == null) { - Slog.w(TAG, "TaskSnapshotSurface.create: no opaque window in " - + topFullscreenActivity); + final WindowState mainWindow = activity.findMainWindow(false); + if (mainWindow == null) { + Slog.w(TAG, "TaskSnapshotSurface.create: no main window in " + activity); return null; } if (activity.mDisplayContent.getRotation() != taskSnapshot.getRotation()) { diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index a555388ab233..9dc9ad4a2ba2 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -3624,14 +3624,15 @@ class Task extends TaskFragment { // If the developer has persist a different configuration, we need to override it to the // starting window because persisted configuration does not effect to Task. info.taskInfo.configuration.setTo(activity.getConfiguration()); - final ActivityRecord topFullscreenActivity = getTopFullscreenActivity(); - if (topFullscreenActivity != null) { - final WindowState topFullscreenOpaqueWindow = - topFullscreenActivity.getTopFullscreenOpaqueWindow(); - if (topFullscreenOpaqueWindow != null) { - info.topOpaqueWindowInsetsState = - topFullscreenOpaqueWindow.getInsetsStateWithVisibilityOverride(); - info.topOpaqueWindowLayoutParams = topFullscreenOpaqueWindow.getAttrs(); + if (!Flags.drawSnapshotAspectRatioMatch()) { + final ActivityRecord topFullscreenActivity = getTopFullscreenActivity(); + if (topFullscreenActivity != null) { + final WindowState mainWindow = topFullscreenActivity.findMainWindow(false); + if (mainWindow != null) { + info.topOpaqueWindowInsetsState = + mainWindow.getInsetsStateWithVisibilityOverride(); + info.topOpaqueWindowLayoutParams = mainWindow.getAttrs(); + } } } return info; @@ -6879,7 +6880,7 @@ class Task extends TaskFragment { private void assignLayer(@NonNull SurfaceControl.Transaction t, int layer) { t.setLayer(mContainerSurface, layer); - t.setVisibility(mContainerSurface, mOwnerTaskFragment.isVisible()); + t.setVisibility(mContainerSurface, mOwnerTaskFragment.isVisible() || mIsBoosted); for (int i = 0; i < mPendingClientTransactions.size(); i++) { t.merge(mPendingClientTransactions.get(i)); } diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index 7ec31d5a8ecb..d8e4aa25dd77 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -236,6 +236,8 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { @VisibleForTesting ArrayList<Runnable> mTransactionCompletedListeners = null; + private ArrayList<Runnable> mTransitionEndedListeners = null; + /** Custom activity-level animation options and callbacks. */ private TransitionInfo.AnimationOptions mOverrideOptions; private IRemoteCallback mClientAnimationStartCallback = null; @@ -1473,6 +1475,18 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { mController.mSnapshotController.onTransitionFinish(mType, mTargets); // Resume snapshot persist thread after snapshot controller analysis this transition. mController.updateAnimatingState(); + + invokeTransitionEndedListeners(); + } + + private void invokeTransitionEndedListeners() { + if (mTransitionEndedListeners == null) { + return; + } + for (int i = 0; i < mTransitionEndedListeners.size(); i++) { + mTransitionEndedListeners.get(i).run(); + } + mTransitionEndedListeners = null; } private void commitConfigAtEndActivities() { @@ -1584,6 +1598,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { // Syncengine abort will call through to onTransactionReady() mSyncEngine.abort(mSyncId); mController.dispatchLegacyAppTransitionCancelled(); + invokeTransitionEndedListeners(); } /** Immediately moves this to playing even if it isn't started yet. */ @@ -1902,6 +1917,20 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { } /** + * Adds a listener that will be executed after the transition is finished or aborted. + */ + void addTransitionEndedListener(Runnable listener) { + if (mState != STATE_COLLECTING && mState != STATE_STARTED) { + throw new IllegalStateException( + "Can't register listeners if the transition isn't collecting. state=" + mState); + } + if (mTransitionEndedListeners == null) { + mTransitionEndedListeners = new ArrayList<>(); + } + mTransitionEndedListeners.add(listener); + } + + /** * Checks if the transition contains order changes. * * This is a shallow check that doesn't account for collection in parallel, unlike @@ -2639,7 +2668,8 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { } } final SurfaceControl rootLeash = leashReference.makeAnimationLeash().setName( - "Transition Root: " + leashReference.getName()).build(); + "Transition Root: " + leashReference.getName()) + .setCallsite("Transition.calculateTransitionRoots").build(); rootLeash.setUnreleasedWarningCallSite("Transition.calculateTransitionRoots"); // Update layers to start transaction because we prevent assignment during collect, so // the layer of transition root can be correct. diff --git a/services/core/java/com/android/server/wm/TrustedOverlayHost.java b/services/core/java/com/android/server/wm/TrustedOverlayHost.java index debe7946dc95..9b868bebd868 100644 --- a/services/core/java/com/android/server/wm/TrustedOverlayHost.java +++ b/services/core/java/com/android/server/wm/TrustedOverlayHost.java @@ -54,6 +54,7 @@ class TrustedOverlayHost { final SurfaceControl.Builder b = mWmService.makeSurfaceBuilder(null) .setContainerLayer() .setHidden(true) + .setCallsite("TrustedOverlayHost.requireOverlaySurfaceControl") .setName("Overlay Host Leash"); mSurfaceControl = b.build(); diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index 5e932d45f3b6..6221d9656962 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -1613,6 +1613,10 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub } case OP_TYPE_SET_DECOR_SURFACE_BOOSTED: { if (Flags.activityEmbeddingInteractiveDividerFlag()) { + final Task task = taskFragment.getTask(); + if (task == null) { + break; + } final SurfaceControl.Transaction clientTransaction = operation.getSurfaceTransaction(); if (clientTransaction != null) { @@ -1621,10 +1625,22 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub // any invalid operations. clientTransaction.sanitize(caller.mPid, caller.mUid); } - taskFragment.getTask().setDecorSurfaceBoosted( - taskFragment, - operation.getBooleanValue() /* isBoosted */, - clientTransaction); + + if (transition != null) { + // The decor surface boost/unboost must happen after the transition is + // completed. Otherwise, the decor surface could be moved before Shell + // completes the transition, causing flicker. + transition.addTransitionEndedListener(() -> + task.setDecorSurfaceBoosted( + taskFragment, + operation.getBooleanValue() /* isBoosted */, + clientTransaction)); + } else { + task.setDecorSurfaceBoosted( + taskFragment, + operation.getBooleanValue() /* isBoosted */, + clientTransaction); + } } break; } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 90c287c056e8..6953c60d0d74 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -188,6 +188,7 @@ import android.annotation.Nullable; import android.app.ActivityTaskManager; import android.app.AppOpsManager; import android.app.admin.DevicePolicyCache; +import android.app.servertransaction.WindowStateInsetsControlChangeItem; import android.app.servertransaction.WindowStateResizeItem; import android.content.Context; import android.content.res.Configuration; @@ -3818,11 +3819,17 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } final InsetsStateController stateController = getDisplayContent().getInsetsStateController(); + final InsetsState insetsState = getCompatInsetsState(); mLastReportedActiveControls.set(stateController.getControlsForDispatch(this)); - try { - mClient.insetsControlChanged(getCompatInsetsState(), mLastReportedActiveControls); - } catch (RemoteException e) { - Slog.w(TAG, "Failed to deliver inset control state change to w=" + this, e); + if (Flags.insetsControlChangedItem()) { + getProcess().scheduleClientTransactionItem(WindowStateInsetsControlChangeItem.obtain( + mClient, insetsState, mLastReportedActiveControls)); + } else { + try { + mClient.insetsControlChanged(insetsState, mLastReportedActiveControls); + } catch (RemoteException e) { + Slog.w(TAG, "Failed to deliver inset control state change to w=" + this, e); + } } } diff --git a/services/tests/mockingservicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java b/services/tests/mockingservicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java index ad68de84eace..9d8d520fcb53 100644 --- a/services/tests/mockingservicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java @@ -15,6 +15,8 @@ */ package com.android.server.power.batterysaver; +import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.NULL_DEFAULT; + import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.inOrder; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; @@ -35,12 +37,14 @@ import android.content.ContentResolver; import android.content.Context; import android.content.res.Resources; import android.os.PowerManager; +import android.platform.test.flag.junit.SetFlagsRule; import android.provider.Settings.Global; +import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InOrder; @@ -65,6 +69,9 @@ public class BatterySaverStateMachineTest { private DevicePersistedState mPersistedState; + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(NULL_DEFAULT); + private class DevicePersistedState { // Current battery level. public int batteryLevel = 100; @@ -171,6 +178,11 @@ public class BatterySaverStateMachineTest { void triggerDynamicModeNotification() { // Do nothing } + + @Override + void triggerDynamicModeNotificationV2() { + // Do nothing + } } @Before diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java index f971f0e6d4fb..4e8c75559f3b 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java @@ -923,6 +923,8 @@ public class AccessibilityManagerServiceTest { ResolveInfo resolveInfo1 = installedService1.getResolveInfo(); AccessibilityServiceInfo installedService2 = mA11yms.getCurrentUserState().mInstalledServices.getLast(); + // Invokes client change to trigger onUserStateChanged. + mA11yms.onClientChangeLocked(false); // Disables `installedService2` when(mMockPackageManager.queryIntentServicesAsUser(any(), anyInt(), anyInt())) diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java index 98e119cf0dad..473d1dc22d7a 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java @@ -139,12 +139,13 @@ public class HdmiCecMessageValidatorTest { @Test public void isValid_setSystemAudioMode() { - assertMessageValidity("40:72:00").isEqualTo(OK); - assertMessageValidity("4F:72:01:03").isEqualTo(OK); + assertMessageValidity("50:72:00").isEqualTo(OK); + assertMessageValidity("50:72:01").isEqualTo(OK); + assertMessageValidity("5F:72:01:03").isEqualTo(ERROR_PARAMETER_LONG); - assertMessageValidity("F0:72").isEqualTo(ERROR_SOURCE); - assertMessageValidity("40:72").isEqualTo(ERROR_PARAMETER_SHORT); - assertMessageValidity("40:72:02").isEqualTo(ERROR_PARAMETER); + assertMessageValidity("40:72:00").isEqualTo(ERROR_SOURCE); + assertMessageValidity("50:72").isEqualTo(ERROR_PARAMETER_SHORT); + assertMessageValidity("50:72:02").isEqualTo(ERROR_PARAMETER); } @Test diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiUtilsTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiUtilsTest.java index c89c32a03553..74583dd619c7 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiUtilsTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiUtilsTest.java @@ -709,4 +709,18 @@ public class HdmiUtilsTest { assertThat(HdmiUtils.buildMessage("40:32:65:6E:67").getParams()).isEqualTo( new byte[]{0x65, 0x6E, 0x67}); } + + @Test + public void testVerifyAddressType() { + assertTrue(HdmiUtils.verifyAddressType(Constants.ADDR_TV, + HdmiDeviceInfo.DEVICE_TV)); + assertTrue(HdmiUtils.verifyAddressType(Constants.ADDR_AUDIO_SYSTEM, + HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM)); + assertTrue(HdmiUtils.verifyAddressType(Constants.ADDR_PLAYBACK_1, + HdmiDeviceInfo.DEVICE_PLAYBACK)); + assertFalse(HdmiUtils.verifyAddressType(Constants.ADDR_SPECIFIC_USE, + HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM)); + assertFalse(HdmiUtils.verifyAddressType(Constants.ADDR_PLAYBACK_2, + HdmiDeviceInfo.DEVICE_VIDEO_PROCESSOR)); + } } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index 70319754253b..4a9760bc3317 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -2057,7 +2057,7 @@ public class ActivityRecordTests extends WindowTestsBase { final ActivityRecord activity = createActivityWithTask(); // TaskSnapshotSurface requires a fullscreen opaque window. final WindowManager.LayoutParams params = new WindowManager.LayoutParams( - WindowManager.LayoutParams.TYPE_APPLICATION_STARTING); + TYPE_BASE_APPLICATION); params.width = params.height = WindowManager.LayoutParams.MATCH_PARENT; final TestWindowState w = new TestWindowState( mAtm.mWindowManager, getTestSession(), new TestIWindow(), params, activity); @@ -2504,25 +2504,6 @@ public class ActivityRecordTests extends WindowTestsBase { activity.removeImmediately(); } - @Test - @Presubmit - public void testGetTopFullscreenOpaqueWindow() { - final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build(); - assertNull(activity.getTopFullscreenOpaqueWindow()); - - final WindowState window1 = createWindow(null, TYPE_BASE_APPLICATION, activity, "window1"); - final WindowState window11 = createWindow(null, TYPE_APPLICATION, activity, "window11"); - final WindowState window12 = createWindow(null, TYPE_APPLICATION, activity, "window12"); - assertEquals(window12, activity.getTopFullscreenOpaqueWindow()); - window12.mAttrs.width = 500; - assertEquals(window11, activity.getTopFullscreenOpaqueWindow()); - window11.mAttrs.width = 500; - assertEquals(window1, activity.getTopFullscreenOpaqueWindow()); - window1.mAttrs.alpha = 0f; - assertNull(activity.getTopFullscreenOpaqueWindow()); - activity.removeImmediately(); - } - @SetupWindows(addWindows = W_ACTIVITY) @Test public void testLandscapeSeascapeRotationByApp() { diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java index 698afaa8e8ab..69f2d684fd77 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java @@ -1446,6 +1446,33 @@ public class TransitionTests extends WindowTestsBase { } @Test + public void testTransitionEndedListeners() { + final TransitionController controller = new TestTransitionController(mAtm); + controller.setSyncEngine(mWm.mSyncEngine); + final ITransitionPlayer player = new ITransitionPlayer.Default(); + controller.registerTransitionPlayer(player, null /* playerProc */); + final Runnable transitionEndedListener = mock(Runnable.class); + + final Transition transition1 = controller.createTransition(TRANSIT_OPEN); + transition1.addTransitionEndedListener(transitionEndedListener); + + // Using abort to force-finish the sync (since we can't wait for drawing in unit test). + // We didn't call abort on the transition itself, so it will still run onTransactionReady + // normally. + mWm.mSyncEngine.abort(transition1.getSyncId()); + transition1.finishTransition(); + + verify(transitionEndedListener).run(); + + clearInvocations(transitionEndedListener); + + final Transition transition2 = controller.createTransition(TRANSIT_OPEN); + transition2.addTransitionEndedListener(transitionEndedListener); + transition2.abort(); + verify(transitionEndedListener).run(); + } + + @Test public void testTransientLaunch() { spyOn(mWm.mSnapshotController.mTaskSnapshotController); final ArrayList<ActivityRecord> enteringAnimReports = new ArrayList<>(); |