Merge "Check that modespecs are not null" into main
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index b42f7bc..e857175 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,6 +1,7 @@
[Builtin Hooks]
clang_format = true
bpfmt = true
+ktfmt = true
[Builtin Hooks Options]
# Only turn on clang-format check for the following subfolders.
@@ -17,6 +18,7 @@
tests/
tools/
bpfmt = -d
+ktfmt = --kotlinlang-style --include-dirs=services/permission,packages/SystemUI
[Hook Scripts]
checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT}
@@ -25,9 +27,10 @@
hidden_api_txt_exclude_hook = ${REPO_ROOT}/frameworks/base/tools/hiddenapi/exclude.sh ${PREUPLOAD_COMMIT} ${REPO_ROOT}
-ktfmt_hook = ${REPO_ROOT}/external/ktfmt/ktfmt.py --check -i ${REPO_ROOT}/frameworks/base/ktfmt_includes.txt ${PREUPLOAD_FILES}
-
ktlint_hook = ${REPO_ROOT}/prebuilts/ktlint/ktlint.py --no-verify-format -f ${PREUPLOAD_FILES}
# This flag check hook runs only for "packages/SystemUI" subdirectory. If you want to include this check for other subdirectories, please modify flag_check.py.
flag_hook = ${REPO_ROOT}/frameworks/base/packages/SystemUI/flag_check.py --msg=${PREUPLOAD_COMMIT_MESSAGE} --files=${PREUPLOAD_FILES} --project=${REPO_PATH}
+
+[Tool Paths]
+ktfmt = ${REPO_ROOT}/prebuilts/build-tools/common/framework/ktfmt.jar
diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
index 11fa7b75..c2aeada 100644
--- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
@@ -619,6 +619,7 @@
* List of end times for app-IDs that are temporarily marked as being allowed to access
* the network and acquire wakelocks. Times are in milliseconds.
*/
+ @GuardedBy("this")
private final SparseArray<Pair<MutableLong, String>> mTempWhitelistAppIdEndTimes
= new SparseArray<>();
@@ -5010,7 +5011,9 @@
if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) {
return -1;
}
- dumpTempWhitelistSchedule(pw, false);
+ synchronized (this) {
+ dumpTempWhitelistScheduleLocked(pw, false);
+ }
}
} else if ("except-idle-whitelist".equals(cmd)) {
getContext().enforceCallingOrSelfPermission(
@@ -5294,7 +5297,7 @@
pw.println();
}
}
- dumpTempWhitelistSchedule(pw, true);
+ dumpTempWhitelistScheduleLocked(pw, true);
size = mTempWhitelistAppIdArray != null ? mTempWhitelistAppIdArray.length : 0;
if (size > 0) {
@@ -5422,7 +5425,8 @@
}
}
- void dumpTempWhitelistSchedule(PrintWriter pw, boolean printTitle) {
+ @GuardedBy("this")
+ void dumpTempWhitelistScheduleLocked(PrintWriter pw, boolean printTitle) {
final int size = mTempWhitelistAppIdEndTimes.size();
if (size > 0) {
String prefix = "";
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/IdleController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/IdleController.java
index adee322..f722e41 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/IdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/IdleController.java
@@ -48,6 +48,7 @@
private static final String TAG = "JobScheduler.IdleController";
// Policy: we decide that we're "idle" if the device has been unused /
// screen off or dreaming or wireless charging dock idle for at least this long
+ @GuardedBy("mLock")
final ArraySet<JobStatus> mTrackedTasks = new ArraySet<>();
IdlenessTracker mIdleTracker;
private final FlexibilityController mFlexibilityController;
@@ -118,8 +119,10 @@
for (int i = mTrackedTasks.size()-1; i >= 0; i--) {
mTrackedTasks.valueAt(i).setIdleConstraintSatisfied(nowElapsed, isIdle);
}
+ if (!mTrackedTasks.isEmpty()) {
+ mStateChangedListener.onControllerStateChanged(mTrackedTasks);
+ }
}
- mStateChangedListener.onControllerStateChanged(mTrackedTasks);
}
/**
diff --git a/core/java/android/companion/virtual/flags/flags.aconfig b/core/java/android/companion/virtual/flags/flags.aconfig
index 006226e..ed5d662 100644
--- a/core/java/android/companion/virtual/flags/flags.aconfig
+++ b/core/java/android/companion/virtual/flags/flags.aconfig
@@ -52,4 +52,15 @@
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 2d9881a..282ede3 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -4397,8 +4397,6 @@
* {@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
- // com.android.internal.R.config_freeformWindowManagement to true in your configuration overlay.
@SdkConstant(SdkConstantType.FEATURE)
public static final String FEATURE_FREEFORM_WINDOW_MANAGEMENT
= "android.software.freeform_window_management";
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index a720b64..248ef1d 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -2745,17 +2745,6 @@
ar.recycle();
Log.i(TAG, "...preloaded " + numberOfEntries + " resources in "
+ (SystemClock.uptimeMillis() - startTime) + "ms.");
-
- if (sysRes.getBoolean(
- com.android.internal.R.bool.config_freeformWindowManagement)) {
- startTime = SystemClock.uptimeMillis();
- ar = sysRes.obtainTypedArray(
- com.android.internal.R.array.preloaded_freeform_multi_window_drawables);
- numberOfEntries = preloadDrawables(sysRes, ar);
- ar.recycle();
- Log.i(TAG, "...preloaded " + numberOfEntries + " resource in "
- + (SystemClock.uptimeMillis() - startTime) + "ms.");
- }
}
sysRes.finishPreloading();
} catch (RuntimeException e) {
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
index 60ad8e8..2d3d252 100644
--- a/core/java/android/hardware/SystemSensorManager.java
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -523,23 +523,25 @@
Handler mainHandler = new Handler(mContext.getMainLooper());
- for (Map.Entry<DynamicSensorCallback, Handler> entry :
- mDynamicSensorCallbacks.entrySet()) {
- final DynamicSensorCallback callback = entry.getKey();
- Handler handler =
- entry.getValue() == null ? mainHandler : entry.getValue();
+ synchronized (mDynamicSensorCallbacks) {
+ for (Map.Entry<DynamicSensorCallback, Handler> entry :
+ mDynamicSensorCallbacks.entrySet()) {
+ final DynamicSensorCallback callback = entry.getKey();
+ Handler handler =
+ entry.getValue() == null ? mainHandler : entry.getValue();
- handler.post(new Runnable() {
- @Override
- public void run() {
- for (Sensor s: addedList) {
- callback.onDynamicSensorConnected(s);
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ for (Sensor s: addedList) {
+ callback.onDynamicSensorConnected(s);
+ }
+ for (Sensor s: removedList) {
+ callback.onDynamicSensorDisconnected(s);
+ }
}
- for (Sensor s: removedList) {
- callback.onDynamicSensorDisconnected(s);
- }
- }
- });
+ });
+ }
}
for (Sensor s: removedList) {
@@ -658,13 +660,15 @@
if (callback == null) {
throw new IllegalArgumentException("callback cannot be null");
}
- if (mDynamicSensorCallbacks.containsKey(callback)) {
- // has been already registered, ignore
- return;
- }
+ synchronized (mDynamicSensorCallbacks) {
+ if (mDynamicSensorCallbacks.containsKey(callback)) {
+ // has been already registered, ignore
+ return;
+ }
- setupDynamicSensorBroadcastReceiver();
- mDynamicSensorCallbacks.put(callback, handler);
+ setupDynamicSensorBroadcastReceiver();
+ mDynamicSensorCallbacks.put(callback, handler);
+ }
}
/** @hide */
@@ -673,7 +677,9 @@
if (DEBUG_DYNAMIC_SENSOR) {
Log.i(TAG, "Removing dynamic sensor listener");
}
- mDynamicSensorCallbacks.remove(callback);
+ synchronized (mDynamicSensorCallbacks) {
+ mDynamicSensorCallbacks.remove(callback);
+ }
}
/*
diff --git a/core/java/android/os/IBinder.java b/core/java/android/os/IBinder.java
index 91c2965..c9f207c 100644
--- a/core/java/android/os/IBinder.java
+++ b/core/java/android/os/IBinder.java
@@ -305,15 +305,28 @@
/**
* Interface for receiving a callback when the process hosting an IBinder
* has gone away.
- *
+ *
* @see #linkToDeath
*/
public interface DeathRecipient {
public void binderDied();
/**
- * Interface for receiving a callback when the process hosting an IBinder
+ * The function called when the process hosting an IBinder
* has gone away.
+ *
+ * This callback will be called from any binder thread like any other binder
+ * transaction. If the process receiving this notification is multithreaded
+ * then synchronization may be required because other threads may be executing
+ * at the same time.
+ *
+ * No locks are held in libbinder when {@link binderDied} is called.
+ *
+ * There is no need to call {@link unlinkToDeath} in the binderDied callback.
+ * The binder is already dead so {@link unlinkToDeath} is a no-op.
+ * It will be unlinked when the last local reference of that binder proxy is
+ * dropped.
+ *
* @param who The IBinder that has become invalid
*/
default void binderDied(@NonNull IBinder who) {
diff --git a/core/java/android/view/HandwritingInitiator.java b/core/java/android/view/HandwritingInitiator.java
index beb4d95..57d1b8d 100644
--- a/core/java/android/view/HandwritingInitiator.java
+++ b/core/java/android/view/HandwritingInitiator.java
@@ -227,7 +227,10 @@
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 ca8a7a8..2fa5768 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_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 @@
@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/NativeVectorDrawableAnimator.java b/core/java/android/view/NativeVectorDrawableAnimator.java
index b0556a3..e92bd1f 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 @@
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 e0fae21..62b2b6c 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 @@
}
@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 bdada11..139285a 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -427,6 +427,12 @@
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 @@
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 @@
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 @@
// 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 @@
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 @@
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).
@@ -12581,6 +12625,24 @@
}
/**
+ * 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() {
@@ -12761,6 +12823,31 @@
}
/**
+ * 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
@@ -12983,6 +13070,10 @@
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);
+ }
}
/**
@@ -13001,7 +13092,7 @@
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/widget/RemoteViewsService.java b/core/java/android/widget/RemoteViewsService.java
index 07d6acb..c79eac6 100644
--- a/core/java/android/widget/RemoteViewsService.java
+++ b/core/java/android/widget/RemoteViewsService.java
@@ -132,7 +132,8 @@
RemoteViews.RemoteCollectionItems items = new RemoteViews.RemoteCollectionItems
.Builder().build();
Parcel capSizeTestParcel = Parcel.obtain();
- capSizeTestParcel.allowSquashing();
+ // restore allowSquashing to reduce the noise in error messages
+ boolean prevAllowSquashing = capSizeTestParcel.allowSquashing();
try {
RemoteViews.RemoteCollectionItems.Builder itemsBuilder =
@@ -154,6 +155,7 @@
items = itemsBuilder.build();
} finally {
+ capSizeTestParcel.restoreAllowSquashing(prevAllowSquashing);
// Recycle the parcel
capSizeTestParcel.recycle();
}
diff --git a/core/java/android/window/DisplayWindowPolicyController.java b/core/java/android/window/DisplayWindowPolicyController.java
index 8d71a8e..9cd2a71 100644
--- a/core/java/android/window/DisplayWindowPolicyController.java
+++ b/core/java/android/window/DisplayWindowPolicyController.java
@@ -23,6 +23,7 @@
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 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/flags/large_screen_experiences_app_compat.aconfig b/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig
index 4b2beb9..5b99ff9 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 @@
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"
@@ -80,6 +73,16 @@
}
flag {
+ name: "immersive_app_repositioning"
+ namespace: "large_screen_experiences_app_compat"
+ description: "Fix immersive apps changing size when repositioning"
+ bug: "334076352"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "camera_compat_for_freeform"
namespace: "large_screen_experiences_app_compat"
description: "Whether to apply Camera Compat treatment to fixed-orientation apps in freeform windowing mode"
diff --git a/core/java/android/window/flags/windowing_sdk.aconfig b/core/java/android/window/flags/windowing_sdk.aconfig
index 6af3d9e..9e69f89 100644
--- a/core/java/android/window/flags/windowing_sdk.aconfig
+++ b/core/java/android/window/flags/windowing_sdk.aconfig
@@ -147,4 +147,25 @@
metadata {
purpose: PURPOSE_BUGFIX
}
-}
\ No newline at end of file
+}
+
+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
+ }
+}
+
+flag {
+ namespace: "windowing_sdk"
+ name: "move_animation_options_to_change"
+ description: "Move AnimationOptions from TransitionInfo to each Change"
+ bug: "327332488"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/core/java/com/android/internal/policy/BackdropFrameRenderer.java b/core/java/com/android/internal/policy/BackdropFrameRenderer.java
deleted file mode 100644
index c6e8bf7..0000000
--- a/core/java/com/android/internal/policy/BackdropFrameRenderer.java
+++ /dev/null
@@ -1,398 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.internal.policy;
-
-import android.graphics.Insets;
-import android.graphics.RecordingCanvas;
-import android.graphics.Rect;
-import android.graphics.RenderNode;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
-import android.os.Looper;
-import android.view.Choreographer;
-import android.view.ThreadedRenderer;
-
-/**
- * The thread which draws a fill in background while the app is resizing in areas where the app
- * content draw is lagging behind the resize operation.
- * It starts with the creation and it ends once someone calls destroy().
- * Any size changes can be passed by a call to setTargetRect will passed to the thread and
- * executed via the Choreographer.
- * @hide
- */
-public class BackdropFrameRenderer extends Thread implements Choreographer.FrameCallback {
-
- private DecorView mDecorView;
-
- // This is containing the last requested size by a resize command. Note that this size might
- // or might not have been applied to the output already.
- private final Rect mTargetRect = new Rect();
-
- // The render nodes for the multi threaded renderer.
- private ThreadedRenderer mRenderer;
- private RenderNode mFrameAndBackdropNode;
- private RenderNode mSystemBarBackgroundNode;
-
- private final Rect mOldTargetRect = new Rect();
- private final Rect mNewTargetRect = new Rect();
-
- private Choreographer mChoreographer;
-
- // Cached size values from the last render for the case that the view hierarchy is gone
- // during a configuration change.
- private int mLastContentWidth;
- private int mLastContentHeight;
- private int mLastXOffset;
- private int mLastYOffset;
-
- // Whether to report when next frame is drawn or not.
- private boolean mReportNextDraw;
-
- private Drawable mCaptionBackgroundDrawable;
- private Drawable mUserCaptionBackgroundDrawable;
- private Drawable mResizingBackgroundDrawable;
- private ColorDrawable mStatusBarColor;
- private ColorDrawable mNavigationBarColor;
- private boolean mOldFullscreen;
- private boolean mFullscreen;
- private final Rect mOldSystemBarInsets = new Rect();
- private final Rect mSystemBarInsets = new Rect();
- private final Rect mTmpRect = new Rect();
-
- public BackdropFrameRenderer(DecorView decorView, ThreadedRenderer renderer, Rect initialBounds,
- Drawable resizingBackgroundDrawable, Drawable captionBackgroundDrawable,
- Drawable userCaptionBackgroundDrawable, int statusBarColor, int navigationBarColor,
- boolean fullscreen, Insets systemBarInsets) {
- setName("ResizeFrame");
-
- mRenderer = renderer;
- onResourcesLoaded(decorView, resizingBackgroundDrawable, captionBackgroundDrawable,
- userCaptionBackgroundDrawable, statusBarColor, navigationBarColor);
-
- // Create a render node for the content and frame backdrop
- // which can be resized independently from the content.
- mFrameAndBackdropNode = RenderNode.create("FrameAndBackdropNode", null);
-
- mRenderer.addRenderNode(mFrameAndBackdropNode, true);
-
- // Set the initial bounds and draw once so that we do not get a broken frame.
- mTargetRect.set(initialBounds);
- mFullscreen = fullscreen;
- mOldFullscreen = fullscreen;
- mSystemBarInsets.set(systemBarInsets.toRect());
- mOldSystemBarInsets.set(systemBarInsets.toRect());
-
- // Kick off our draw thread.
- start();
- }
-
- void onResourcesLoaded(DecorView decorView, Drawable resizingBackgroundDrawable,
- Drawable captionBackgroundDrawableDrawable, Drawable userCaptionBackgroundDrawable,
- int statusBarColor, int navigationBarColor) {
- synchronized (this) {
- mDecorView = decorView;
- mResizingBackgroundDrawable = resizingBackgroundDrawable != null
- && resizingBackgroundDrawable.getConstantState() != null
- ? resizingBackgroundDrawable.getConstantState().newDrawable()
- : null;
- mCaptionBackgroundDrawable = captionBackgroundDrawableDrawable != null
- && captionBackgroundDrawableDrawable.getConstantState() != null
- ? captionBackgroundDrawableDrawable.getConstantState().newDrawable()
- : null;
- mUserCaptionBackgroundDrawable = userCaptionBackgroundDrawable != null
- && userCaptionBackgroundDrawable.getConstantState() != null
- ? userCaptionBackgroundDrawable.getConstantState().newDrawable()
- : null;
- if (mCaptionBackgroundDrawable == null) {
- mCaptionBackgroundDrawable = mResizingBackgroundDrawable;
- }
- if (statusBarColor != 0) {
- mStatusBarColor = new ColorDrawable(statusBarColor);
- addSystemBarNodeIfNeeded();
- } else {
- mStatusBarColor = null;
- }
- if (navigationBarColor != 0) {
- mNavigationBarColor = new ColorDrawable(navigationBarColor);
- addSystemBarNodeIfNeeded();
- } else {
- mNavigationBarColor = null;
- }
- }
- }
-
- private void addSystemBarNodeIfNeeded() {
- if (mSystemBarBackgroundNode != null) {
- return;
- }
- mSystemBarBackgroundNode = RenderNode.create("SystemBarBackgroundNode", null);
- mRenderer.addRenderNode(mSystemBarBackgroundNode, false);
- }
-
- /**
- * Call this function asynchronously when the window size has been changed or when the insets
- * have changed or whether window switched between a fullscreen or non-fullscreen layout.
- * The change will be picked up once per frame and the frame will be re-rendered accordingly.
- *
- * @param newTargetBounds The new target bounds.
- * @param fullscreen Whether the window is currently drawing in fullscreen.
- * @param systemBarInsets The current visible system insets for the window.
- */
- public void setTargetRect(Rect newTargetBounds, boolean fullscreen, Rect systemBarInsets) {
- synchronized (this) {
- mFullscreen = fullscreen;
- mTargetRect.set(newTargetBounds);
- mSystemBarInsets.set(systemBarInsets);
- // Notify of a bounds change.
- pingRenderLocked(false /* drawImmediate */);
- }
- }
-
- /**
- * The window got replaced due to a configuration change.
- */
- public void onConfigurationChange() {
- synchronized (this) {
- if (mRenderer != null) {
- // Enforce a window redraw.
- mOldTargetRect.set(0, 0, 0, 0);
- pingRenderLocked(false /* drawImmediate */);
- }
- }
- }
-
- /**
- * All resources of the renderer will be released. This function can be called from the
- * the UI thread as well as the renderer thread.
- */
- void releaseRenderer() {
- synchronized (this) {
- if (mRenderer != null) {
- // Invalidate the current content bounds.
- mRenderer.setContentDrawBounds(0, 0, 0, 0);
-
- // Remove the render node again
- // (see comment above - better to do that only once).
- mRenderer.removeRenderNode(mFrameAndBackdropNode);
- if (mSystemBarBackgroundNode != null) {
- mRenderer.removeRenderNode(mSystemBarBackgroundNode);
- }
-
- mRenderer = null;
-
- // Exit the renderer loop.
- pingRenderLocked(false /* drawImmediate */);
- }
- }
- }
-
- @Override
- public void run() {
- try {
- Looper.prepare();
- synchronized (this) {
- if (mRenderer == null) {
- // This can happen if 'releaseRenderer' is called immediately after 'start'.
- return;
- }
- mChoreographer = Choreographer.getInstance();
- }
- Looper.loop();
- } finally {
- releaseRenderer();
- }
- synchronized (this) {
- // Make sure no more messages are being sent.
- mChoreographer = null;
- Choreographer.releaseInstance();
- }
- }
-
- /**
- * The implementation of the FrameCallback.
- * @param frameTimeNanos The time in nanoseconds when the frame started being rendered,
- * in the {@link System#nanoTime()} timebase. Divide this value by {@code 1000000}
- */
- @Override
- public void doFrame(long frameTimeNanos) {
- synchronized (this) {
- if (mRenderer == null) {
- reportDrawIfNeeded();
- // Tell the looper to stop. We are done.
- Looper.myLooper().quit();
- return;
- }
- doFrameUncheckedLocked();
- }
- }
-
- private void doFrameUncheckedLocked() {
- mNewTargetRect.set(mTargetRect);
- if (!mNewTargetRect.equals(mOldTargetRect)
- || mOldFullscreen != mFullscreen
- || !mSystemBarInsets.equals(mOldSystemBarInsets)
- || mReportNextDraw) {
- mOldFullscreen = mFullscreen;
- mOldTargetRect.set(mNewTargetRect);
- mOldSystemBarInsets.set(mSystemBarInsets);
- redrawLocked(mNewTargetRect, mFullscreen);
- }
- }
-
- /**
- * The content is about to be drawn and we got the location of where it will be shown.
- * If a "redrawLocked" call has already been processed, we will re-issue the call
- * if the previous call was ignored since the size was unknown.
- * @param xOffset The x offset where the content is drawn to.
- * @param yOffset The y offset where the content is drawn to.
- * @param xSize The width size of the content. This should not be 0.
- * @param ySize The height of the content.
- * @return true if a frame should be requested after the content is drawn; false otherwise.
- */
- boolean onContentDrawn(int xOffset, int yOffset, int xSize, int ySize) {
- synchronized (this) {
- final boolean firstCall = mLastContentWidth == 0;
- // The current content buffer is drawn here.
- mLastContentWidth = xSize;
- mLastContentHeight = ySize;
- mLastXOffset = xOffset;
- mLastYOffset = yOffset;
-
- // Inform the renderer of the content's new bounds
- mRenderer.setContentDrawBounds(
- mLastXOffset,
- mLastYOffset,
- mLastXOffset + mLastContentWidth,
- mLastYOffset + mLastContentHeight);
-
- // If this was the first call and redrawLocked got already called prior
- // to us, we should re-issue a redrawLocked now.
- return firstCall;
- }
- }
-
- void onRequestDraw(boolean reportNextDraw) {
- synchronized (this) {
- mReportNextDraw = reportNextDraw;
- mOldTargetRect.set(0, 0, 0, 0);
- pingRenderLocked(true /* drawImmediate */);
- }
- }
-
- /**
- * Redraws the background, the caption and the system inset backgrounds if something changed.
- *
- * @param newBounds The window bounds which needs to be drawn.
- * @param fullscreen Whether the window is currently drawing in fullscreen.
- */
- private void redrawLocked(Rect newBounds, boolean fullscreen) {
-
- // Make sure that the other thread has already prepared the render draw calls for the
- // content. If any size is 0, we have to wait for it to be drawn first.
- if (mLastContentWidth == 0 || mLastContentHeight == 0) {
- return;
- }
-
- // Content may not be drawn at the surface origin, so we want to keep the offset when we're
- // resizing it.
- final int left = mLastXOffset + newBounds.left;
- final int top = mLastYOffset + newBounds.top;
- final int width = newBounds.width();
- final int height = newBounds.height();
-
- mFrameAndBackdropNode.setLeftTopRightBottom(left, top, left + width, top + height);
-
- // Draw the caption and content backdrops in to our render node.
- RecordingCanvas canvas = mFrameAndBackdropNode.beginRecording(width, height);
- final Drawable drawable = mUserCaptionBackgroundDrawable != null
- ? mUserCaptionBackgroundDrawable : mCaptionBackgroundDrawable;
-
- if (drawable != null) {
- drawable.setBounds(0, 0, left + width, top);
- drawable.draw(canvas);
- }
-
- // The backdrop: clear everything with the background. Clipping is done elsewhere.
- if (mResizingBackgroundDrawable != null) {
- mResizingBackgroundDrawable.setBounds(0, 0, left + width, top + height);
- mResizingBackgroundDrawable.draw(canvas);
- }
- mFrameAndBackdropNode.endRecording();
-
- drawColorViews(left, top, width, height, fullscreen);
-
- // We need to render the node explicitly
- mRenderer.drawRenderNode(mFrameAndBackdropNode);
-
- reportDrawIfNeeded();
- }
-
- private void drawColorViews(int left, int top, int width, int height, boolean fullscreen) {
- if (mSystemBarBackgroundNode == null) {
- return;
- }
- RecordingCanvas canvas = mSystemBarBackgroundNode.beginRecording(width, height);
- mSystemBarBackgroundNode.setLeftTopRightBottom(left, top, left + width, top + height);
- final int topInset = mSystemBarInsets.top;
- if (mStatusBarColor != null) {
- mStatusBarColor.setBounds(0, 0, left + width, topInset);
- mStatusBarColor.draw(canvas);
- }
-
- // We only want to draw the navigation bar if our window is currently fullscreen because we
- // don't want the navigation bar background be moving around when resizing in docked mode.
- // However, we need it for the transitions into/out of docked mode.
- if (mNavigationBarColor != null && fullscreen) {
- DecorView.getNavigationBarRect(width, height, mSystemBarInsets, mTmpRect, 1f);
- mNavigationBarColor.setBounds(mTmpRect);
- mNavigationBarColor.draw(canvas);
- }
- mSystemBarBackgroundNode.endRecording();
- mRenderer.drawRenderNode(mSystemBarBackgroundNode);
- }
-
- /** Notify view root that a frame has been drawn by us, if it has requested so. */
- private void reportDrawIfNeeded() {
- if (mReportNextDraw) {
- if (mDecorView.isAttachedToWindow()) {
- mDecorView.getViewRootImpl().reportDrawFinish();
- }
- mReportNextDraw = false;
- }
- }
-
- /**
- * Sends a message to the renderer to wake up and perform the next action which can be
- * either the next rendering or the self destruction if mRenderer is null.
- * Note: This call must be synchronized.
- *
- * @param drawImmediate if we should draw immediately instead of scheduling a frame
- */
- private void pingRenderLocked(boolean drawImmediate) {
- if (mChoreographer != null && !drawImmediate) {
- mChoreographer.postFrameCallback(this);
- } else {
- doFrameUncheckedLocked();
- }
- }
-
- void setUserCaptionBackgroundDrawable(Drawable userCaptionBackgroundDrawable) {
- synchronized (this) {
- mUserCaptionBackgroundDrawable = userCaptionBackgroundDrawable;
- }
- }
-}
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 74c2325..c14a6c1 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -57,7 +57,6 @@
import android.graphics.PixelFormat;
import android.graphics.RecordingCanvas;
import android.graphics.Rect;
-import android.graphics.Region;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.InsetDrawable;
@@ -238,11 +237,8 @@
private Rect mTempRect;
private boolean mWindowResizeCallbacksAdded = false;
- private Drawable.Callback mLastBackgroundDrawableCb = null;
- private BackdropFrameRenderer mBackdropFrameRenderer = null;
private Drawable mOriginalBackgroundDrawable;
private Drawable mLastOriginalBackgroundDrawable;
- private Drawable mResizingBackgroundDrawable;
private BackgroundBlurDrawable mBackgroundBlurDrawable;
private BackgroundBlurDrawable mLastBackgroundBlurDrawable;
@@ -253,8 +249,6 @@
*/
@Nullable
private Drawable mPendingWindowBackground;
- private Drawable mCaptionBackgroundDrawable;
- private Drawable mUserCaptionBackgroundDrawable;
String mLogTag = TAG;
private final Rect mFloatingInsets = new Rect();
@@ -329,26 +323,6 @@
}
@Override
- public boolean gatherTransparentRegion(Region region) {
- boolean statusOpaque = gatherTransparentRegion(mStatusColorViewState, region);
- boolean navOpaque = gatherTransparentRegion(mNavigationColorViewState, region);
- boolean decorOpaque = super.gatherTransparentRegion(region);
-
- // combine bools after computation, so each method above always executes
- return statusOpaque || navOpaque || decorOpaque;
- }
-
- boolean gatherTransparentRegion(ColorViewState colorViewState, Region region) {
- if (colorViewState.view != null && colorViewState.visible && isResizing()) {
- // If a visible ColorViewState is in a resizing host DecorView, forcibly register its
- // opaque area, since it's drawn by a different root RenderNode. It would otherwise be
- // rejected by ViewGroup#gatherTransparentRegion() for the view not being VISIBLE.
- return colorViewState.view.gatherTransparentRegion(region);
- }
- return false; // no opaque area added
- }
-
- @Override
public void onDraw(Canvas c) {
super.onDraw(c);
@@ -838,7 +812,7 @@
final MenuHelper helper;
final boolean isPopup = !Float.isNaN(x) && !Float.isNaN(y);
if (isPopup) {
- helper = mWindow.mContextMenu.showPopup(getContext(), originalView, x, y);
+ helper = mWindow.mContextMenu.showPopup(originalView.getContext(), originalView, x, y);
} else {
helper = mWindow.mContextMenu.showDialog(originalView, originalView.getWindowToken());
}
@@ -977,15 +951,11 @@
updateColorViews(null /* insets */, false /* animate */);
}
if (drawable != null) {
- mResizingBackgroundDrawable = enforceNonTranslucentBackground(drawable,
- mWindow.isTranslucent() || mWindow.isShowingWallpaper());
- } else {
- mResizingBackgroundDrawable = getResizingBackgroundDrawable(
- mWindow.mBackgroundDrawable, mWindow.mBackgroundFallbackDrawable,
- mWindow.isTranslucent() || mWindow.isShowingWallpaper());
- }
- if (mResizingBackgroundDrawable != null) {
- mResizingBackgroundDrawable.getPadding(mBackgroundPadding);
+ drawable.getPadding(mBackgroundPadding);
+ } else if (mWindow.mBackgroundDrawable != null) {
+ mWindow.mBackgroundDrawable.getPadding(mBackgroundPadding);
+ } else if (mWindow.mBackgroundFallbackDrawable != null) {
+ mWindow.mBackgroundFallbackDrawable.getPadding(mBackgroundPadding);
} else {
mBackgroundPadding.setEmpty();
}
@@ -1451,7 +1421,7 @@
mWindow.getAttributes().flags, force);
boolean show = state.attributes.isVisible(state.present, color,
mWindow.getAttributes().flags, force);
- boolean showView = show && !isResizing() && size > 0;
+ boolean showView = show && size > 0;
boolean visibilityChanged = false;
View view = state.view;
@@ -1505,7 +1475,7 @@
}
if (visibilityChanged) {
view.animate().cancel();
- if (animate && !isResizing()) {
+ if (animate) {
if (showView) {
if (view.getVisibility() != VISIBLE) {
view.setVisibility(VISIBLE);
@@ -1834,10 +1804,6 @@
// Note that our ViewRootImpl object will not change.
getViewRootImpl().addWindowCallbacks(this);
mWindowResizeCallbacksAdded = true;
- } else if (mBackdropFrameRenderer != null) {
- // We are resizing and this call happened due to a configuration change. Tell the
- // renderer about it.
- mBackdropFrameRenderer.onConfigurationChange();
}
updateBackgroundBlurRadius();
@@ -1877,8 +1843,6 @@
st.menu.close();
}
- releaseThreadedRenderer();
-
if (mWindowResizeCallbacksAdded) {
getViewRootImpl().removeWindowCallbacks(this);
mWindowResizeCallbacksAdded = false;
@@ -2158,14 +2122,6 @@
}
void onResourcesLoaded(LayoutInflater inflater, int layoutResource) {
- if (mBackdropFrameRenderer != null) {
- loadBackgroundDrawablesIfNeeded();
- mBackdropFrameRenderer.onResourcesLoaded(
- this, mResizingBackgroundDrawable, mCaptionBackgroundDrawable,
- mUserCaptionBackgroundDrawable, getCurrentColor(mStatusColorViewState),
- getCurrentColor(mNavigationColorViewState));
- }
-
final View root = inflater.inflate(layoutResource, null);
// Put it below the color views.
@@ -2174,63 +2130,6 @@
initializeElevation();
}
- private void loadBackgroundDrawablesIfNeeded() {
- if (mResizingBackgroundDrawable == null) {
- mResizingBackgroundDrawable = getResizingBackgroundDrawable(mWindow.mBackgroundDrawable,
- mWindow.mBackgroundFallbackDrawable, mWindow.isTranslucent()
- || mWindow.isShowingWallpaper());
- if (mResizingBackgroundDrawable == null) {
- // We shouldn't really get here as the background fallback should be always
- // available since it is defaulted by the system.
- Log.w(mLogTag, "Failed to find background drawable for PhoneWindow=" + mWindow);
- }
- }
- if (mCaptionBackgroundDrawable == null) {
- mCaptionBackgroundDrawable = getContext().getDrawable(
- R.drawable.decor_caption_title_focused);
- }
- if (mResizingBackgroundDrawable != null) {
- mLastBackgroundDrawableCb = mResizingBackgroundDrawable.getCallback();
- mResizingBackgroundDrawable.setCallback(null);
- }
- }
-
- /**
- * Returns the color used to fill areas the app has not rendered content to yet when the
- * user is resizing the window of an activity in multi-window mode.
- */
- public static Drawable getResizingBackgroundDrawable(@Nullable Drawable backgroundDrawable,
- @Nullable Drawable fallbackDrawable, boolean windowTranslucent) {
- if (backgroundDrawable != null) {
- return enforceNonTranslucentBackground(backgroundDrawable, windowTranslucent);
- }
-
- if (fallbackDrawable != null) {
- return enforceNonTranslucentBackground(fallbackDrawable, windowTranslucent);
- }
- return new ColorDrawable(Color.BLACK);
- }
-
- /**
- * Enforces a drawable to be non-translucent to act as a background if needed, i.e. if the
- * window is not translucent.
- */
- private static Drawable enforceNonTranslucentBackground(Drawable drawable,
- boolean windowTranslucent) {
- if (!windowTranslucent && drawable instanceof ColorDrawable) {
- ColorDrawable colorDrawable = (ColorDrawable) drawable;
- int color = colorDrawable.getColor();
- if (Color.alpha(color) != 255) {
- ColorDrawable copy = (ColorDrawable) colorDrawable.getConstantState().newDrawable()
- .mutate();
- copy.setColor(
- Color.argb(255, Color.red(color), Color.green(color), Color.blue(color)));
- return copy;
- }
- }
- return drawable;
- }
-
void clearContentView() {
for (int i = getChildCount() - 1; i >= 0; i--) {
View v = getChildAt(i);
@@ -2243,21 +2142,13 @@
@Override
public void onWindowSizeIsChanging(Rect newBounds, boolean fullscreen, Rect systemInsets,
- Rect stableInsets) {
- if (mBackdropFrameRenderer != null) {
- mBackdropFrameRenderer.setTargetRect(newBounds, fullscreen, systemInsets);
- }
- }
+ Rect stableInsets) {}
@Override
public void onWindowDragResizeStart(Rect initialBounds, boolean fullscreen, Rect systemInsets,
Rect stableInsets) {
if (mWindow.isDestroyed()) {
// If the owner's window is gone, we should not be able to come here anymore.
- releaseThreadedRenderer();
- return;
- }
- if (mBackdropFrameRenderer != null) {
return;
}
getViewRootImpl().requestInvalidateRootRenderNode();
@@ -2265,28 +2156,23 @@
@Override
public void onWindowDragResizeEnd() {
- releaseThreadedRenderer();
updateColorViews(null /* insets */, false);
getViewRootImpl().requestInvalidateRootRenderNode();
}
@Override
public boolean onContentDrawn(int offsetX, int offsetY, int sizeX, int sizeY) {
- if (mBackdropFrameRenderer == null) {
- return false;
- }
- return mBackdropFrameRenderer.onContentDrawn(offsetX, offsetY, sizeX, sizeY);
+ return false;
}
@Override
public void onRequestDraw(boolean reportNextDraw) {
- if (mBackdropFrameRenderer != null) {
- mBackdropFrameRenderer.onRequestDraw(reportNextDraw);
- } else if (reportNextDraw) {
- // If render thread is gone, just report immediately.
- if (isAttachedToWindow()) {
- getViewRootImpl().reportDrawFinish();
- }
+ if (!reportNextDraw) {
+ return;
+ }
+ // If render thread is gone, just report immediately.
+ if (isAttachedToWindow()) {
+ getViewRootImpl().reportDrawFinish();
}
}
@@ -2307,25 +2193,6 @@
mLegacyNavigationBarBackgroundPaint);
}
- /** Release the renderer thread which is usually done when the user stops resizing. */
- private void releaseThreadedRenderer() {
- if (mResizingBackgroundDrawable != null && mLastBackgroundDrawableCb != null) {
- mResizingBackgroundDrawable.setCallback(mLastBackgroundDrawableCb);
- mLastBackgroundDrawableCb = null;
- }
-
- if (mBackdropFrameRenderer != null) {
- mBackdropFrameRenderer.releaseRenderer();
- mBackdropFrameRenderer = null;
- // Bring the shadow back.
- updateElevation();
- }
- }
-
- private boolean isResizing() {
- return mBackdropFrameRenderer != null;
- }
-
/**
* The elevation gets set for the first time and the framework needs to be informed that
* the surface layer gets created with the shadow size in mind.
@@ -2348,7 +2215,7 @@
final boolean wasAdjustedForStack = mElevationAdjustedForStack;
// Do not use a shadow when we are in resizing mode (mBackdropFrameRenderer not null)
// since the shadow is bound to the content size and not the target size.
- if ((windowingMode == WINDOWING_MODE_FREEFORM) && !isResizing()) {
+ if (windowingMode == WINDOWING_MODE_FREEFORM) {
elevation = hasWindowFocus() ?
DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP : DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP;
// Add a maximum shadow height value to the top level view.
@@ -2367,16 +2234,8 @@
// Don't change the elevation if we didn't previously adjust it for the stack it was in
// or it didn't change.
- if ((wasAdjustedForStack || mElevationAdjustedForStack)
- && getElevation() != elevation) {
- if (!isResizing()) {
- mWindow.setElevation(elevation);
- } else {
- // Just suppress the shadow when resizing, don't adjust surface insets because it'll
- // cause a flicker when drag resize for freeform window starts. #onContentDrawn()
- // will compensate the offset when passing to BackdropFrameRenderer.
- setElevation(elevation);
- }
+ if ((wasAdjustedForStack || mElevationAdjustedForStack) && getElevation() != elevation) {
+ mWindow.setElevation(elevation);
}
}
@@ -2390,16 +2249,6 @@
getResources().getDisplayMetrics());
}
- /**
- * Provide an override of the caption background drawable.
- */
- void setUserCaptionBackgroundDrawable(Drawable drawable) {
- mUserCaptionBackgroundDrawable = drawable;
- if (mBackdropFrameRenderer != null) {
- mBackdropFrameRenderer.setUserCaptionBackgroundDrawable(drawable);
- }
- }
-
private static String getTitleSuffix(WindowManager.LayoutParams params) {
if (params == null) {
return "";
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index a091e19..2194c89 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -4055,7 +4055,8 @@
@Override
public void setResizingCaptionDrawable(Drawable drawable) {
- mDecor.setUserCaptionBackgroundDrawable(drawable);
+ // TODO(b/333724879): Deprecate this public API. The new caption in WM shell allows the app
+ // content to draw behind it directly if requested.
}
@Override
diff --git a/core/java/com/android/internal/policy/ScreenDecorationsUtils.java b/core/java/com/android/internal/policy/ScreenDecorationsUtils.java
index ec62839..067e5e88 100644
--- a/core/java/com/android/internal/policy/ScreenDecorationsUtils.java
+++ b/core/java/com/android/internal/policy/ScreenDecorationsUtils.java
@@ -18,6 +18,9 @@
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 @@
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/java/com/android/internal/policy/TransitionAnimation.java b/core/java/com/android/internal/policy/TransitionAnimation.java
index 2f09a55..66b2a9c 100644
--- a/core/java/com/android/internal/policy/TransitionAnimation.java
+++ b/core/java/com/android/internal/policy/TransitionAnimation.java
@@ -1299,6 +1299,21 @@
== HardwareBuffer.USAGE_PROTECTED_CONTENT;
}
+ /**
+ * Returns the luminance in 0~1. The surface control is the source of the hardware buffer,
+ * which will be used if the buffer is protected from reading.
+ */
+ public static float getBorderLuma(@NonNull HardwareBuffer hwBuffer,
+ @NonNull ColorSpace colorSpace, @NonNull SurfaceControl sourceSurfaceControl) {
+ if (hasProtectedContent(hwBuffer)) {
+ // The buffer cannot be read. Capture another buffer which excludes protected content
+ // from the source surface.
+ return getBorderLuma(sourceSurfaceControl, hwBuffer.getWidth(), hwBuffer.getHeight());
+ }
+ // Use the existing buffer directly.
+ return getBorderLuma(hwBuffer, colorSpace);
+ }
+
/** Returns the luminance in 0~1. */
public static float getBorderLuma(SurfaceControl surfaceControl, int w, int h) {
final ScreenCapture.ScreenshotHardwareBuffer buffer =
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 7b9235cd..6dbe44b 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/drawable/decor_caption_title.xml b/core/res/res/drawable/decor_caption_title.xml
deleted file mode 100644
index 591605d3..0000000
--- a/core/res/res/drawable/decor_caption_title.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 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.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_window_focused="true"
- android:drawable="@drawable/decor_caption_title_focused" />
- <item android:drawable="@drawable/decor_caption_title_unfocused" />
-</selector>
diff --git a/core/res/res/drawable/decor_caption_title_focused.xml b/core/res/res/drawable/decor_caption_title_focused.xml
deleted file mode 100644
index 7d1c230..0000000
--- a/core/res/res/drawable/decor_caption_title_focused.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 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.
--->
-
-<shape android:shape="rectangle"
- android:tintMode="multiply"
- android:tint="#D8D8D8"
- xmlns:android="http://schemas.android.com/apk/res/android">
- <!-- Fading the primary color to 85% blackness -->
- <solid android:color="?android:attr/colorPrimary" />
-</shape>
diff --git a/core/res/res/drawable/decor_caption_title_unfocused.xml b/core/res/res/drawable/decor_caption_title_unfocused.xml
deleted file mode 100644
index 2846d8ca..0000000
--- a/core/res/res/drawable/decor_caption_title_unfocused.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 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.
--->
-
-<shape android:shape="rectangle"
- android:tintMode="multiply"
- android:tint="#F2F2F2"
- xmlns:android="http://schemas.android.com/apk/res/android">
- <!-- Fading the primary color to 95% blackness -->
- <solid android:color="?android:attr/colorPrimary"/>
-</shape>
diff --git a/core/res/res/drawable/decor_close_button_dark.xml b/core/res/res/drawable/decor_close_button_dark.xml
deleted file mode 100644
index 950e4fd..0000000
--- a/core/res/res/drawable/decor_close_button_dark.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<!--
-Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="32.0dp"
- android:height="32.0dp"
- android:viewportWidth="32.0"
- android:viewportHeight="32.0"
- android:tint="@color/decor_button_dark_color"
- >
- <group android:scaleX="0.5"
- android:scaleY="0.5"
- android:translateX="8.0"
- android:translateY="8.0" >
- <path
- android:fillColor="@color/white"
- android:pathData="M6.9,4.0l-2.9,2.9 9.1,9.1 -9.1,9.200001 2.9,2.799999 9.1,-9.1 9.1,9.1 2.9,-2.799999 -9.1,-9.200001 9.1,-9.1 -2.9,-2.9 -9.1,9.2z"/>
- </group>
-</vector>
diff --git a/core/res/res/drawable/decor_close_button_light.xml b/core/res/res/drawable/decor_close_button_light.xml
deleted file mode 100644
index d75cd25..0000000
--- a/core/res/res/drawable/decor_close_button_light.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<!--
-Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="32.0dp"
- android:height="32.0dp"
- android:viewportWidth="32.0"
- android:viewportHeight="32.0"
- android:tint="@color/decor_button_light_color"
- >
- <group android:scaleX="0.5"
- android:scaleY="0.5"
- android:translateX="8.0"
- android:translateY="8.0" >
- <path
- android:fillColor="@color/white"
- android:pathData="M6.9,4.0l-2.9,2.9 9.1,9.1 -9.1,9.200001 2.9,2.799999 9.1,-9.1 9.1,9.1 2.9,-2.799999 -9.1,-9.200001 9.1,-9.1 -2.9,-2.9 -9.1,9.2z"/>
- </group>
-</vector>
diff --git a/core/res/res/drawable/decor_maximize_button_dark.xml b/core/res/res/drawable/decor_maximize_button_dark.xml
deleted file mode 100644
index 619b460..0000000
--- a/core/res/res/drawable/decor_maximize_button_dark.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="32.0dp"
- android:height="32.0dp"
- android:viewportWidth="32.0"
- android:viewportHeight="32.0"
- android:tint="@color/decor_button_dark_color"
- >
- <group android:scaleX="0.5"
- android:scaleY="0.5"
- android:translateX="8.0"
- android:translateY="8.0" >
- <path
- android:fillColor="@color/white"
- android:pathData="M2.0,4.0l0.0,16.0l28.0,0.0L30.0,4.0L2.0,4.0zM26.0,16.0L6.0,16.0L6.0,8.0l20.0,0.0L26.0,16.0z"/>
- <path
- android:fillColor="@color/white"
- android:pathData="M2.0,24.0l28.0,0.0l0.0,4.0l-28.0,0.0z"/>
- </group>
-</vector>
-
-
diff --git a/core/res/res/drawable/decor_maximize_button_light.xml b/core/res/res/drawable/decor_maximize_button_light.xml
deleted file mode 100644
index 5b55fd2..0000000
--- a/core/res/res/drawable/decor_maximize_button_light.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<!--
-Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="32.0dp"
- android:height="32.0dp"
- android:viewportWidth="32.0"
- android:viewportHeight="32.0"
- android:tint="@color/decor_button_light_color"
- >
- <group android:scaleX="0.5"
- android:scaleY="0.5"
- android:translateX="8.0"
- android:translateY="8.0" >
- <path
- android:fillColor="@color/white"
- android:pathData="M2.0,4.0l0.0,16.0l28.0,0.0L30.0,4.0L2.0,4.0zM26.0,16.0L6.0,16.0L6.0,8.0l20.0,0.0L26.0,16.0z"/>
- <path
- android:fillColor="@color/white"
- android:pathData="M2.0,24.0l28.0,0.0l0.0,4.0l-28.0,0.0z"/>
- </group>
-</vector>
diff --git a/core/res/res/layout/decor_caption.xml b/core/res/res/layout/decor_caption.xml
deleted file mode 100644
index 0246736..0000000
--- a/core/res/res/layout/decor_caption.xml
+++ /dev/null
@@ -1,52 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 2015, 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.internal.widget.DecorCaptionView xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:descendantFocusability="beforeDescendants" >
- <LinearLayout
- android:id="@+id/caption"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="end"
- android:background="@drawable/decor_caption_title"
- android:focusable="false"
- android:descendantFocusability="blocksDescendants" >
- <Button
- android:id="@+id/maximize_window"
- android:layout_width="32dp"
- android:layout_height="32dp"
- android:layout_margin="5dp"
- android:padding="4dp"
- android:layout_gravity="center_vertical|end"
- android:contentDescription="@string/maximize_button_text"
- android:background="@drawable/decor_maximize_button_dark" />
- <Button
- android:id="@+id/close_window"
- android:layout_width="32dp"
- android:layout_height="32dp"
- android:layout_margin="5dp"
- android:padding="4dp"
- android:layout_gravity="center_vertical|end"
- android:contentDescription="@string/close_button_text"
- android:background="@drawable/decor_close_button_dark" />
- </LinearLayout>
-</com.android.internal.widget.DecorCaptionView>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index b532ad7..ca6a384 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 060c8cb..218b13a 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 f59a8cb..d0e28b7 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 c20d5ae..42b0af9 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 9d44759..5633c06 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 140ca4a..e38706e 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 116a836..25ae5a7 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 086cb63..6b388d8 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 679cf57..3f338cc 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 a4d1b46..0438302 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 3219c56..21f397b 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 2305f6a..4013a03 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 dd50635..5226d56 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 af5a20d..949150a 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 31a52c8..11dac6c 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 a051155..1effe7c 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 8f3f623..4abc581 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 ff3c20a..425d88c 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 daa61ab..56ff14a 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 98cac20..e599c03 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 98a2c50..f5859bf 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 2e23042..d8b1f59 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 6f80461..77e665a 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 2a544f3..9bf2a4d 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 96d1203..308260f 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 8760948..db579f2 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 4aeb86e..8888005 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 f380133..4c2835d 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 342d76b..cb8e804 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 5aca7d6..55032c9 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 3af0279..e47715a 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 57caeec..0b9b662 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 8447d79..de6777e 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 e882794..58331c7 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 a075749..eeaf2b6 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 8b6f7c7..7e68a06 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 abd1c29..037e148 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 0c70e91..a1e72da 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 4704e38..04e47a7 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 e0a507e..4f87855 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 04c99a2..f36d9fc 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 527745c..195eb13 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 ade6f76..073e448 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 c60482f..bbe8aef 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 c23e49a..9686a14 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 12f59b7..b6bd4b2 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 c4e228c..2b4f370 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 c70abad..3669f04 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 b3b2d73..8902619 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 97ce202..005d7cb 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 2d630ac..ddbeb35 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 a6e3e66..77a58af 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 4e4189f..96691f6 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 fa449ca..c1b7822 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 a07639b..23f675e 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 284b3886..99dd0e4 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 0c55e6b..0b2c507 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 d38d824..f3cd70e 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 61e1846..60d8737 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 fc09874..ec5fee7 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 2f666a6..7067a89 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 9c9fb8d..6632f85 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 2f666a6..7067a89 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 76d69d2..bf82cd8c 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 b21a13c..c1900a8 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 11e8d0e..f216ce2 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 39fee34..9c2a875 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 ee37cb8..b3530e7 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 1d09715..5f9a642 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 a610344..301fe24 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 9cc174c..b3c2063 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 d1bd775..f15796e 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 9479033..f615965 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 05b23d5..a84f6eb 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 aa9d77d..e34b526 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 6b4be29..4288460 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 96780a0..906ccbc 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 a64c990..cc9df2e 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 0436022..c0be641 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 e5a45da..517176b 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 6047ea7..e6db9dd 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 2503bf6..4b04940 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 7113146..1aa9c72 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 94a5d11..1c83ee6 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 bbf844e..2375442 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/arrays.xml b/core/res/res/values/arrays.xml
index 97e753e..575573c 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -136,11 +136,6 @@
<item>@color/search_url_text_material_light</item>
</array>
- <array name="preloaded_freeform_multi_window_drawables">
- <item>@drawable/decor_maximize_button_dark</item>
- <item>@drawable/decor_maximize_button_light</item>
- </array>
-
<!-- Used in LocalePicker -->
<string-array translatable="false" name="special_locale_codes">
<!-- http://b/17150708 - ensure that the list of languages says "Arabic"
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 1112e65..0706b32 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4200,13 +4200,6 @@
automatically try to pair with it when the device exits tablet mode. -->
<string translatable="false" name="config_packagedKeyboardName"></string>
- <!-- The device supports freeform window management. Windows have title bars and can be moved
- and resized. If you set this to true, you also need to add
- PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT feature to your device specification.
- The duplication is necessary, because this information is used before the features are
- available to the system.-->
- <bool name="config_freeformWindowManagement">false</bool>
-
<!-- If set, this will force all windows to draw the status bar background, including the apps
that have not requested doing so (via the WindowManager.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS
flag). -->
diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml
index 04f6f52..dcda5d8 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/res/res/values/strings.xml b/core/res/res/values/strings.xml
index a956a43..87141c7 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5991,8 +5991,6 @@
<string name="accessibility_system_action_dpad_right_label">Dpad Right</string>
<!-- Label for Dpad center action [CHAR LIMIT=NONE] -->
<string name="accessibility_system_action_dpad_center_label">Dpad Center</string>
- <!-- Accessibility description of caption view -->
- <string name="accessibility_freeform_caption">Caption bar of <xliff:g id="app_name">%1$s</xliff:g>.</string>
<!-- Text to tell the user that a package has been forced by themselves in the RESTRICTED bucket. [CHAR LIMIT=NONE] -->
<string name="as_app_forced_to_restricted_bucket">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 0d2fd1c..bb73934 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -402,7 +402,6 @@
<java-symbol type="bool" name="config_supportMicNearUltrasound" />
<java-symbol type="bool" name="config_supportSpeakerNearUltrasound" />
<java-symbol type="bool" name="config_supportAudioSourceUnprocessed" />
- <java-symbol type="bool" name="config_freeformWindowManagement" />
<java-symbol type="bool" name="config_supportsBubble" />
<java-symbol type="bool" name="config_supportsMultiWindow" />
<java-symbol type="bool" name="config_supportsSplitScreenMultiWindow" />
@@ -1266,7 +1265,6 @@
<java-symbol type="array" name="networkAttributes" />
<java-symbol type="array" name="preloaded_color_state_lists" />
<java-symbol type="array" name="preloaded_drawables" />
- <java-symbol type="array" name="preloaded_freeform_multi_window_drawables" />
<java-symbol type="array" name="sim_colors" />
<java-symbol type="array" name="special_locale_codes" />
<java-symbol type="array" name="special_locale_names" />
@@ -2470,16 +2468,6 @@
<!-- From Phone -->
<java-symbol type="bool" name="config_built_in_sip_phone" />
- <java-symbol type="id" name="maximize_window" />
- <java-symbol type="id" name="close_window" />
- <java-symbol type="layout" name="decor_caption" />
- <java-symbol type="drawable" name="decor_caption_title_focused" />
- <java-symbol type="drawable" name="decor_close_button_dark" />
- <java-symbol type="drawable" name="decor_close_button_light" />
- <java-symbol type="drawable" name="decor_maximize_button_dark" />
- <java-symbol type="drawable" name="decor_maximize_button_light" />
- <java-symbol type="color" name="decor_button_dark_color" />
- <java-symbol type="color" name="decor_button_light_color" />
<java-symbol type="array" name="unloggable_phone_numbers" />
<!-- From TelephonyProvider -->
@@ -4470,8 +4458,6 @@
<java-symbol type="string" name="accessibility_system_action_dpad_right_label" />
<java-symbol type="string" name="accessibility_system_action_dpad_center_label" />
- <java-symbol type="string" name="accessibility_freeform_caption" />
-
<!-- For Wide Color Gamut -->
<java-symbol type="bool" name="config_enableWcgMode" />
diff --git a/core/tests/coretests/OWNERS b/core/tests/coretests/OWNERS
index b7e008b..b669e3b 100644
--- a/core/tests/coretests/OWNERS
+++ b/core/tests/coretests/OWNERS
@@ -3,3 +3,4 @@
per-file BinderTest.java = file:platform/frameworks/native:/libs/binder/OWNERS
per-file ParcelTest.java = file:platform/frameworks/native:/libs/binder/OWNERS
per-file SurfaceControlRegistryTests.java = file:/services/core/java/com/android/server/wm/OWNERS
+per-file VintfObjectTest.java = file:platform/system/libvintf:/OWNERS
diff --git a/core/tests/coretests/src/android/view/ViewFrameRateTest.java b/core/tests/coretests/src/android/view/ViewFrameRateTest.java
index 0b1b40c..07446e7 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.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 @@
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/core.protolog.pb b/data/etc/core.protolog.pb
index ddb706e..a105ba7 100644
--- a/data/etc/core.protolog.pb
+++ b/data/etc/core.protolog.pb
Binary files differ
diff --git a/data/etc/preinstalled-packages-platform.xml b/data/etc/preinstalled-packages-platform.xml
index f9fb84d..7823277 100644
--- a/data/etc/preinstalled-packages-platform.xml
+++ b/data/etc/preinstalled-packages-platform.xml
@@ -134,19 +134,4 @@
<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/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 80f143c..db68f95 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -2035,6 +2035,24 @@
"group": "WM_DEBUG_WINDOW_TRANSITIONS",
"at": "com\/android\/server\/wm\/PhysicalDisplaySwitchTransitionLauncher.java"
},
+ "-1640401313436844534": {
+ "message": "Resetting frozen recents task list reason=app touch win=%s x=%d y=%d insetFrame=%s",
+ "level": "INFO",
+ "group": "WM_DEBUG_TASKS",
+ "at": "com\/android\/server\/wm\/RecentTasks.java"
+ },
+ "-8803811426486764449": {
+ "message": "Setting frozen recents task list",
+ "level": "INFO",
+ "group": "WM_DEBUG_TASKS",
+ "at": "com\/android\/server\/wm\/RecentTasks.java"
+ },
+ "4040735335719974079": {
+ "message": "Resetting frozen recents task list reason=timeout",
+ "level": "INFO",
+ "group": "WM_DEBUG_TASKS",
+ "at": "com\/android\/server\/wm\/RecentTasks.java"
+ },
"3308140128142966415": {
"message": "remove RecentTask %s when finishing user %d",
"level": "INFO",
diff --git a/graphics/java/android/graphics/RenderNode.java b/graphics/java/android/graphics/RenderNode.java
index 0650b78..211f74a 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 interface AnimationHost {
/** @hide */
- void registerAnimatingRenderNode(RenderNode animator);
+ void registerAnimatingRenderNode(RenderNode renderNode, Animator animator);
/** @hide */
void registerVectorDrawableAnimator(NativeVectorDrawableAnimator animator);
@@ -1654,7 +1655,7 @@
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 55f205b..d4bb461 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -1266,6 +1266,7 @@
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 @@
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 @@
if (mListener != null) {
mListener.onAnimationStart(null);
}
+ if (mThreadedRendererAnimatorListener != null) {
+ mThreadedRendererAnimatorListener.onAnimationStart(null);
+ }
}
@Override
@@ -1725,6 +1732,11 @@
}
@Override
+ public void setThreadedRendererAnimatorListener(AnimatorListener animatorListener) {
+ mThreadedRendererAnimatorListener = animatorListener;
+ }
+
+ @Override
public boolean canReverse() {
return mIsReversible;
}
@@ -1788,6 +1800,9 @@
if (mListener != null) {
mListener.onAnimationEnd(null);
}
+ if (mThreadedRendererAnimatorListener != null) {
+ mThreadedRendererAnimatorListener.onAnimationEnd(null);
+ }
}
// onFinished: should be called from native
diff --git a/ktfmt_includes.txt b/ktfmt_includes.txt
deleted file mode 100644
index 0ac6265..0000000
--- a/ktfmt_includes.txt
+++ /dev/null
@@ -1,740 +0,0 @@
-+services/permission
-+packages/SystemUI
--packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt
--packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt
--packages/SystemUI/checks/src/com/android/internal/systemui/lint/BroadcastSentViaContextDetector.kt
--packages/SystemUI/checks/src/com/android/internal/systemui/lint/RegisterReceiverViaContextDetector.kt
--packages/SystemUI/checks/src/com/android/internal/systemui/lint/SoftwareBitmapDetector.kt
--packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
--packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/View.kt
--packages/SystemUI/shared/src/com/android/systemui/flags/Flag.kt
--packages/SystemUI/shared/src/com/android/systemui/flags/FlagListenable.kt
--packages/SystemUI/shared/src/com/android/systemui/flags/FlagManager.kt
--packages/SystemUI/shared/src/com/android/systemui/flags/FlagSerializer.kt
--packages/SystemUI/shared/src/com/android/systemui/flags/FlagSettingsHelper.kt
--packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimator.kt
--packages/SystemUI/shared/src/com/android/systemui/shared/regionsampling/RegionDarkness.kt
--packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButtonPositionCalculator.kt
--packages/SystemUI/shared/src/com/android/systemui/shared/system/UncaughtExceptionPreHandlerManager.kt
--packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/SmartspaceState.kt
--packages/SystemUI/shared/src/com/android/systemui/unfold/system/ActivityManagerActivityTypeProvider.kt
--packages/SystemUI/shared/src/com/android/systemui/unfold/system/DeviceStateManagerFoldProvider.kt
--packages/SystemUI/shared/src/com/android/systemui/unfold/system/SystemUnfoldSharedModule.kt
--packages/SystemUI/src-debug/com/android/systemui/flags/FlagsModule.kt
--packages/SystemUI/src-release/com/android/systemui/flags/FlagsModule.kt
--packages/SystemUI/src/com/android/keyguard/ActiveUnlockConfig.kt
--packages/SystemUI/src/com/android/keyguard/BouncerPanelExpansionCalculator.kt
--packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
--packages/SystemUI/src/com/android/keyguard/KeyguardBiometricLockoutLogger.kt
--packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt
--packages/SystemUI/src/com/android/keyguard/KeyguardUserSwitcherAnchor.kt
--packages/SystemUI/src/com/android/keyguard/clock/ClockPalette.kt
--packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
--packages/SystemUI/src/com/android/keyguard/mediator/ScreenOnCoordinator.kt
--packages/SystemUI/src/com/android/systemui/BootCompleteCache.kt
--packages/SystemUI/src/com/android/systemui/BootCompleteCacheImpl.kt
--packages/SystemUI/src/com/android/systemui/CameraAvailabilityListener.kt
--packages/SystemUI/src/com/android/systemui/ChooserSelector.kt
--packages/SystemUI/src/com/android/systemui/DarkReceiverImpl.kt
--packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt
--packages/SystemUI/src/com/android/systemui/DualToneHandler.kt
--packages/SystemUI/src/com/android/systemui/FaceScanningOverlay.kt
--packages/SystemUI/src/com/android/systemui/ScreenDecorHwcLayer.kt
--packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactoryBase.kt
--packages/SystemUI/src/com/android/systemui/SystemUIInitializerFactory.kt
--packages/SystemUI/src/com/android/systemui/SystemUIInitializerImpl.kt
--packages/SystemUI/src/com/android/systemui/assist/AssistLogger.kt
--packages/SystemUI/src/com/android/systemui/assist/AssistantInvocationEvent.kt
--packages/SystemUI/src/com/android/systemui/assist/AssistantSessionEvent.kt
--packages/SystemUI/src/com/android/systemui/backup/BackupHelper.kt
--packages/SystemUI/src/com/android/systemui/biometrics/AlternateUdfpsTouchProvider.kt
--packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceIconController.kt
--packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.kt
--packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceIconController.kt
--packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceView.kt
--packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
--packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.kt
--packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
--packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
--packages/SystemUI/src/com/android/systemui/biometrics/BiometricDisplayListener.kt
--packages/SystemUI/src/com/android/systemui/biometrics/DwellRippleShader.kt
--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt
--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpView.kt
--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.kt
--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDrawable.kt
--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpDrawable.kt
--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmEmptyView.kt
--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmEmptyViewController.kt
--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsHapticsSimulator.kt
--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsShell.kt
--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.kt
--packages/SystemUI/src/com/android/systemui/biometrics/Utils.kt
--packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt
--packages/SystemUI/src/com/android/systemui/broadcast/ActionReceiver.kt
--packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt
--packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcherStartable.kt
--packages/SystemUI/src/com/android/systemui/broadcast/BroadcastSender.kt
--packages/SystemUI/src/com/android/systemui/broadcast/PendingRemovalStore.kt
--packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt
--packages/SystemUI/src/com/android/systemui/broadcast/logging/BroadcastDispatcherLogger.kt
--packages/SystemUI/src/com/android/systemui/camera/CameraGestureHelper.kt
--packages/SystemUI/src/com/android/systemui/charging/WiredChargingRippleController.kt
--packages/SystemUI/src/com/android/systemui/controls/ControlStatus.kt
--packages/SystemUI/src/com/android/systemui/controls/ControlsMetricsLogger.kt
--packages/SystemUI/src/com/android/systemui/controls/ControlsMetricsLoggerImpl.kt
--packages/SystemUI/src/com/android/systemui/controls/ControlsServiceInfo.kt
--packages/SystemUI/src/com/android/systemui/controls/CustomIconCache.kt
--packages/SystemUI/src/com/android/systemui/controls/TooltipManager.kt
--packages/SystemUI/src/com/android/systemui/controls/controller/ControlInfo.kt
--packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingController.kt
--packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt
--packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt
--packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
--packages/SystemUI/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapper.kt
--packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt
--packages/SystemUI/src/com/android/systemui/controls/controller/ControlsTileResourceConfiguration.kt
--packages/SystemUI/src/com/android/systemui/controls/controller/ControlsTileResourceConfigurationImpl.kt
--packages/SystemUI/src/com/android/systemui/controls/controller/ServiceWrapper.kt
--packages/SystemUI/src/com/android/systemui/controls/controller/StatefulControlSubscriber.kt
--packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsComponent.kt
--packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsFeatureEnabled.kt
--packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt
--packages/SystemUI/src/com/android/systemui/controls/management/AllModel.kt
--packages/SystemUI/src/com/android/systemui/controls/management/AppAdapter.kt
--packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
--packages/SystemUI/src/com/android/systemui/controls/management/ControlsAnimations.kt
--packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt
--packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
--packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingController.kt
--packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt
--packages/SystemUI/src/com/android/systemui/controls/management/ControlsModel.kt
--packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt
--packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestDialog.kt
--packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestReceiver.kt
--packages/SystemUI/src/com/android/systemui/controls/management/FavoritesModel.kt
--packages/SystemUI/src/com/android/systemui/controls/management/ManagementPageIndicator.kt
--packages/SystemUI/src/com/android/systemui/controls/management/StructureAdapter.kt
--packages/SystemUI/src/com/android/systemui/controls/start/ControlsStartable.kt
--packages/SystemUI/src/com/android/systemui/controls/ui/Behavior.kt
--packages/SystemUI/src/com/android/systemui/controls/ui/ChallengeDialogs.kt
--packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt
--packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
--packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
--packages/SystemUI/src/com/android/systemui/controls/ui/ControlWithState.kt
--packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt
--packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt
--packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
--packages/SystemUI/src/com/android/systemui/controls/ui/CornerDrawable.kt
--packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
--packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt
--packages/SystemUI/src/com/android/systemui/controls/ui/StatusBehavior.kt
--packages/SystemUI/src/com/android/systemui/controls/ui/TemperatureControlBehavior.kt
--packages/SystemUI/src/com/android/systemui/controls/ui/ThumbnailBehavior.kt
--packages/SystemUI/src/com/android/systemui/controls/ui/ToggleBehavior.kt
--packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
--packages/SystemUI/src/com/android/systemui/controls/ui/TouchBehavior.kt
--packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
--packages/SystemUI/src/com/android/systemui/decor/CutoutDecorProviderFactory.kt
--packages/SystemUI/src/com/android/systemui/decor/CutoutDecorProviderImpl.kt
--packages/SystemUI/src/com/android/systemui/decor/DecorProvider.kt
--packages/SystemUI/src/com/android/systemui/decor/DecorProviderFactory.kt
--packages/SystemUI/src/com/android/systemui/decor/FaceScanningProviderFactory.kt
--packages/SystemUI/src/com/android/systemui/decor/OverlayWindow.kt
--packages/SystemUI/src/com/android/systemui/decor/PrivacyDotDecorProviderFactory.kt
--packages/SystemUI/src/com/android/systemui/decor/RoundedCornerDecorProviderFactory.kt
--packages/SystemUI/src/com/android/systemui/decor/RoundedCornerDecorProviderImpl.kt
--packages/SystemUI/src/com/android/systemui/decor/RoundedCornerResDelegate.kt
--packages/SystemUI/src/com/android/systemui/demomode/DemoModeAvailabilityTracker.kt
--packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt
--packages/SystemUI/src/com/android/systemui/doze/util/BurnInHelper.kt
--packages/SystemUI/src/com/android/systemui/dreams/smartspace/DreamSmartspaceController.kt
--packages/SystemUI/src/com/android/systemui/dump/DumpHandler.kt
--packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt
--packages/SystemUI/src/com/android/systemui/dump/DumpsysTableLogger.kt
--packages/SystemUI/src/com/android/systemui/dump/LogBufferEulogizer.kt
--packages/SystemUI/src/com/android/systemui/dump/LogBufferFreezer.kt
--packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.kt
--packages/SystemUI/src/com/android/systemui/flags/Flags.kt
--packages/SystemUI/src/com/android/systemui/flags/ServerFlagReader.kt
--packages/SystemUI/src/com/android/systemui/flags/SystemPropertiesHelper.kt
--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
--packages/SystemUI/src/com/android/systemui/keyguard/LifecycleScreenStatusProvider.kt
--packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceConfig.kt
--packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceCoreStartable.kt
--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt
--packages/SystemUI/src/com/android/systemui/log/LogBufferFactory.kt
--packages/SystemUI/src/com/android/systemui/media/MediaProjectionCaptureTarget.kt
--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogFactory.kt
--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt
--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogReceiver.kt
--packages/SystemUI/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionCli.kt
--packages/SystemUI/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManager.kt
--packages/SystemUI/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManagerFactory.kt
--packages/SystemUI/src/com/android/systemui/media/muteawait/MediaMuteAwaitLogger.kt
--packages/SystemUI/src/com/android/systemui/media/nearby/NearbyMediaDevicesLogger.kt
--packages/SystemUI/src/com/android/systemui/media/nearby/NearbyMediaDevicesManager.kt
--packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt
--packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttFlags.kt
--packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ChipStateReceiver.kt
--packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
--packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ReceiverChipRippleView.kt
--packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt
--packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderUiEventLogger.kt
--packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorResultHandler.kt
--packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewController.kt
--packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionTaskView.kt
--packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/RecentTasksAdapter.kt
--packages/SystemUI/src/com/android/systemui/mediaprojection/devicepolicy/ScreenCaptureDevicePolicyResolver.kt
--packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanel.kt
--packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt
--packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgePanelParams.kt
--packages/SystemUI/src/com/android/systemui/notetask/NoteTaskEventLogger.kt
--packages/SystemUI/src/com/android/systemui/power/BatteryStateSnapshot.kt
--packages/SystemUI/src/com/android/systemui/privacy/AppOpsPrivacyItemMonitor.kt
--packages/SystemUI/src/com/android/systemui/privacy/MediaProjectionPrivacyItemMonitor.kt
--packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt
--packages/SystemUI/src/com/android/systemui/privacy/PrivacyChipBuilder.kt
--packages/SystemUI/src/com/android/systemui/privacy/PrivacyChipEvent.kt
--packages/SystemUI/src/com/android/systemui/privacy/PrivacyConfig.kt
--packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialog.kt
--packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt
--packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogEvent.kt
--packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt
--packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
--packages/SystemUI/src/com/android/systemui/privacy/logging/PrivacyLogger.kt
--packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.kt
--packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt
--packages/SystemUI/src/com/android/systemui/qs/HeaderPrivacyIconsController.kt
--packages/SystemUI/src/com/android/systemui/qs/QSEvents.kt
--packages/SystemUI/src/com/android/systemui/qs/QSExpansionPathInterpolator.kt
--packages/SystemUI/src/com/android/systemui/qs/QSFragmentDisableFlagsLogger.kt
--packages/SystemUI/src/com/android/systemui/qs/QSSquishinessController.kt
--packages/SystemUI/src/com/android/systemui/qs/QSUtils.kt
--packages/SystemUI/src/com/android/systemui/qs/SideLabelTileLayout.kt
--packages/SystemUI/src/com/android/systemui/qs/VisibilityChangedDispatcher.kt
--packages/SystemUI/src/com/android/systemui/qs/carrier/CellSignalState.kt
--packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.kt
--packages/SystemUI/src/com/android/systemui/qs/external/CustomTileStatePersister.kt
--packages/SystemUI/src/com/android/systemui/qs/external/QSExternalModule.kt
--packages/SystemUI/src/com/android/systemui/qs/external/TileRequestDialog.kt
--packages/SystemUI/src/com/android/systemui/qs/external/TileRequestDialogEventLogger.kt
--packages/SystemUI/src/com/android/systemui/qs/external/TileServiceRequestController.kt
--packages/SystemUI/src/com/android/systemui/qs/tileimpl/HeightOverrideable.kt
--packages/SystemUI/src/com/android/systemui/qs/tileimpl/IgnorableChildLinearLayout.kt
--packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
--packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.kt
--packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt
--packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt
--packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt
--packages/SystemUI/src/com/android/systemui/screenshot/ImageCaptureImpl.kt
--packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt
--packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotPolicy.kt
--packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotPolicyImpl.kt
--packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotProxyService.kt
--packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseDialog.kt
--packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt
--packages/SystemUI/src/com/android/systemui/settings/UserContentResolverProvider.kt
--packages/SystemUI/src/com/android/systemui/settings/UserContextProvider.kt
--packages/SystemUI/src/com/android/systemui/settings/UserFileManager.kt
--packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt
--packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
--packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessMirrorHandler.kt
--packages/SystemUI/src/com/android/systemui/settings/brightness/MirroredBrightnessController.kt
--packages/SystemUI/src/com/android/systemui/shade/CombinedShadeHeadersConstraintManager.kt
--packages/SystemUI/src/com/android/systemui/shade/CombinedShadeHeadersConstraintManagerImpl.kt
--packages/SystemUI/src/com/android/systemui/shade/NPVCDownEventState.kt
--packages/SystemUI/src/com/android/systemui/shade/NotificationPanelUnfoldAnimationController.kt
--packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt
--packages/SystemUI/src/com/android/systemui/shade/PulsingGestureListener.kt
--packages/SystemUI/src/com/android/systemui/shade/ShadeHeightLogger.kt
--packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt
--packages/SystemUI/src/com/android/systemui/shade/ShadeWindowLogger.kt
--packages/SystemUI/src/com/android/systemui/shade/transition/ScrimShadeTransitionController.kt
--packages/SystemUI/src/com/android/systemui/shade/transition/ShadeTransitionController.kt
--packages/SystemUI/src/com/android/systemui/smartspace/SmartspacePrecondition.kt
--packages/SystemUI/src/com/android/systemui/smartspace/SmartspaceTargetFilter.kt
--packages/SystemUI/src/com/android/systemui/smartspace/dagger/SmartspaceModule.kt
--packages/SystemUI/src/com/android/systemui/smartspace/dagger/SmartspaceViewComponent.kt
--packages/SystemUI/src/com/android/systemui/smartspace/filters/LockscreenAndDreamTargetFilter.kt
--packages/SystemUI/src/com/android/systemui/smartspace/preconditions/LockscreenPrecondition.kt
--packages/SystemUI/src/com/android/systemui/statusbar/AbstractLockscreenShadeTransitionController.kt
--packages/SystemUI/src/com/android/systemui/statusbar/ActionClickLogger.kt
--packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt
--packages/SystemUI/src/com/android/systemui/statusbar/LockScreenShadeOverScroller.kt
--packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeKeyguardTransitionController.kt
--packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeScrimTransitionController.kt
--packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
--packages/SystemUI/src/com/android/systemui/statusbar/MediaArtworkProcessor.kt
--packages/SystemUI/src/com/android/systemui/statusbar/NotificationClickNotifier.kt
--packages/SystemUI/src/com/android/systemui/statusbar/NotificationInteractionTracker.kt
--packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
--packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
--packages/SystemUI/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScroller.kt
--packages/SystemUI/src/com/android/systemui/statusbar/SplitShadeLockScreenOverScroller.kt
--packages/SystemUI/src/com/android/systemui/statusbar/commandline/CommandRegistry.kt
--packages/SystemUI/src/com/android/systemui/statusbar/connectivity/AccessPointController.kt
--packages/SystemUI/src/com/android/systemui/statusbar/connectivity/ConnectivityState.kt
--packages/SystemUI/src/com/android/systemui/statusbar/connectivity/MobileSignalControllerFactory.kt
--packages/SystemUI/src/com/android/systemui/statusbar/connectivity/MobileState.kt
--packages/SystemUI/src/com/android/systemui/statusbar/connectivity/MobileStatusTrackerFactory.kt
--packages/SystemUI/src/com/android/systemui/statusbar/connectivity/SignalCallback.kt
--packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiState.kt
--packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiStatusTrackerFactory.kt
--packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializer.kt
--packages/SystemUI/src/com/android/systemui/statusbar/dagger/StartCentralSurfacesModule.kt
--packages/SystemUI/src/com/android/systemui/statusbar/disableflags/DisableFlagsLogger.kt
--packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt
--packages/SystemUI/src/com/android/systemui/statusbar/events/StatusBarEventsModule.kt
--packages/SystemUI/src/com/android/systemui/statusbar/events/StatusEvent.kt
--packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt
--packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventCoordinator.kt
--packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt
--packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImpl.kt
--packages/SystemUI/src/com/android/systemui/statusbar/gesture/GesturePointerEventDetector.kt
--packages/SystemUI/src/com/android/systemui/statusbar/gesture/GenericGestureDetector.kt
--packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeUpGestureHandler.kt
--packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeUpGestureLogger.kt
--packages/SystemUI/src/com/android/systemui/statusbar/gesture/TapGestureDetector.kt
--packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/FeedbackIcon.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/LaunchAnimationParameters.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotifPipelineFlags.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClickerLogger.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/ViewGroupFadeHelper.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListAttachState.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataStoreImpl.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipelineChoreographer.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/PipelineDumper.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/SuppressedAttachState.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/TargetSdkResolver.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerLogger.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DataStoreCoordinator.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DebugModeCoordinator.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GroupCountCoordinator.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinator.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorLogger.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorLogger.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorLogger.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RemoteInputCoordinator.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinator.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinator.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorLogger.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinator.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/dagger/CoordinatorsModule.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/BindEventManager.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/BindEventManagerImpl.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifInflater.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustment.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProvider.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifSection.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifStabilityManager.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionInconsistencyTracker.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifEvent.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/SelfTrackingLifetimeExtender.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/DebugModeFilterProvider.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/NotificationVisibilityProviderImpl.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/SectionHeaderVisibilityProvider.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/SectionStyleProvider.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/MediaContainerController.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeController.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilder.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderLogger.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifGroupController.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifGutsViewListener.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifGutsViewManager.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifRowController.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifShadeEventSource.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifStackController.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewBarn.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewController.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewRenderer.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotificationVisibilityProvider.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RenderExtensions.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RenderStageManager.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RootNodeController.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/SectionHeaderController.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDiffer.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferLogger.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationSectionHeadersModule.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconBuilder.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderLogger.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProvider.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryViewWalker.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/people/NotificationPersonExtractor.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/people/ViewPipeline.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorListView.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineLogger.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStageLogger.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/RemoteInputViewModule.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCallTemplateViewWrapper.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MediaContainerView.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationPriorityBucket.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsLogger.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLogger.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt
--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateLogger.kt
--packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt
--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaViewController.kt
--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
--packages/SystemUI/src/com/android/systemui/statusbar/phone/LSShadeTransitionLogger.kt
--packages/SystemUI/src/com/android/systemui/statusbar/phone/LetterboxAppearanceCalculator.kt
--packages/SystemUI/src/com/android/systemui/statusbar/phone/LetterboxBackgroundProvider.kt
--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScreenOffAnimationController.kt
--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt
--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHideIconsForBouncerManager.kt
--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLaunchAnimatorController.kt
--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLocationPublisher.kt
--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationController.kt
--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterLogger.kt
--packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemBarAttributesListener.kt
--packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
--packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLogger.kt
--packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarIconBlocklist.kt
--packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarSystemEventAnimator.kt
--packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallChronometer.kt
--packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
--packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallFlags.kt
--packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallLogger.kt
--packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherContainer.kt
--packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryStateNotifier.kt
--packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceControlsController.kt
--packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceControlsControllerImpl.kt
--packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.kt
--packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerLogger.kt
--packages/SystemUI/src/com/android/systemui/statusbar/policy/InflatedSmartReplyState.kt
--packages/SystemUI/src/com/android/systemui/statusbar/policy/InflatedSmartReplyViewHolder.kt
--packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisabler.kt
--packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputViewController.kt
--packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyStateInflater.kt
--packages/SystemUI/src/com/android/systemui/statusbar/policy/VariableDateView.kt
--packages/SystemUI/src/com/android/systemui/statusbar/policy/VariableDateViewController.kt
--packages/SystemUI/src/com/android/systemui/statusbar/policy/WalletController.kt
--packages/SystemUI/src/com/android/systemui/statusbar/policy/WalletControllerImpl.kt
--packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/RemoteInput.kt
--packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/SmartRepliesInflationModule.kt
--packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowModule.kt
--packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowStateController.kt
--packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt
--packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewInfo.kt
--packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarRootView.kt
--packages/SystemUI/src/com/android/systemui/toast/ToastDefaultAnimation.kt
--packages/SystemUI/src/com/android/systemui/toast/ToastLogger.kt
--packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt
--packages/SystemUI/src/com/android/systemui/unfold/FoldStateLogger.kt
--packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt
--packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt
--packages/SystemUI/src/com/android/systemui/unfold/UnfoldProgressProvider.kt
--packages/SystemUI/src/com/android/systemui/user/UserSwitcherPopupMenu.kt
--packages/SystemUI/src/com/android/systemui/user/UserSwitcherRootView.kt
--packages/SystemUI/src/com/android/systemui/util/AsyncActivityLauncher.kt
--packages/SystemUI/src/com/android/systemui/util/ColorUtil.kt
--packages/SystemUI/src/com/android/systemui/util/ConvenienceExtensions.kt
--packages/SystemUI/src/com/android/systemui/util/DelayableMarqueeTextView.kt
--packages/SystemUI/src/com/android/systemui/util/DumpUtils.kt
--packages/SystemUI/src/com/android/systemui/util/InitializationChecker.kt
--packages/SystemUI/src/com/android/systemui/util/LargeScreenUtils.kt
--packages/SystemUI/src/com/android/systemui/util/ListenerSet.kt
--packages/SystemUI/src/com/android/systemui/util/NeverExactlyLinearLayout.kt
--packages/SystemUI/src/com/android/systemui/util/NoRemeasureMotionLayout.kt
--packages/SystemUI/src/com/android/systemui/util/PluralMessageFormater.kt
--packages/SystemUI/src/com/android/systemui/util/RingerModeTracker.kt
--packages/SystemUI/src/com/android/systemui/util/RingerModeTrackerImpl.kt
--packages/SystemUI/src/com/android/systemui/util/RoundedCornerProgressDrawable.kt
--packages/SystemUI/src/com/android/systemui/util/SafeMarqueeTextView.kt
--packages/SystemUI/src/com/android/systemui/util/SparseArrayUtils.kt
--packages/SystemUI/src/com/android/systemui/util/TraceUtils.kt
--packages/SystemUI/src/com/android/systemui/util/UserAwareController.kt
--packages/SystemUI/src/com/android/systemui/util/WallpaperController.kt
--packages/SystemUI/src/com/android/systemui/util/animation/AnimationUtil.kt
--packages/SystemUI/src/com/android/systemui/util/animation/MeasurementInput.kt
--packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayout.kt
--packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayoutController.kt
--packages/SystemUI/src/com/android/systemui/util/animation/UniqueObjectHostView.kt
--packages/SystemUI/src/com/android/systemui/util/concurrency/Execution.kt
--packages/SystemUI/src/com/android/systemui/util/concurrency/PendingTasksContainer.kt
--packages/SystemUI/src/com/android/systemui/util/drawable/DrawableSize.kt
--packages/SystemUI/src/com/android/systemui/util/kotlin/CoroutinesModule.kt
--packages/SystemUI/src/com/android/systemui/util/kotlin/Flow.kt
--packages/SystemUI/src/com/android/systemui/util/kotlin/IpcSerializer.kt
--packages/SystemUI/src/com/android/systemui/util/kotlin/nullability.kt
--packages/SystemUI/src/com/android/systemui/util/recycler/HorizontalSpacerItemDecoration.kt
--packages/SystemUI/src/com/android/systemui/util/view/ViewUtil.kt
--packages/SystemUI/src/com/android/systemui/util/wrapper/RotationPolicyWrapper.kt
--packages/SystemUI/src/com/android/systemui/volume/VolumePanelDialogReceiver.kt
--packages/SystemUI/src/com/android/systemui/volume/VolumePanelFactory.kt
--packages/SystemUI/tests/src/com/android/keyguard/ActiveUnlockConfigTest.kt
--packages/SystemUI/tests/src/com/android/keyguard/BouncerPanelExpansionCalculatorTest.kt
--packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
--packages/SystemUI/tests/src/com/android/keyguard/KeyguardBiometricLockoutLoggerTest.kt
--packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt
--packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
--packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.kt
--packages/SystemUI/tests/src/com/android/keyguard/KeyguardUserSwitcherAnchorTest.kt
--packages/SystemUI/tests/src/com/android/keyguard/clock/ClockPaletteTest.kt
--packages/SystemUI/tests/src/com/android/keyguard/clock/ViewPreviewerTest.kt
--packages/SystemUI/tests/src/com/android/keyguard/mediator/ScreenOnCoordinatorTest.kt
--packages/SystemUI/tests/src/com/android/systemui/BootCompleteCacheTest.kt
--packages/SystemUI/tests/src/com/android/systemui/ChooserSelectorTest.kt
--packages/SystemUI/tests/src/com/android/systemui/DisplayCutoutBaseViewTest.kt
--packages/SystemUI/tests/src/com/android/systemui/InstanceIdSequenceFake.kt
--packages/SystemUI/tests/src/com/android/systemui/ScreenDecorHwcLayerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/animation/DialogTransitionAnimatorTest.kt
--packages/SystemUI/tests/src/com/android/systemui/animation/FontInterpolatorTest.kt
--packages/SystemUI/tests/src/com/android/systemui/animation/GhostedViewTransitionAnimatorControllerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/animation/TextAnimatorTest.kt
--packages/SystemUI/tests/src/com/android/systemui/animation/TextInterpolatorTest.kt
--packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt
--packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewTest.kt
--packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceViewTest.kt
--packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintViewTest.kt
--packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
--packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
--packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt
--packages/SystemUI/tests/src/com/android/systemui/broadcast/ActionReceiverTest.kt
--packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt
--packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastSenderTest.kt
--packages/SystemUI/tests/src/com/android/systemui/broadcast/PendingRemovalStoreTest.kt
--packages/SystemUI/tests/src/com/android/systemui/broadcast/UserBroadcastDispatcherTest.kt
--packages/SystemUI/tests/src/com/android/systemui/camera/CameraGestureHelperTest.kt
--packages/SystemUI/tests/src/com/android/systemui/camera/CameraIntentsTest.kt
--packages/SystemUI/tests/src/com/android/systemui/charging/WiredChargingRippleControllerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/controls/CustomIconCacheTest.kt
--packages/SystemUI/tests/src/com/android/systemui/controls/controller/AuxiliaryPersistenceWrapperTest.kt
--packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt
--packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt
--packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt
--packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapperTest.kt
--packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsTileResourceConfigurationImplTest.kt
--packages/SystemUI/tests/src/com/android/systemui/controls/controller/ServiceWrapperTest.kt
--packages/SystemUI/tests/src/com/android/systemui/controls/controller/StatefulControlSubscriberTest.kt
--packages/SystemUI/tests/src/com/android/systemui/controls/dagger/ControlsComponentTest.kt
--packages/SystemUI/tests/src/com/android/systemui/controls/management/AllModelTest.kt
--packages/SystemUI/tests/src/com/android/systemui/controls/management/AppAdapterTest.kt
--packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt
--packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsRequestDialogTest.kt
--packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsRequestReceiverTest.kt
--packages/SystemUI/tests/src/com/android/systemui/controls/management/FavoritesModelTest.kt
--packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlViewHolderTest.kt
--packages/SystemUI/tests/src/com/android/systemui/controls/ui/DetailDialogTest.kt
--packages/SystemUI/tests/src/com/android/systemui/decor/CutoutDecorProviderFactoryTest.kt
--packages/SystemUI/tests/src/com/android/systemui/decor/OverlayWindowTest.kt
--packages/SystemUI/tests/src/com/android/systemui/decor/PrivacyDotDecorProviderFactoryTest.kt
--packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerDecorProviderFactoryTest.kt
--packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt
--packages/SystemUI/tests/src/com/android/systemui/dump/DumpHandlerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/dump/DumpsysTableLoggerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/dump/LogBufferFreezerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/dump/LogBufferHelper.kt
--packages/SystemUI/tests/src/com/android/systemui/dump/LogEulogizerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt
--packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsReleaseTest.kt
--packages/SystemUI/tests/src/com/android/systemui/flags/FlagManagerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceConfigTest.kt
--packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceCoreStartableTest.kt
--packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepositoryTest.kt
--packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt
--packages/SystemUI/tests/src/com/android/systemui/lifecycle/InstantTaskExecutorRule.kt
--packages/SystemUI/tests/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManagerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/media/nearby/NearbyMediaDevicesManagerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt
--packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt
--packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderUiEventLoggerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/navigationbar/TaskbarDelegateTest.kt
--packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/FloatingRotationButtonPositionCalculatorTest.kt
--packages/SystemUI/tests/src/com/android/systemui/privacy/AppOpsPrivacyItemMonitorTest.kt
--packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyChipBuilderTest.kt
--packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyConfigFlagsTest.kt
--packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogTest.kt
--packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/qs/HeaderPrivacyIconsControllerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/qs/QSContainerImplTest.kt
--packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentDisableFlagsLoggerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelSwitchToParentTest.kt
--packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt
--packages/SystemUI/tests/src/com/android/systemui/qs/QSSquishinessControllerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelTest.kt
--packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/qs/SettingObserverTest.kt
--packages/SystemUI/tests/src/com/android/systemui/qs/carrier/CellSignalStateTest.kt
--packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileStatePersisterTest.kt
--packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt
--packages/SystemUI/tests/src/com/android/systemui/qs/external/TileRequestDialogEventLoggerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/qs/external/TileRequestDialogTest.kt
--packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceRequestControllerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSFactoryImplTest.kt
--packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileViewImplTest.kt
--packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/ResourceIconTest.kt
--packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/TilesStatesTextTest.kt
--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/AirplaneModeTileTest.kt
--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/AlarmTileTest.kt
--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt
--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt
--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CameraToggleTileTest.kt
--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt
--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DndTileTest.kt
--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/LocationTileTest.kt
--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/MicrophoneToggleTileTest.kt
--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/NightDisplayTileTest.kt
--packages/SystemUI/tests/src/com/android/systemui/qs/user/UserSwitchDialogControllerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordDialogTest.kt
--packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotPolicyImplTest.kt
--packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt
--packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessSliderControllerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/shade/CombinedShadeHeaderConstraintsTest.kt
--packages/SystemUI/tests/src/com/android/systemui/shade/NotificationQSContainerControllerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/shade/transition/ScrimShadeTransitionControllerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/shade/transition/ShadeTransitionControllerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimatorTest.kt
--packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimatorTest.kt
--packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
--packages/SystemUI/tests/src/com/android/systemui/shared/navigationbar/RegionSamplingHelperTest.kt
--packages/SystemUI/tests/src/com/android/systemui/shared/rotation/RotationButtonControllerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/smartspace/DreamSmartspaceControllerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/smartspace/LockscreenAndDreamTargetFilterTest.kt
--packages/SystemUI/tests/src/com/android/systemui/smartspace/LockscreenPreconditionTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/BlurUtilsTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/DragDownHelperTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/LSShadeTransitionLoggerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/LightRevealScrimTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/MediaArtworkProcessorTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScrollerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/SplitShadeLockScreenOverScrollerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateEventTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/VibratorHelperTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/commandline/CommandRegistryTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImplTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/DisableFlagsLoggerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/DisableStateTrackerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/gesture/GenericGestureDetectorTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorControllerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManagerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataImplTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataStoreImplTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifPipelineChoreographerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/TargetSdkResolverTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DataStoreCoordinatorTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GroupCountCoordinatorTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RemoteInputCoordinatorTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinatorTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinatorTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinatorTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProviderTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionInconsistencyTrackerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/SelfTrackingLifetimeExtenderTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/provider/VisualStabilityProviderTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/RenderStageManagerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/IconManagerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogControllerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/MediaContainerViewTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ConfigurationControllerImplTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/FoldStateListenerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LetterboxAppearanceCalculatorTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LetterboxBackgroundProviderTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationControllerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemBarAttributesListenerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLoggerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallChronometerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallLoggerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryStateNotifierTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ClockTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceControlsControllerImplTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImplTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/FlashlightControllerImplTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchControllerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisablerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SafetyControllerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/VariableDateViewControllerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/WalletControllerImplTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/window/StatusBarWindowStateControllerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/unfold/FoldStateLoggingProviderTest.kt
--packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldLatencyTrackerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldTransitionWallpaperControllerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/unfold/config/ResourceUnfoldTransitionConfigTest.kt
--packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt
--packages/SystemUI/tests/src/com/android/systemui/unfold/util/FoldableTestUtils.kt
--packages/SystemUI/tests/src/com/android/systemui/unfold/util/ScaleAwareUnfoldProgressProviderTest.kt
--packages/SystemUI/tests/src/com/android/systemui/unfold/util/TestFoldStateProvider.kt
--packages/SystemUI/tests/src/com/android/systemui/usb/UsbPermissionActivityTest.kt
--packages/SystemUI/tests/src/com/android/systemui/user/UserCreatorTest.kt
--packages/SystemUI/tests/src/com/android/systemui/util/FakeSharedPreferencesTest.kt
--packages/SystemUI/tests/src/com/android/systemui/util/FloatingContentCoordinatorTest.kt
--packages/SystemUI/tests/src/com/android/systemui/util/ListenerSetTest.kt
--packages/SystemUI/tests/src/com/android/systemui/util/RingerModeLiveDataTest.kt
--packages/SystemUI/tests/src/com/android/systemui/util/WallpaperControllerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/util/animation/AnimationUtilTest.kt
--packages/SystemUI/tests/src/com/android/systemui/util/drawable/DrawableSizeTest.kt
--packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt
--packages/SystemUI/tests/src/com/android/systemui/util/kotlin/IpcSerializerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/util/kotlin/SuspendUtilTests.kt
--packages/SystemUI/tests/src/com/android/systemui/util/view/ViewUtilTest.kt
--packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt
--packages/SystemUI/tests/utils/src/com/android/systemui/util/FakeSharedPreferences.kt
--packages/SystemUI/tests/utils/src/com/android/systemui/util/mockito/KotlinMockitoHelpers.kt
--packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedModule.kt
--packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
--packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionProgressProvider.kt
--packages/SystemUI/unfold/src/com/android/systemui/unfold/compat/ScreenSizeFoldProvider.kt
--packages/SystemUI/unfold/src/com/android/systemui/unfold/compat/SizeScreenStatusProvider.kt
--packages/SystemUI/unfold/src/com/android/systemui/unfold/config/ResourceUnfoldTransitionConfig.kt
--packages/SystemUI/unfold/src/com/android/systemui/unfold/dagger/UnfoldMain.kt
--packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
--packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
--packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/FoldStateProvider.kt
--packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/screen/ScreenStatusProvider.kt
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 6b95711..774b212 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/DividerPresenter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/DividerPresenter.java
@@ -200,6 +200,10 @@
}
// At this point, a divider is required.
+ final TaskFragmentContainer primaryContainer =
+ topSplitContainer.getPrimaryContainer();
+ final TaskFragmentContainer secondaryContainer =
+ topSplitContainer.getSecondaryContainer();
// Create the decor surface if one is not available yet.
final SurfaceControl decorSurface = parentInfo.getDecorSurface();
@@ -207,41 +211,44 @@
// Clean up when the decor surface is currently unavailable.
removeDivider();
// Request to create the decor surface
- createOrMoveDecorSurfaceLocked(wct, topSplitContainer.getPrimaryContainer());
+ createOrMoveDecorSurfaceLocked(wct, primaryContainer);
return;
}
// Update the decor surface owner if needed.
boolean isDraggableExpandType =
SplitAttributesHelper.isDraggableExpandType(splitAttributes);
- final TaskFragmentContainer decorSurfaceOwnerContainer = isDraggableExpandType
- ? topSplitContainer.getSecondaryContainer()
- : topSplitContainer.getPrimaryContainer();
+ final TaskFragmentContainer decorSurfaceOwnerContainer =
+ isDraggableExpandType ? secondaryContainer : primaryContainer;
if (!Objects.equals(
mDecorSurfaceOwner, decorSurfaceOwnerContainer.getTaskFragmentToken())) {
createOrMoveDecorSurfaceLocked(wct, decorSurfaceOwnerContainer);
}
- final boolean isVerticalSplit = isVerticalSplit(topSplitContainer);
- final boolean isReversedLayout = isReversedLayout(
- topSplitContainer.getCurrentSplitAttributes(),
- parentInfo.getConfiguration());
+
+ final Configuration parentConfiguration = parentInfo.getConfiguration();
+ final Rect taskBounds = parentConfiguration.windowConfiguration.getBounds();
+ final boolean isVerticalSplit = isVerticalSplit(splitAttributes);
+ final boolean isReversedLayout = isReversedLayout(splitAttributes, parentConfiguration);
+ final int dividerWidthPx = getDividerWidthPx(dividerAttributes);
updateProperties(
new Properties(
- parentInfo.getConfiguration(),
+ parentConfiguration,
dividerAttributes,
decorSurface,
getInitialDividerPosition(
- topSplitContainer, isVerticalSplit, isReversedLayout),
+ primaryContainer, secondaryContainer, taskBounds,
+ dividerWidthPx, isDraggableExpandType, isVerticalSplit,
+ isReversedLayout),
isVerticalSplit,
isReversedLayout,
parentInfo.getDisplayId(),
isDraggableExpandType,
- getContainerBackgroundColor(topSplitContainer.getPrimaryContainer(),
- DEFAULT_PRIMARY_VEIL_COLOR),
- getContainerBackgroundColor(topSplitContainer.getSecondaryContainer(),
- DEFAULT_SECONDARY_VEIL_COLOR)
+ getContainerBackgroundColor(
+ primaryContainer, DEFAULT_PRIMARY_VEIL_COLOR),
+ getContainerBackgroundColor(
+ secondaryContainer, DEFAULT_SECONDARY_VEIL_COLOR)
));
}
}
@@ -338,32 +345,31 @@
@VisibleForTesting
static int getInitialDividerPosition(
- @NonNull SplitContainer splitContainer,
+ @NonNull TaskFragmentContainer primaryContainer,
+ @NonNull TaskFragmentContainer secondaryContainer,
+ @NonNull Rect taskBounds,
+ int dividerWidthPx,
+ boolean isDraggableExpandType,
boolean isVerticalSplit,
boolean isReversedLayout) {
- final Rect primaryBounds =
- splitContainer.getPrimaryContainer().getLastRequestedBounds();
- final Rect secondaryBounds =
- splitContainer.getSecondaryContainer().getLastRequestedBounds();
- final SplitAttributes splitAttributes = splitContainer.getCurrentSplitAttributes();
-
- if (SplitAttributesHelper.isDraggableExpandType(splitAttributes)) {
- // If the container is fully expanded by dragging the divider, we display the divider
- // on the edge.
- final int dividerWidth = getDividerWidthPx(splitAttributes.getDividerAttributes());
+ if (isDraggableExpandType) {
+ // If the secondary container is fully expanded by dragging the divider, we display the
+ // divider on the edge.
final int fullyExpandedPosition = isVerticalSplit
- ? primaryBounds.right - dividerWidth
- : primaryBounds.bottom - dividerWidth;
+ ? taskBounds.width() - dividerWidthPx
+ : taskBounds.height() - dividerWidthPx;
return isReversedLayout ? fullyExpandedPosition : 0;
} else {
+ final Rect primaryBounds = primaryContainer.getLastRequestedBounds();
+ final Rect secondaryBounds = secondaryContainer.getLastRequestedBounds();
return isVerticalSplit
? Math.min(primaryBounds.right, secondaryBounds.right)
: Math.min(primaryBounds.bottom, secondaryBounds.bottom);
}
}
- private static boolean isVerticalSplit(@NonNull SplitContainer splitContainer) {
- final int layoutDirection = splitContainer.getCurrentSplitAttributes().getLayoutDirection();
+ private static boolean isVerticalSplit(@NonNull SplitAttributes splitAttributes) {
+ final int layoutDirection = splitAttributes.getLayoutDirection();
switch (layoutDirection) {
case SplitAttributes.LayoutDirection.LEFT_TO_RIGHT:
case SplitAttributes.LayoutDirection.RIGHT_TO_LEFT:
@@ -510,7 +516,7 @@
if (mProperties != null && mRenderer != null) {
final Rect taskBounds = mProperties.mConfiguration.windowConfiguration.getBounds();
mDividerPosition = calculateDividerPosition(
- event, taskBounds, mRenderer.mDividerWidthPx,
+ event, taskBounds, mProperties.mDividerWidthPx,
mProperties.mDividerAttributes, mProperties.mIsVerticalSplit,
calculateMinPosition(), calculateMaxPosition());
mRenderer.setDividerPosition(mDividerPosition);
@@ -676,8 +682,8 @@
final int minPosition = calculateMinPosition();
final int maxPosition = calculateMaxPosition();
final int fullyExpandedPosition = mProperties.mIsVerticalSplit
- ? taskBounds.right - mRenderer.mDividerWidthPx
- : taskBounds.bottom - mRenderer.mDividerWidthPx;
+ ? taskBounds.width() - mProperties.mDividerWidthPx
+ : taskBounds.height() - mProperties.mDividerWidthPx;
if (isDraggingToFullscreenAllowed(mProperties.mDividerAttributes)) {
final float displayDensity = getDisplayDensity();
@@ -782,7 +788,7 @@
private int calculateMinPosition() {
return calculateMinPosition(
mProperties.mConfiguration.windowConfiguration.getBounds(),
- mRenderer.mDividerWidthPx, mProperties.mDividerAttributes,
+ mProperties.mDividerWidthPx, mProperties.mDividerAttributes,
mProperties.mIsVerticalSplit, mProperties.mIsReversedLayout);
}
@@ -790,7 +796,7 @@
private int calculateMaxPosition() {
return calculateMaxPosition(
mProperties.mConfiguration.windowConfiguration.getBounds(),
- mRenderer.mDividerWidthPx, mProperties.mDividerAttributes,
+ mProperties.mDividerWidthPx, mProperties.mDividerAttributes,
mProperties.mIsVerticalSplit, mProperties.mIsReversedLayout);
}
@@ -828,13 +834,12 @@
* Returns the new split ratio of the {@link SplitContainer} based on the current divider
* position.
*/
- float calculateNewSplitRatio(@NonNull SplitContainer topSplitContainer) {
+ float calculateNewSplitRatio() {
synchronized (mLock) {
return calculateNewSplitRatio(
- topSplitContainer,
mDividerPosition,
mProperties.mConfiguration.windowConfiguration.getBounds(),
- mRenderer.mDividerWidthPx,
+ mProperties.mDividerWidthPx,
mProperties.mIsVerticalSplit,
mProperties.mIsReversedLayout,
calculateMinPosition(),
@@ -846,21 +851,20 @@
private static boolean isDraggingToFullscreenAllowed(
@NonNull DividerAttributes dividerAttributes) {
// TODO(b/293654166) Use DividerAttributes.isDraggingToFullscreenAllowed when extension is
- // updated.
- return true;
+ // updated to v7.
+ return false;
}
/**
* Returns the new split ratio of the {@link SplitContainer} based on the current divider
* position.
*
- * @param topSplitContainer the {@link SplitContainer} for which to compute the split ratio.
* @param dividerPosition the divider position. See {@link #mDividerPosition}.
* @param taskBounds the task bounds
* @param dividerWidthPx the width of the divider in pixels.
* @param isVerticalSplit if {@code true}, the split is a vertical split. If {@code false}, the
* split is a horizontal split. See
- * {@link #isVerticalSplit(SplitContainer)}.
+ * {@link #isVerticalSplit(SplitAttributes)}.
* @param isReversedLayout if {@code true}, the split layout is reversed, i.e. right-to-left or
* bottom-to-top. If {@code false}, the split is not reversed, i.e.
* left-to-right or top-to-bottom. See
@@ -871,7 +875,6 @@
*/
@VisibleForTesting
static float calculateNewSplitRatio(
- @NonNull SplitContainer topSplitContainer,
int dividerPosition,
@NonNull Rect taskBounds,
int dividerWidthPx,
@@ -896,8 +899,6 @@
dividerPosition = Math.clamp(dividerPosition, minPosition, maxPosition);
}
- final TaskFragmentContainer primaryContainer = topSplitContainer.getPrimaryContainer();
- final Rect origPrimaryBounds = primaryContainer.getLastRequestedBounds();
final int usableSize = isVerticalSplit
? taskBounds.width() - dividerWidthPx
: taskBounds.height() - dividerWidthPx;
@@ -905,13 +906,13 @@
final float newRatio;
if (isVerticalSplit) {
final int newPrimaryWidth = isReversedLayout
- ? (origPrimaryBounds.right - (dividerPosition + dividerWidthPx))
- : (dividerPosition - origPrimaryBounds.left);
+ ? taskBounds.width() - (dividerPosition + dividerWidthPx)
+ : dividerPosition;
newRatio = 1.0f * newPrimaryWidth / usableSize;
} else {
final int newPrimaryHeight = isReversedLayout
- ? (origPrimaryBounds.bottom - (dividerPosition + dividerWidthPx))
- : (dividerPosition - origPrimaryBounds.top);
+ ? taskBounds.height() - (dividerPosition + dividerWidthPx)
+ : dividerPosition;
newRatio = 1.0f * newPrimaryHeight / usableSize;
}
return newRatio;
@@ -966,6 +967,7 @@
private final boolean mIsDraggableExpandType;
private final Color mPrimaryVeilColor;
private final Color mSecondaryVeilColor;
+ private final int mDividerWidthPx;
@VisibleForTesting
Properties(
@@ -989,6 +991,7 @@
mIsDraggableExpandType = isDraggableExpandType;
mPrimaryVeilColor = primaryVeilColor;
mSecondaryVeilColor = secondaryVeilColor;
+ mDividerWidthPx = getDividerWidthPx(dividerAttributes);
}
/**
@@ -1055,7 +1058,6 @@
private final View.OnTouchListener mListener;
@NonNull
private Properties mProperties;
- private int mDividerWidthPx;
private int mHandleWidthPx;
@Nullable
private SurfaceControl mPrimaryVeil;
@@ -1095,7 +1097,6 @@
/** Updates the divider when initializing or when properties are changed */
@VisibleForTesting
void update() {
- mDividerWidthPx = getDividerWidthPx(mProperties.mDividerAttributes);
mDividerPosition = mProperties.mInitialDividerPosition;
mWindowlessWindowManager.setConfiguration(mProperties.mConfiguration);
@@ -1161,15 +1162,17 @@
// When the divider drag handle width is larger than the divider width, the position
// of the divider surface is adjusted so that it is large enough to host both the
// divider line and the divider drag handle.
- mDividerSurfaceWidthPx = Math.max(mDividerWidthPx, mHandleWidthPx);
+ mDividerSurfaceWidthPx = Math.max(mProperties.mDividerWidthPx, mHandleWidthPx);
+ dividerSurfacePosition = mProperties.mIsReversedLayout
+ ? mDividerPosition
+ : mDividerPosition + mProperties.mDividerWidthPx - mDividerSurfaceWidthPx;
dividerSurfacePosition =
- mProperties.mIsReversedLayout
- ? mDividerPosition
- : mDividerPosition + mDividerWidthPx - mDividerSurfaceWidthPx;
- dividerSurfacePosition = Math.clamp(dividerSurfacePosition, 0,
- mProperties.mIsVerticalSplit ? taskBounds.width() : taskBounds.height());
+ Math.clamp(dividerSurfacePosition, 0,
+ mProperties.mIsVerticalSplit
+ ? taskBounds.width() - mDividerSurfaceWidthPx
+ : taskBounds.height() - mDividerSurfaceWidthPx);
} else {
- mDividerSurfaceWidthPx = mDividerWidthPx;
+ mDividerSurfaceWidthPx = mProperties.mDividerWidthPx;
dividerSurfacePosition = mDividerPosition;
}
@@ -1182,16 +1185,9 @@
}
// Update divider line position in the surface
- if (!mProperties.mIsReversedLayout) {
- final int offset = mDividerPosition - dividerSurfacePosition;
- mDividerLine.setX(mProperties.mIsVerticalSplit ? offset : 0);
- mDividerLine.setY(mProperties.mIsVerticalSplit ? 0 : offset);
- } else {
- // For reversed layout, the divider line is always at the start of the divider
- // surface.
- mDividerLine.setX(0);
- mDividerLine.setY(0);
- }
+ final int offset = mDividerPosition - dividerSurfacePosition;
+ mDividerLine.setX(mProperties.mIsVerticalSplit ? offset : 0);
+ mDividerLine.setY(mProperties.mIsVerticalSplit ? 0 : offset);
if (mIsDragging) {
updateVeils(t);
@@ -1241,8 +1237,10 @@
final Rect taskBounds = mProperties.mConfiguration.windowConfiguration.getBounds();
mDividerLine.setLayoutParams(
mProperties.mIsVerticalSplit
- ? new FrameLayout.LayoutParams(mDividerWidthPx, taskBounds.height())
- : new FrameLayout.LayoutParams(taskBounds.width(), mDividerWidthPx)
+ ? new FrameLayout.LayoutParams(
+ mProperties.mDividerWidthPx, taskBounds.height())
+ : new FrameLayout.LayoutParams(
+ taskBounds.width(), mProperties.mDividerWidthPx)
);
if (mProperties.mDividerAttributes.getDividerType()
== DividerAttributes.DIVIDER_TYPE_DRAGGABLE) {
@@ -1352,13 +1350,14 @@
Rect secondaryBounds;
if (mProperties.mIsVerticalSplit) {
final Rect boundsLeft = new Rect(0, 0, mDividerPosition, taskBounds.height());
- final Rect boundsRight = new Rect(mDividerPosition + mDividerWidthPx, 0,
+ final Rect boundsRight = new Rect(mDividerPosition + mProperties.mDividerWidthPx, 0,
taskBounds.width(), taskBounds.height());
primaryBounds = mProperties.mIsReversedLayout ? boundsRight : boundsLeft;
secondaryBounds = mProperties.mIsReversedLayout ? boundsLeft : boundsRight;
} else {
final Rect boundsTop = new Rect(0, 0, taskBounds.width(), mDividerPosition);
- final Rect boundsBottom = new Rect(0, mDividerPosition + mDividerWidthPx,
+ final Rect boundsBottom = new Rect(
+ 0, mDividerPosition + mProperties.mDividerWidthPx,
taskBounds.width(), taskBounds.height());
primaryBounds = mProperties.mIsReversedLayout ? boundsBottom : boundsTop;
secondaryBounds = mProperties.mIsReversedLayout ? boundsTop : boundsBottom;
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
index c708da9..ee00c4c 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
@@ -510,7 +510,7 @@
return;
}
final TaskFragmentContainer primaryContainer = topSplitContainer.getPrimaryContainer();
- final float newRatio = dividerPresenter.calculateNewSplitRatio(topSplitContainer);
+ final float newRatio = dividerPresenter.calculateNewSplitRatio();
// If the primary container is fully expanded, we should finish all the associated
// secondary containers.
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 20626c7..4515187 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
@@ -144,6 +144,7 @@
new SplitAttributes.Builder()
.setDividerAttributes(DEFAULT_DIVIDER_ATTRIBUTES)
.build());
+ final Rect mockTaskBounds = new Rect(0, 0, 2000, 1000);
final TaskFragmentContainer mockPrimaryContainer =
createMockTaskFragmentContainer(
mPrimaryContainerToken, new Rect(0, 0, 950, 1000));
@@ -158,7 +159,9 @@
DEFAULT_DIVIDER_ATTRIBUTES,
mSurfaceControl,
getInitialDividerPosition(
- mSplitContainer, true /* isVerticalSplit */, false /* isReversedLayout */),
+ mockPrimaryContainer, mockSecondaryContainer, mockTaskBounds,
+ 50 /* divideWidthPx */, false /* isDraggableExpandType */,
+ true /* isVerticalSplit */, false /* isReversedLayout */),
true /* isVerticalSplit */,
false /* isReversedLayout */,
Display.DEFAULT_DISPLAY,
@@ -502,7 +505,6 @@
assertEquals(
0.3f, // Primary is 300px after dragging.
DividerPresenter.calculateNewSplitRatio(
- mSplitContainer,
dividerPosition,
taskBounds,
dividerWidthPx,
@@ -518,7 +520,6 @@
assertEquals(
DividerPresenter.RATIO_EXPANDED_SECONDARY,
DividerPresenter.calculateNewSplitRatio(
- mSplitContainer,
dividerPosition,
taskBounds,
dividerWidthPx,
@@ -535,7 +536,6 @@
assertEquals(
0.2f, // Adjusted to the minPosition 200
DividerPresenter.calculateNewSplitRatio(
- mSplitContainer,
dividerPosition,
taskBounds,
dividerWidthPx,
@@ -569,7 +569,6 @@
// After dragging, secondary is [0, 0, 2000, 300]. Primary is [0, 400, 2000, 1100].
0.7f,
DividerPresenter.calculateNewSplitRatio(
- mSplitContainer,
dividerPosition,
taskBounds,
dividerWidthPx,
@@ -587,7 +586,6 @@
// The primary (bottom) container is expanded
DividerPresenter.RATIO_EXPANDED_PRIMARY,
DividerPresenter.calculateNewSplitRatio(
- mSplitContainer,
dividerPosition,
taskBounds,
dividerWidthPx,
@@ -605,7 +603,6 @@
// Adjusted to minPosition 200, so the primary (bottom) container is 800.
0.8f,
DividerPresenter.calculateNewSplitRatio(
- mSplitContainer,
dividerPosition,
taskBounds,
dividerWidthPx,
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 fb0a1ab..12bbd51 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 @@
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/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index 6e45397..ef384c7 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.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 @@
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 @@
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 6fcea1f..b52b0d8 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
@@ -489,6 +489,14 @@
// activity windowing mode, and set the task bounds to the final bounds
wct.setActivityWindowingMode(taskInfo.token, WINDOWING_MODE_UNDEFINED);
wct.setBounds(taskInfo.token, destinationBounds);
+ // If the animation is only used to apply destination bounds immediately and
+ // invisibly, then reshow it until the pip is drawn with the bounds.
+ final PipAnimationController.PipTransitionAnimator<?> animator =
+ mPipAnimationController.getCurrentAnimator();
+ if (animator != null && animator.getEndValue().equals(0f)) {
+ tx.addTransactionCommittedListener(mTransitions.getMainExecutor(),
+ () -> fadeExistingPip(true /* show */));
+ }
} else {
wct.setBounds(taskInfo.token, null /* bounds */);
}
@@ -1026,6 +1034,7 @@
}
startTransaction.apply();
+ int animationDuration = mEnterExitAnimationDuration;
PipAnimationController.PipTransitionAnimator animator;
if (enterAnimationType == ANIM_TYPE_BOUNDS) {
animator = mPipAnimationController.getAnimator(taskInfo, leash, currentBounds,
@@ -1057,8 +1066,17 @@
}
}
} else if (enterAnimationType == ANIM_TYPE_ALPHA) {
+ // In case augmentRequest() is unable to apply the entering bounds (e.g. the request
+ // info only contains display change), keep the animation invisible (alpha 0) and
+ // duration 0 to apply the destination bounds. The actual fade-in animation will be
+ // done in onFinishResize() after the bounds are applied.
+ final boolean fadeInAfterOnFinishResize = rotationDelta != Surface.ROTATION_0
+ && mFixedRotationState == FIXED_ROTATION_CALLBACK;
animator = mPipAnimationController.getAnimator(taskInfo, leash, destinationBounds,
- 0f, 1f);
+ 0f, fadeInAfterOnFinishResize ? 0f : 1f);
+ if (fadeInAfterOnFinishResize) {
+ animationDuration = 0;
+ }
mSurfaceTransactionHelper
.crop(finishTransaction, leash, destinationBounds)
.round(finishTransaction, leash, true /* applyCornerRadius */);
@@ -1068,7 +1086,7 @@
mPipOrganizer.setContentOverlay(animator.getContentOverlayLeash(), currentBounds);
animator.setTransitionDirection(TRANSITION_DIRECTION_TO_PIP)
.setPipAnimationCallback(mPipAnimationCallback)
- .setDuration(mEnterExitAnimationDuration);
+ .setDuration(animationDuration);
if (rotationDelta != Surface.ROTATION_0
&& mFixedRotationState == FIXED_ROTATION_TRANSITION) {
// For fixed rotation, the animation destination bounds is in old rotation coordinates.
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 d8f2c02..863202d 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 @@
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/ScreenRotationAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
index 9ce2209..e196254 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
@@ -167,7 +167,7 @@
t.show(mScreenshotLayer);
if (!isCustomRotate()) {
mStartLuma = TransitionAnimation.getBorderLuma(hardwareBuffer,
- screenshotBuffer.getColorSpace());
+ screenshotBuffer.getColorSpace(), mSurfaceControl);
}
hardwareBuffer.close();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
index e85cb64..95e0d79 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
@@ -255,6 +255,7 @@
private final WindowContainerToken mTaskToken;
private final DragPositioningCallback mDragPositioningCallback;
private final DragDetector mDragDetector;
+ private final int mDisplayId;
private int mDragPointerId = -1;
private boolean mIsDragging;
@@ -266,6 +267,7 @@
mTaskToken = taskInfo.token;
mDragPositioningCallback = dragPositioningCallback;
mDragDetector = new DragDetector(this);
+ mDisplayId = taskInfo.displayId;
}
@Override
@@ -274,7 +276,7 @@
if (id == R.id.close_window) {
mTaskOperations.closeTask(mTaskToken);
} else if (id == R.id.back_button) {
- mTaskOperations.injectBackKey();
+ mTaskOperations.injectBackKey(mDisplayId);
} else if (id == R.id.minimize_window) {
mTaskOperations.minimizeTask(mTaskToken);
} else if (id == R.id.maximize_window) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
index 74b091f..6901e75 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
@@ -386,6 +386,7 @@
private final DragPositioningCallback mDragPositioningCallback;
private final DragDetector mDragDetector;
private final GestureDetector mGestureDetector;
+ private final int mDisplayId;
/**
* Whether to pilfer the next motion event to send cancellations to the windows below.
@@ -407,6 +408,7 @@
mDragPositioningCallback = dragPositioningCallback;
mDragDetector = new DragDetector(this);
mGestureDetector = new GestureDetector(mContext, this);
+ mDisplayId = taskInfo.displayId;
mCloseMaximizeWindowRunnable = () -> {
final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(mTaskId);
if (decoration == null) return;
@@ -432,7 +434,7 @@
mTaskOperations.closeTask(mTaskToken, wct);
}
} else if (id == R.id.back_button) {
- mTaskOperations.injectBackKey();
+ mTaskOperations.injectBackKey(mDisplayId);
} else if (id == R.id.caption_handle || id == R.id.open_menu_button) {
if (!decoration.isHandleMenuActive()) {
moveTaskToFront(decoration.mTaskInfo);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.java
deleted file mode 100644
index 93e2a21..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.java
+++ /dev/null
@@ -1,451 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.windowdecor;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
-import android.annotation.ColorRes;
-import android.annotation.NonNull;
-import android.app.ActivityManager.RunningTaskInfo;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.graphics.Bitmap;
-import android.graphics.Color;
-import android.graphics.PixelFormat;
-import android.graphics.PointF;
-import android.graphics.Rect;
-import android.os.Trace;
-import android.view.Display;
-import android.view.LayoutInflater;
-import android.view.SurfaceControl;
-import android.view.SurfaceControlViewHost;
-import android.view.SurfaceSession;
-import android.view.View;
-import android.view.WindowManager;
-import android.view.WindowlessWindowManager;
-import android.widget.ImageView;
-import android.window.TaskConstants;
-
-import com.android.wm.shell.R;
-import com.android.wm.shell.common.DisplayController;
-
-import java.util.function.Supplier;
-
-/**
- * Creates and updates a veil that covers task contents on resize.
- */
-public class ResizeVeil {
- private static final String TAG = "ResizeVeil";
- private static final int RESIZE_ALPHA_DURATION = 100;
-
- private static final int VEIL_CONTAINER_LAYER = TaskConstants.TASK_CHILD_LAYER_RESIZE_VEIL;
- /** The background is a child of the veil container layer and goes at the bottom. */
- private static final int VEIL_BACKGROUND_LAYER = 0;
- /** The icon is a child of the veil container layer and goes in front of the background. */
- private static final int VEIL_ICON_LAYER = 1;
-
- private final Context mContext;
- private final DisplayController mDisplayController;
- private final Supplier<SurfaceControl.Transaction> mSurfaceControlTransactionSupplier;
- private final SurfaceControlBuilderFactory mSurfaceControlBuilderFactory;
- private final WindowDecoration.SurfaceControlViewHostFactory mSurfaceControlViewHostFactory;
- private final SurfaceSession mSurfaceSession = new SurfaceSession();
- private final Bitmap mAppIcon;
- private ImageView mIconView;
- private int mIconSize;
- private SurfaceControl mParentSurface;
-
- /** A container surface to host the veil background and icon child surfaces. */
- private SurfaceControl mVeilSurface;
- /** A color surface for the veil background. */
- private SurfaceControl mBackgroundSurface;
- /** A surface that hosts a windowless window with the app icon. */
- private SurfaceControl mIconSurface;
-
- private final RunningTaskInfo mTaskInfo;
- private SurfaceControlViewHost mViewHost;
- private Display mDisplay;
- private ValueAnimator mVeilAnimator;
-
- private boolean mIsShowing = false;
-
- private final DisplayController.OnDisplaysChangedListener mOnDisplaysChangedListener =
- new DisplayController.OnDisplaysChangedListener() {
- @Override
- public void onDisplayAdded(int displayId) {
- if (mTaskInfo.displayId != displayId) {
- return;
- }
- mDisplayController.removeDisplayWindowListener(this);
- setupResizeVeil();
- }
- };
-
- public ResizeVeil(Context context,
- @NonNull DisplayController displayController,
- Bitmap appIcon, RunningTaskInfo taskInfo,
- SurfaceControl taskSurface,
- Supplier<SurfaceControl.Transaction> surfaceControlTransactionSupplier) {
- this(context,
- displayController,
- appIcon,
- taskInfo,
- taskSurface,
- surfaceControlTransactionSupplier,
- new SurfaceControlBuilderFactory() {},
- new WindowDecoration.SurfaceControlViewHostFactory() {});
- }
-
- public ResizeVeil(Context context,
- @NonNull DisplayController displayController,
- Bitmap appIcon, RunningTaskInfo taskInfo,
- SurfaceControl taskSurface,
- Supplier<SurfaceControl.Transaction> surfaceControlTransactionSupplier,
- SurfaceControlBuilderFactory surfaceControlBuilderFactory,
- WindowDecoration.SurfaceControlViewHostFactory surfaceControlViewHostFactory) {
- mContext = context;
- mDisplayController = displayController;
- mAppIcon = appIcon;
- mSurfaceControlTransactionSupplier = surfaceControlTransactionSupplier;
- mTaskInfo = taskInfo;
- mParentSurface = taskSurface;
- mSurfaceControlBuilderFactory = surfaceControlBuilderFactory;
- mSurfaceControlViewHostFactory = surfaceControlViewHostFactory;
- setupResizeVeil();
- }
- /**
- * Create the veil in its default invisible state.
- */
- private void setupResizeVeil() {
- if (!obtainDisplayOrRegisterListener()) {
- // Display may not be available yet, skip this until then.
- return;
- }
- Trace.beginSection("ResizeVeil#setupResizeVeil");
- mVeilSurface = mSurfaceControlBuilderFactory
- .create("Resize veil of Task=" + mTaskInfo.taskId)
- .setContainerLayer()
- .setHidden(true)
- .setParent(mParentSurface)
- .setCallsite("ResizeVeil#setupResizeVeil")
- .build();
- mBackgroundSurface = mSurfaceControlBuilderFactory
- .create("Resize veil background of Task=" + mTaskInfo.taskId, mSurfaceSession)
- .setColorLayer()
- .setHidden(true)
- .setParent(mVeilSurface)
- .setCallsite("ResizeVeil#setupResizeVeil")
- .build();
- mIconSurface = mSurfaceControlBuilderFactory
- .create("Resize veil icon of Task=" + mTaskInfo.taskId)
- .setContainerLayer()
- .setHidden(true)
- .setParent(mVeilSurface)
- .setCallsite("ResizeVeil#setupResizeVeil")
- .build();
-
- mIconSize = mContext.getResources()
- .getDimensionPixelSize(R.dimen.desktop_mode_resize_veil_icon_size);
- final View root = LayoutInflater.from(mContext)
- .inflate(R.layout.desktop_mode_resize_veil, null /* root */);
- mIconView = root.findViewById(R.id.veil_application_icon);
- mIconView.setImageBitmap(mAppIcon);
-
- final WindowManager.LayoutParams lp =
- new WindowManager.LayoutParams(
- mIconSize,
- mIconSize,
- WindowManager.LayoutParams.TYPE_APPLICATION,
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
- PixelFormat.TRANSPARENT);
- lp.setTitle("Resize veil icon window of Task=" + mTaskInfo.taskId);
- lp.setTrustedOverlay();
-
- final WindowlessWindowManager wwm = new WindowlessWindowManager(mTaskInfo.configuration,
- mIconSurface, null /* hostInputToken */);
-
- mViewHost = mSurfaceControlViewHostFactory.create(mContext, mDisplay, wwm, "ResizeVeil");
- mViewHost.setView(root, lp);
- Trace.endSection();
- }
-
- private boolean obtainDisplayOrRegisterListener() {
- mDisplay = mDisplayController.getDisplay(mTaskInfo.displayId);
- if (mDisplay == null) {
- mDisplayController.addDisplayWindowListener(mOnDisplaysChangedListener);
- return false;
- }
- return true;
- }
-
- /**
- * Shows the veil surface/view.
- *
- * @param t the transaction to apply in sync with the veil draw
- * @param parentSurface the surface that the veil should be a child of
- * @param taskBounds the bounds of the task that owns the veil
- * @param fadeIn if true, the veil will fade-in with an animation, if false, it will be shown
- * immediately
- */
- public void showVeil(SurfaceControl.Transaction t, SurfaceControl parentSurface,
- Rect taskBounds, boolean fadeIn) {
- if (!isReady() || isVisible()) {
- t.apply();
- return;
- }
- mIsShowing = true;
-
- // Parent surface can change, ensure it is up to date.
- if (!parentSurface.equals(mParentSurface)) {
- t.reparent(mVeilSurface, parentSurface);
- mParentSurface = parentSurface;
- }
-
- t.show(mVeilSurface);
- t.setLayer(mVeilSurface, VEIL_CONTAINER_LAYER);
- t.setLayer(mIconSurface, VEIL_ICON_LAYER);
- t.setLayer(mBackgroundSurface, VEIL_BACKGROUND_LAYER);
- t.setColor(mBackgroundSurface,
- Color.valueOf(mContext.getColor(getBackgroundColorId())).getComponents());
-
- relayout(taskBounds, t);
- if (fadeIn) {
- cancelAnimation();
- final SurfaceControl.Transaction veilAnimT = mSurfaceControlTransactionSupplier.get();
- mVeilAnimator = new ValueAnimator();
- mVeilAnimator.setFloatValues(0f, 1f);
- mVeilAnimator.setDuration(RESIZE_ALPHA_DURATION);
- mVeilAnimator.addUpdateListener(animation -> {
- veilAnimT.setAlpha(mBackgroundSurface, mVeilAnimator.getAnimatedFraction());
- veilAnimT.apply();
- });
- mVeilAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- veilAnimT.show(mBackgroundSurface)
- .setAlpha(mBackgroundSurface, 0)
- .apply();
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- veilAnimT.setAlpha(mBackgroundSurface, 1).apply();
- }
- });
-
- final SurfaceControl.Transaction iconAnimT = mSurfaceControlTransactionSupplier.get();
- final ValueAnimator iconAnimator = new ValueAnimator();
- iconAnimator.setFloatValues(0f, 1f);
- iconAnimator.setDuration(RESIZE_ALPHA_DURATION);
- iconAnimator.addUpdateListener(animation -> {
- iconAnimT.setAlpha(mIconSurface, animation.getAnimatedFraction());
- iconAnimT.apply();
- });
- iconAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- iconAnimT.show(mIconSurface)
- .setAlpha(mIconSurface, 0)
- .apply();
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- iconAnimT.setAlpha(mIconSurface, 1).apply();
- }
- });
- // Let the animators show it with the correct alpha value once the animation starts.
- t.hide(mIconSurface);
- t.hide(mBackgroundSurface);
- t.apply();
-
- mVeilAnimator.start();
- iconAnimator.start();
- } else {
- // Show the veil immediately.
- t.show(mIconSurface);
- t.show(mBackgroundSurface);
- t.setAlpha(mIconSurface, 1);
- t.setAlpha(mBackgroundSurface, 1);
- t.apply();
- }
- }
-
- /**
- * Animate veil's alpha to 1, fading it in.
- */
- public void showVeil(SurfaceControl parentSurface, Rect taskBounds) {
- if (!isReady() || isVisible()) {
- return;
- }
- SurfaceControl.Transaction t = mSurfaceControlTransactionSupplier.get();
- showVeil(t, parentSurface, taskBounds, true /* fadeIn */);
- }
-
- /**
- * Update veil bounds to match bounds changes.
- * @param newBounds bounds to update veil to.
- */
- private void relayout(Rect newBounds, SurfaceControl.Transaction t) {
- t.setWindowCrop(mVeilSurface, newBounds.width(), newBounds.height());
- final PointF iconPosition = calculateAppIconPosition(newBounds);
- t.setPosition(mIconSurface, iconPosition.x, iconPosition.y);
- t.setPosition(mParentSurface, newBounds.left, newBounds.top);
- t.setWindowCrop(mParentSurface, newBounds.width(), newBounds.height());
- }
-
- /**
- * Calls relayout to update task and veil bounds.
- * @param newBounds bounds to update veil to.
- */
- public void updateResizeVeil(Rect newBounds) {
- if (!isVisible()) {
- return;
- }
- SurfaceControl.Transaction t = mSurfaceControlTransactionSupplier.get();
- updateResizeVeil(t, newBounds);
- }
-
- /**
- * Calls relayout to update task and veil bounds.
- * Finishes veil fade in if animation is currently running; this is to prevent empty space
- * being visible behind the transparent veil during a fast resize.
- *
- * @param t a transaction to be applied in sync with the veil draw.
- * @param newBounds bounds to update veil to.
- */
- public void updateResizeVeil(SurfaceControl.Transaction t, Rect newBounds) {
- if (!isVisible()) {
- t.apply();
- return;
- }
- if (mVeilAnimator != null && mVeilAnimator.isStarted()) {
- mVeilAnimator.removeAllUpdateListeners();
- mVeilAnimator.end();
- }
- relayout(newBounds, t);
- t.apply();
- }
-
- /**
- * Animate veil's alpha to 0, fading it out.
- */
- public void hideVeil() {
- if (!isVisible()) {
- return;
- }
- cancelAnimation();
- mVeilAnimator = new ValueAnimator();
- mVeilAnimator.setFloatValues(1, 0);
- mVeilAnimator.setDuration(RESIZE_ALPHA_DURATION);
- mVeilAnimator.addUpdateListener(animation -> {
- SurfaceControl.Transaction t = mSurfaceControlTransactionSupplier.get();
- t.setAlpha(mBackgroundSurface, 1 - mVeilAnimator.getAnimatedFraction());
- t.setAlpha(mIconSurface, 1 - mVeilAnimator.getAnimatedFraction());
- t.apply();
- });
- mVeilAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- SurfaceControl.Transaction t = mSurfaceControlTransactionSupplier.get();
- t.hide(mBackgroundSurface);
- t.hide(mIconSurface);
- t.apply();
- }
- });
- mVeilAnimator.start();
- mIsShowing = false;
- }
-
- @ColorRes
- private int getBackgroundColorId() {
- Configuration configuration = mContext.getResources().getConfiguration();
- if ((configuration.uiMode & Configuration.UI_MODE_NIGHT_MASK)
- == Configuration.UI_MODE_NIGHT_YES) {
- return R.color.desktop_mode_resize_veil_dark;
- } else {
- return R.color.desktop_mode_resize_veil_light;
- }
- }
-
- private PointF calculateAppIconPosition(Rect parentBounds) {
- return new PointF((float) parentBounds.width() / 2 - (float) mIconSize / 2,
- (float) parentBounds.height() / 2 - (float) mIconSize / 2);
- }
-
- private void cancelAnimation() {
- if (mVeilAnimator != null) {
- mVeilAnimator.removeAllUpdateListeners();
- mVeilAnimator.cancel();
- }
- }
-
- /**
- * Whether the resize veil is currently visible.
- *
- * Note: when animating a {@link ResizeVeil#hideVeil()}, the veil is considered visible as soon
- * as the animation starts.
- */
- private boolean isVisible() {
- return mIsShowing;
- }
-
- /** Whether the resize veil is ready to be shown. */
- private boolean isReady() {
- return mViewHost != null;
- }
-
- /**
- * Dispose of veil when it is no longer needed, likely on close of its container decor.
- */
- void dispose() {
- cancelAnimation();
- mIsShowing = false;
- mVeilAnimator = null;
-
- if (mViewHost != null) {
- mViewHost.release();
- mViewHost = null;
- }
- final SurfaceControl.Transaction t = mSurfaceControlTransactionSupplier.get();
- if (mBackgroundSurface != null) {
- t.remove(mBackgroundSurface);
- mBackgroundSurface = null;
- }
- if (mIconSurface != null) {
- t.remove(mIconSurface);
- mIconSurface = null;
- }
- if (mVeilSurface != null) {
- t.remove(mVeilSurface);
- mVeilSurface = null;
- }
- t.apply();
- mDisplayController.removeDisplayWindowListener(mOnDisplaysChangedListener);
- }
-
- interface SurfaceControlBuilderFactory {
- default SurfaceControl.Builder create(@NonNull String name) {
- return new SurfaceControl.Builder().setName(name);
- }
- default SurfaceControl.Builder create(@NonNull String name,
- @NonNull SurfaceSession surfaceSession) {
- return new SurfaceControl.Builder(surfaceSession).setName(name);
- }
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.kt
new file mode 100644
index 0000000..4f2d945
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.kt
@@ -0,0 +1,417 @@
+/*
+ * 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.wm.shell.windowdecor
+
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.ValueAnimator
+import android.app.ActivityManager.RunningTaskInfo
+import android.content.Context
+import android.content.res.Configuration
+import android.graphics.Bitmap
+import android.graphics.Color
+import android.graphics.PixelFormat
+import android.graphics.PointF
+import android.graphics.Rect
+import android.os.Trace
+import android.view.Display
+import android.view.LayoutInflater
+import android.view.SurfaceControl
+import android.view.SurfaceControlViewHost
+import android.view.SurfaceSession
+import android.view.WindowManager
+import android.view.WindowlessWindowManager
+import android.widget.ImageView
+import android.window.TaskConstants
+import com.android.wm.shell.R
+import com.android.wm.shell.common.DisplayController
+import com.android.wm.shell.common.DisplayController.OnDisplaysChangedListener
+import com.android.wm.shell.windowdecor.WindowDecoration.SurfaceControlViewHostFactory
+import java.util.function.Supplier
+
+/**
+ * Creates and updates a veil that covers task contents on resize.
+ */
+class ResizeVeil @JvmOverloads constructor(
+ private val context: Context,
+ private val displayController: DisplayController,
+ private val appIcon: Bitmap,
+ private val taskInfo: RunningTaskInfo,
+ private var parentSurface: SurfaceControl,
+ private val surfaceControlTransactionSupplier: Supplier<SurfaceControl.Transaction>,
+ private val surfaceControlBuilderFactory: SurfaceControlBuilderFactory =
+ object : SurfaceControlBuilderFactory {},
+ private val surfaceControlViewHostFactory: SurfaceControlViewHostFactory =
+ object : SurfaceControlViewHostFactory {}
+) {
+ private val surfaceSession = SurfaceSession()
+ private lateinit var iconView: ImageView
+ private var iconSize = 0
+
+ /** A container surface to host the veil background and icon child surfaces. */
+ private var veilSurface: SurfaceControl? = null
+ /** A color surface for the veil background. */
+ private var backgroundSurface: SurfaceControl? = null
+ /** A surface that hosts a windowless window with the app icon. */
+ private var iconSurface: SurfaceControl? = null
+ private var viewHost: SurfaceControlViewHost? = null
+ private var display: Display? = null
+ private var veilAnimator: ValueAnimator? = null
+
+ /**
+ * Whether the resize veil is currently visible.
+ *
+ * Note: when animating a [ResizeVeil.hideVeil], the veil is considered visible as soon
+ * as the animation starts.
+ */
+ private var isVisible = false
+
+ private val onDisplaysChangedListener: OnDisplaysChangedListener =
+ object : OnDisplaysChangedListener {
+ override fun onDisplayAdded(displayId: Int) {
+ if (taskInfo.displayId != displayId) {
+ return
+ }
+ displayController.removeDisplayWindowListener(this)
+ setupResizeVeil()
+ }
+ }
+
+ private val backgroundColorId: Int
+ get() {
+ val configuration = context.resources.configuration
+ return if (configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
+ == Configuration.UI_MODE_NIGHT_YES) {
+ R.color.desktop_mode_resize_veil_dark
+ } else {
+ R.color.desktop_mode_resize_veil_light
+ }
+ }
+
+ /**
+ * Whether the resize veil is ready to be shown.
+ */
+ private val isReady: Boolean
+ get() = viewHost != null
+
+ init {
+ setupResizeVeil()
+ }
+
+ /**
+ * Create the veil in its default invisible state.
+ */
+ private fun setupResizeVeil() {
+ if (!obtainDisplayOrRegisterListener()) {
+ // Display may not be available yet, skip this until then.
+ return
+ }
+ Trace.beginSection("ResizeVeil#setupResizeVeil")
+ veilSurface = surfaceControlBuilderFactory
+ .create("Resize veil of Task=" + taskInfo.taskId)
+ .setContainerLayer()
+ .setHidden(true)
+ .setParent(parentSurface)
+ .setCallsite("ResizeVeil#setupResizeVeil")
+ .build()
+ backgroundSurface = surfaceControlBuilderFactory
+ .create("Resize veil background of Task=" + taskInfo.taskId, surfaceSession)
+ .setColorLayer()
+ .setHidden(true)
+ .setParent(veilSurface)
+ .setCallsite("ResizeVeil#setupResizeVeil")
+ .build()
+ iconSurface = surfaceControlBuilderFactory
+ .create("Resize veil icon of Task=" + taskInfo.taskId)
+ .setContainerLayer()
+ .setHidden(true)
+ .setParent(veilSurface)
+ .setCallsite("ResizeVeil#setupResizeVeil")
+ .build()
+ iconSize = context.resources
+ .getDimensionPixelSize(R.dimen.desktop_mode_resize_veil_icon_size)
+ val root = LayoutInflater.from(context)
+ .inflate(R.layout.desktop_mode_resize_veil, null /* root */)
+ iconView = root.requireViewById(R.id.veil_application_icon)
+ iconView.setImageBitmap(appIcon)
+ val lp = WindowManager.LayoutParams(
+ iconSize,
+ iconSize,
+ WindowManager.LayoutParams.TYPE_APPLICATION,
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
+ PixelFormat.TRANSPARENT)
+ lp.title = "Resize veil icon window of Task=" + taskInfo.taskId
+ lp.setTrustedOverlay()
+ val wwm = WindowlessWindowManager(taskInfo.configuration,
+ iconSurface, null /* hostInputToken */)
+ viewHost = surfaceControlViewHostFactory.create(context, display, wwm, "ResizeVeil")
+ viewHost?.setView(root, lp)
+ Trace.endSection()
+ }
+
+ private fun obtainDisplayOrRegisterListener(): Boolean {
+ display = displayController.getDisplay(taskInfo.displayId)
+ if (display == null) {
+ displayController.addDisplayWindowListener(onDisplaysChangedListener)
+ return false
+ }
+ return true
+ }
+
+ /**
+ * Shows the veil surface/view.
+ *
+ * @param t the transaction to apply in sync with the veil draw
+ * @param parent the surface that the veil should be a child of
+ * @param taskBounds the bounds of the task that owns the veil
+ * @param fadeIn if true, the veil will fade-in with an animation, if false, it will be shown
+ * immediately
+ */
+ fun showVeil(
+ t: SurfaceControl.Transaction,
+ parent: SurfaceControl,
+ taskBounds: Rect,
+ fadeIn: Boolean
+ ) {
+ if (!isReady || isVisible) {
+ t.apply()
+ return
+ }
+ isVisible = true
+ val background = backgroundSurface
+ val icon = iconSurface
+ val veil = veilSurface
+ if (background == null || icon == null || veil == null) return
+
+ // Parent surface can change, ensure it is up to date.
+ if (parent != parentSurface) {
+ t.reparent(veil, parent)
+ parentSurface = parent
+ }
+
+
+ t.show(veil)
+ .setLayer(veil, VEIL_CONTAINER_LAYER)
+ .setLayer(icon, VEIL_ICON_LAYER)
+ .setLayer(background, VEIL_BACKGROUND_LAYER)
+ .setColor(background,
+ Color.valueOf(context.getColor(backgroundColorId)).components)
+ relayout(taskBounds, t)
+ if (fadeIn) {
+ cancelAnimation()
+ val veilAnimT = surfaceControlTransactionSupplier.get()
+ val iconAnimT = surfaceControlTransactionSupplier.get()
+ veilAnimator = ValueAnimator.ofFloat(0f, 1f).apply {
+ duration = RESIZE_ALPHA_DURATION
+ addUpdateListener {
+ veilAnimT.setAlpha(background, animatedValue as Float)
+ .apply()
+ }
+ addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationStart(animation: Animator) {
+ veilAnimT.show(background)
+ .setAlpha(background, 0f)
+ .apply()
+ }
+
+ override fun onAnimationEnd(animation: Animator) {
+ veilAnimT.setAlpha(background, 1f).apply()
+ }
+ })
+ }
+ val iconAnimator = ValueAnimator.ofFloat(0f, 1f).apply {
+ duration = RESIZE_ALPHA_DURATION
+ addUpdateListener {
+ iconAnimT.setAlpha(icon, animatedValue as Float)
+ .apply()
+ }
+ addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationStart(animation: Animator) {
+ iconAnimT.show(icon)
+ .setAlpha(icon, 0f)
+ .apply()
+ }
+
+ override fun onAnimationEnd(animation: Animator) {
+ iconAnimT.setAlpha(icon, 1f).apply()
+ }
+ })
+ }
+
+ // Let the animators show it with the correct alpha value once the animation starts.
+ t.hide(icon)
+ .hide(background)
+ .apply()
+ veilAnimator?.start()
+ iconAnimator.start()
+ } else {
+ // Show the veil immediately.
+ t.show(icon)
+ .show(background)
+ .setAlpha(icon, 1f)
+ .setAlpha(background, 1f)
+ .apply()
+ }
+ }
+
+ /**
+ * Animate veil's alpha to 1, fading it in.
+ */
+ fun showVeil(parentSurface: SurfaceControl, taskBounds: Rect) {
+ if (!isReady || isVisible) {
+ return
+ }
+ val t = surfaceControlTransactionSupplier.get()
+ showVeil(t, parentSurface, taskBounds, true /* fadeIn */)
+ }
+
+ /**
+ * Update veil bounds to match bounds changes.
+ * @param newBounds bounds to update veil to.
+ */
+ private fun relayout(newBounds: Rect, t: SurfaceControl.Transaction) {
+ val iconPosition = calculateAppIconPosition(newBounds)
+ val veil = veilSurface
+ val icon = iconSurface
+ if (veil == null || icon == null) return
+ t.setWindowCrop(veil, newBounds.width(), newBounds.height())
+ .setPosition(icon, iconPosition.x, iconPosition.y)
+ .setPosition(parentSurface, newBounds.left.toFloat(), newBounds.top.toFloat())
+ .setWindowCrop(parentSurface, newBounds.width(), newBounds.height())
+ }
+
+ /**
+ * Calls relayout to update task and veil bounds.
+ * @param newBounds bounds to update veil to.
+ */
+ fun updateResizeVeil(newBounds: Rect) {
+ if (!isVisible) {
+ return
+ }
+ val t = surfaceControlTransactionSupplier.get()
+ updateResizeVeil(t, newBounds)
+ }
+
+ /**
+ * Calls relayout to update task and veil bounds.
+ * Finishes veil fade in if animation is currently running; this is to prevent empty space
+ * being visible behind the transparent veil during a fast resize.
+ *
+ * @param t a transaction to be applied in sync with the veil draw.
+ * @param newBounds bounds to update veil to.
+ */
+ fun updateResizeVeil(t: SurfaceControl.Transaction, newBounds: Rect) {
+ if (!isVisible) {
+ t.apply()
+ return
+ }
+ veilAnimator?.let { animator ->
+ if (animator.isStarted) {
+ animator.removeAllUpdateListeners()
+ animator.end()
+ }
+ }
+ relayout(newBounds, t)
+ t.apply()
+ }
+
+ /**
+ * Animate veil's alpha to 0, fading it out.
+ */
+ fun hideVeil() {
+ if (!isVisible) {
+ return
+ }
+ cancelAnimation()
+ val background = backgroundSurface
+ val icon = iconSurface
+ if (background == null || icon == null) return
+
+ veilAnimator = ValueAnimator.ofFloat(1f, 0f).apply {
+ duration = RESIZE_ALPHA_DURATION
+ addUpdateListener {
+ surfaceControlTransactionSupplier.get()
+ .setAlpha(background, animatedValue as Float)
+ .setAlpha(icon, animatedValue as Float)
+ .apply()
+ }
+ addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator) {
+ surfaceControlTransactionSupplier.get()
+ .hide(background)
+ .hide(icon)
+ .apply()
+ }
+ })
+ }
+ veilAnimator?.start()
+ isVisible = false
+ }
+
+ private fun calculateAppIconPosition(parentBounds: Rect): PointF {
+ return PointF(parentBounds.width().toFloat() / 2 - iconSize.toFloat() / 2,
+ parentBounds.height().toFloat() / 2 - iconSize.toFloat() / 2)
+ }
+
+ private fun cancelAnimation() {
+ veilAnimator?.removeAllUpdateListeners()
+ veilAnimator?.cancel()
+ }
+
+ /**
+ * Dispose of veil when it is no longer needed, likely on close of its container decor.
+ */
+ fun dispose() {
+ cancelAnimation()
+ veilAnimator = null
+ isVisible = false
+
+ viewHost?.release()
+ viewHost = null
+
+ val t: SurfaceControl.Transaction = surfaceControlTransactionSupplier.get()
+ backgroundSurface?.let { background -> t.remove(background) }
+ backgroundSurface = null
+ iconSurface?.let { icon -> t.remove(icon) }
+ iconSurface = null
+ veilSurface?.let { veil -> t.remove(veil) }
+ veilSurface = null
+ t.apply()
+ displayController.removeDisplayWindowListener(onDisplaysChangedListener)
+ }
+
+ interface SurfaceControlBuilderFactory {
+ fun create(name: String): SurfaceControl.Builder {
+ return SurfaceControl.Builder().setName(name)
+ }
+
+ fun create(name: String, surfaceSession: SurfaceSession): SurfaceControl.Builder {
+ return SurfaceControl.Builder(surfaceSession).setName(name)
+ }
+ }
+
+ companion object {
+ private const val TAG = "ResizeVeil"
+ private const val RESIZE_ALPHA_DURATION = 100L
+ private const val VEIL_CONTAINER_LAYER = TaskConstants.TASK_CHILD_LAYER_RESIZE_VEIL
+
+ /** The background is a child of the veil container layer and goes at the bottom. */
+ private const val VEIL_BACKGROUND_LAYER = 0
+
+ /** The icon is a child of the veil container layer and goes in front of the background. */
+ private const val VEIL_ICON_LAYER = 1
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskOperations.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskOperations.java
index 53d4e27..ad238c3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskOperations.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskOperations.java
@@ -52,19 +52,19 @@
mSyncQueue = syncQueue;
}
- void injectBackKey() {
- sendBackEvent(KeyEvent.ACTION_DOWN);
- sendBackEvent(KeyEvent.ACTION_UP);
+ void injectBackKey(int displayId) {
+ sendBackEvent(KeyEvent.ACTION_DOWN, displayId);
+ sendBackEvent(KeyEvent.ACTION_UP, displayId);
}
- private void sendBackEvent(int action) {
+ private void sendBackEvent(int action, int displayId) {
final long when = SystemClock.uptimeMillis();
final KeyEvent ev = new KeyEvent(when, when, action, KeyEvent.KEYCODE_BACK,
0 /* repeat */, 0 /* metaState */, KeyCharacterMap.VIRTUAL_KEYBOARD,
0 /* scancode */, KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY,
InputDevice.SOURCE_KEYBOARD);
- ev.setDisplayId(mContext.getDisplay().getDisplayId());
+ ev.setDisplayId(displayId);
if (!mContext.getSystemService(InputManager.class)
.injectInputEvent(ev, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC)) {
Log.e(TAG, "Inject input event fail");
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 0dc5128..2ae3cb9 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
@@ -51,6 +51,7 @@
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.shared.DesktopModeStatus;
@@ -687,7 +688,8 @@
}
}
- interface SurfaceControlViewHostFactory {
+ @VisibleForTesting
+ public interface SurfaceControlViewHostFactory {
default SurfaceControlViewHost create(Context c, Display d, WindowlessWindowManager wmm) {
return new SurfaceControlViewHost(c, d, wmm, "WindowDecoration");
}
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 ac67bd1..cf6cea2 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_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.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.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.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 @@
@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 @@
multiInstanceHelper,
shellExecutor,
Optional.of(desktopTasksLimiter),
+ recentTasksController
)
}
@@ -622,7 +629,7 @@
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 @@
}
@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 @@
}
@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 @@
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 @@
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/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
index aa2cee7..9c1dc22 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
@@ -26,6 +26,7 @@
import android.graphics.Rect
import android.hardware.display.DisplayManager
import android.hardware.display.VirtualDisplay
+import android.hardware.input.InputManager
import android.os.Handler
import android.platform.test.annotations.EnableFlags
import android.platform.test.annotations.RequiresFlagsEnabled
@@ -42,8 +43,10 @@
import android.view.InputMonitor
import android.view.InsetsSource
import android.view.InsetsState
+import android.view.KeyEvent
import android.view.SurfaceControl
import android.view.SurfaceView
+import android.view.View
import android.view.WindowInsets.Type.navigationBars
import android.view.WindowInsets.Type.statusBars
import androidx.test.filters.SmallTest
@@ -51,6 +54,7 @@
import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
import com.android.dx.mockito.inline.extended.StaticMockitoSession
import com.android.window.flags.Flags
+import com.android.wm.shell.R
import com.android.wm.shell.RootTaskDisplayAreaOrganizer
import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.ShellTestCase
@@ -61,6 +65,7 @@
import com.android.wm.shell.common.ShellExecutor
import com.android.wm.shell.common.SyncTransactionQueue
import com.android.wm.shell.desktopmode.DesktopTasksController
+import com.android.wm.shell.freeform.FreeformTaskTransitionStarter
import com.android.wm.shell.shared.DesktopModeStatus
import com.android.wm.shell.sysui.KeyguardChangeListener
import com.android.wm.shell.sysui.ShellCommandHandler
@@ -70,6 +75,7 @@
import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel.DesktopModeOnInsetsChangedListener
import java.util.Optional
import java.util.function.Supplier
+import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Rule
import org.junit.Test
@@ -279,6 +285,41 @@
}
@Test
+ fun testBackEventHasRightDisplayId() {
+ val secondaryDisplay = createVirtualDisplay() ?: return
+ val secondaryDisplayId = secondaryDisplay.display.displayId
+ val task = createTask(
+ displayId = secondaryDisplayId,
+ windowingMode = WINDOWING_MODE_FREEFORM
+ )
+ val windowDecor = setUpMockDecorationForTask(task)
+
+ onTaskOpening(task)
+ val onClickListenerCaptor = argumentCaptor<View.OnClickListener>()
+ verify(windowDecor).setCaptionListeners(
+ onClickListenerCaptor.capture(), any(), any(), any())
+
+ val onClickListener = onClickListenerCaptor.firstValue
+ val view = mock(View::class.java)
+ whenever(view.id).thenReturn(R.id.back_button)
+
+ val inputManager = mock(InputManager::class.java)
+ mContext.addMockSystemService(InputManager::class.java, inputManager)
+
+ val freeformTaskTransitionStarter = mock(FreeformTaskTransitionStarter::class.java)
+ desktopModeWindowDecorViewModel
+ .setFreeformTaskTransitionStarter(freeformTaskTransitionStarter)
+
+ onClickListener.onClick(view)
+
+ val eventCaptor = argumentCaptor<KeyEvent>()
+ verify(inputManager, times(2)).injectInputEvent(eventCaptor.capture(), anyInt())
+
+ assertEquals(secondaryDisplayId, eventCaptor.firstValue.displayId)
+ assertEquals(secondaryDisplayId, eventCaptor.secondValue.displayId)
+ }
+
+ @Test
fun testCaptionIsNotCreatedWhenKeyguardIsVisible() {
val task = createTask(windowingMode = WINDOWING_MODE_FULLSCREEN, focused = true)
val keyguardListenerCaptor = argumentCaptor<KeyguardChangeListener>()
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/ResizeVeilTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/ResizeVeilTest.kt
index 8742591..5da57c5 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/ResizeVeilTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/ResizeVeilTest.kt
@@ -33,6 +33,8 @@
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers.anyFloat
+import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
import org.mockito.Spy
import org.mockito.kotlin.any
@@ -102,6 +104,14 @@
.create("Resize veil icon of Task=" + taskInfo.taskId))
.thenReturn(spyIconSurfaceBuilder)
doReturn(mockIconSurface).whenever(spyIconSurfaceBuilder).build()
+
+ doReturn(mockTransaction).whenever(mockTransaction).setLayer(any(), anyInt())
+ doReturn(mockTransaction).whenever(mockTransaction).setAlpha(any(), anyFloat())
+ doReturn(mockTransaction).whenever(mockTransaction).show(any())
+ doReturn(mockTransaction).whenever(mockTransaction).hide(any())
+ doReturn(mockTransaction).whenever(mockTransaction)
+ .setPosition(any(), anyFloat(), anyFloat())
+ doReturn(mockTransaction).whenever(mockTransaction).setWindowCrop(any(), anyInt(), anyInt())
}
@Test
@@ -139,52 +149,48 @@
@Test
fun showVeil() {
val veil = createResizeVeil()
- val tx = mock<SurfaceControl.Transaction>()
- veil.showVeil(tx, mock(), Rect(0, 0, 100, 100), false /* fadeIn */)
+ veil.showVeil(mockTransaction, mock(), Rect(0, 0, 100, 100), false /* fadeIn */)
- verify(tx).show(mockResizeVeilSurface)
- verify(tx).show(mockBackgroundSurface)
- verify(tx).show(mockIconSurface)
- verify(tx).apply()
+ verify(mockTransaction).show(mockResizeVeilSurface)
+ verify(mockTransaction).show(mockBackgroundSurface)
+ verify(mockTransaction).show(mockIconSurface)
+ verify(mockTransaction).apply()
}
@Test
fun showVeil_displayUnavailable_doesNotShow() {
val veil = createResizeVeil(withDisplayAvailable = false)
- val tx = mock<SurfaceControl.Transaction>()
- veil.showVeil(tx, mock(), Rect(0, 0, 100, 100), false /* fadeIn */)
+ veil.showVeil(mockTransaction, mock(), Rect(0, 0, 100, 100), false /* fadeIn */)
- verify(tx, never()).show(mockResizeVeilSurface)
- verify(tx, never()).show(mockBackgroundSurface)
- verify(tx, never()).show(mockIconSurface)
- verify(tx).apply()
+ verify(mockTransaction, never()).show(mockResizeVeilSurface)
+ verify(mockTransaction, never()).show(mockBackgroundSurface)
+ verify(mockTransaction, never()).show(mockIconSurface)
+ verify(mockTransaction).apply()
}
@Test
fun showVeil_alreadyVisible_doesNotShowAgain() {
val veil = createResizeVeil()
- val tx = mock<SurfaceControl.Transaction>()
- veil.showVeil(tx, mock(), Rect(0, 0, 100, 100), false /* fadeIn */)
- veil.showVeil(tx, mock(), Rect(0, 0, 100, 100), false /* fadeIn */)
+ veil.showVeil(mockTransaction, mock(), Rect(0, 0, 100, 100), false /* fadeIn */)
+ veil.showVeil(mockTransaction, mock(), Rect(0, 0, 100, 100), false /* fadeIn */)
- verify(tx, times(1)).show(mockResizeVeilSurface)
- verify(tx, times(1)).show(mockBackgroundSurface)
- verify(tx, times(1)).show(mockIconSurface)
- verify(tx, times(2)).apply()
+ verify(mockTransaction, times(1)).show(mockResizeVeilSurface)
+ verify(mockTransaction, times(1)).show(mockBackgroundSurface)
+ verify(mockTransaction, times(1)).show(mockIconSurface)
+ verify(mockTransaction, times(2)).apply()
}
@Test
fun showVeil_reparentsVeilToNewParent() {
val veil = createResizeVeil(parent = mock())
- val tx = mock<SurfaceControl.Transaction>()
val newParent = mock<SurfaceControl>()
- veil.showVeil(tx, newParent, Rect(0, 0, 100, 100), false /* fadeIn */)
+ veil.showVeil(mockTransaction, newParent, Rect(0, 0, 100, 100), false /* fadeIn */)
- verify(tx).reparent(mockResizeVeilSurface, newParent)
+ verify(mockTransaction).reparent(mockResizeVeilSurface, newParent)
}
@Test
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index 679e8a1..5672cd5 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -681,8 +681,19 @@
/**
* 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 61b18c8..d21cb93 100644
--- a/media/tests/MediaRouter/Android.bp
+++ b/media/tests/MediaRouter/Android.bp
@@ -9,6 +9,7 @@
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 c5be208..fe8f59c 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 1b6491a..697ab63 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 78677b3..fb34edd 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 5c40ca82..39905de 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 48eb369..f2d4340 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 5ed73dd..d4f024a 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 12bdf3d..680c4e3 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 abf5551..b8571ec 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 ac2a689..b9a3e20 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 51f1a14..2490d81 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 009a6c6..0510240 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 7fe2153..1893704 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 c44cab5..b76c0fe 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 7717909..0e80d71 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 1e3d7e4..5094a29 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 939e1b4..1755c7a 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/DataStore/src/com/android/settingslib/datastore/BackupRestoreStorageManager.kt b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/BackupRestoreStorageManager.kt
index 8242347..b4a9172 100644
--- a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/BackupRestoreStorageManager.kt
+++ b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/BackupRestoreStorageManager.kt
@@ -138,7 +138,7 @@
private fun notifyBackupManager(key: Any?, reason: Int) {
val name = storage.name
// prefer not triggering backup immediately after restore
- if (reason == ChangeReason.RESTORE) {
+ if (reason == DataChangeReason.RESTORE) {
Log.d(
LOG_TAG,
"Notify BackupManager dataChanged ignored for restore: storage=$name key=$key"
@@ -161,8 +161,8 @@
fun notifyRestoreFinished() {
when (storage) {
- is KeyedObservable<*> -> storage.notifyChange(ChangeReason.RESTORE)
- is Observable -> storage.notifyChange(ChangeReason.RESTORE)
+ is KeyedObservable<*> -> storage.notifyChange(DataChangeReason.RESTORE)
+ is Observable -> storage.notifyChange(DataChangeReason.RESTORE)
}
}
}
diff --git a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/DataChangeReason.kt b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/DataChangeReason.kt
new file mode 100644
index 0000000..145fabe
--- /dev/null
+++ b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/DataChangeReason.kt
@@ -0,0 +1,43 @@
+/*
+ * 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.settingslib.datastore
+
+import androidx.annotation.IntDef
+
+/** The reason of data change. */
+@IntDef(
+ DataChangeReason.UNKNOWN,
+ DataChangeReason.UPDATE,
+ DataChangeReason.DELETE,
+ DataChangeReason.RESTORE,
+ DataChangeReason.SYNC_ACROSS_PROFILES,
+)
+@Retention(AnnotationRetention.SOURCE)
+annotation class DataChangeReason {
+ companion object {
+ /** Unknown reason of the change. */
+ const val UNKNOWN = 0
+ /** Data is updated. */
+ const val UPDATE = 1
+ /** Data is deleted. */
+ const val DELETE = 2
+ /** Data is restored from backup/restore framework. */
+ const val RESTORE = 3
+ /** Data is synced from another profile (e.g. personal profile to work profile). */
+ const val SYNC_ACROSS_PROFILES = 4
+ }
+}
diff --git a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/KeyedObserver.kt b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/KeyedObserver.kt
index 3ed4d46..ede7c63 100644
--- a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/KeyedObserver.kt
+++ b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/KeyedObserver.kt
@@ -37,7 +37,7 @@
* @param reason the reason of change
* @see KeyedObservable.addObserver
*/
- fun onKeyChanged(key: K, @ChangeReason reason: Int)
+ fun onKeyChanged(key: K, reason: Int)
}
/**
@@ -89,7 +89,7 @@
*
* @param reason reason of the change
*/
- fun notifyChange(@ChangeReason reason: Int)
+ fun notifyChange(reason: Int)
/**
* Notifies observers that a change occurs on given key.
@@ -99,7 +99,7 @@
* @param key key of the change
* @param reason reason of the change
*/
- fun notifyChange(key: K, @ChangeReason reason: Int)
+ fun notifyChange(key: K, reason: Int)
}
/** A thread safe implementation of [KeyedObservable]. */
@@ -141,7 +141,7 @@
}
}
- override fun notifyChange(@ChangeReason reason: Int) {
+ override fun notifyChange(reason: Int) {
// make a copy to avoid potential ConcurrentModificationException
val observers = synchronized(observers) { observers.entries.toTypedArray() }
val keyedObservers = synchronized(keyedObservers) { keyedObservers.copy() }
@@ -165,7 +165,7 @@
return result
}
- override fun notifyChange(key: K, @ChangeReason reason: Int) {
+ override fun notifyChange(key: K, reason: Int) {
// make a copy to avoid potential ConcurrentModificationException
val observers = synchronized(observers) { observers.entries.toTypedArray() }
val keyedObservers =
diff --git a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/Observer.kt b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/Observer.kt
index 6d0ca669..98d0f6e 100644
--- a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/Observer.kt
+++ b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/Observer.kt
@@ -18,34 +18,9 @@
import androidx.annotation.AnyThread
import androidx.annotation.GuardedBy
-import androidx.annotation.IntDef
import java.util.WeakHashMap
import java.util.concurrent.Executor
-/** The reason of a change. */
-@IntDef(
- ChangeReason.UNKNOWN,
- ChangeReason.UPDATE,
- ChangeReason.DELETE,
- ChangeReason.RESTORE,
- ChangeReason.SYNC_ACROSS_PROFILES,
-)
-@Retention(AnnotationRetention.SOURCE)
-annotation class ChangeReason {
- companion object {
- /** Unknown reason of the change. */
- const val UNKNOWN = 0
- /** Data is updated. */
- const val UPDATE = 1
- /** Data is deleted. */
- const val DELETE = 2
- /** Data is restored from backup/restore framework. */
- const val RESTORE = 3
- /** Data is synced from another profile (e.g. personal profile to work profile). */
- const val SYNC_ACROSS_PROFILES = 4
- }
-}
-
/**
* Callback to be informed of changes in [Observable] object.
*
@@ -60,7 +35,7 @@
* @param reason the reason of change
* @see [Observable.addObserver] for the notices.
*/
- fun onChanged(@ChangeReason reason: Int)
+ fun onChanged(reason: Int)
}
/** An observable object allows to observe change with [Observer]. */
@@ -90,7 +65,7 @@
*
* @param reason reason of the change
*/
- fun notifyChange(@ChangeReason reason: Int)
+ fun notifyChange(reason: Int)
}
/** A thread safe implementation of [Observable]. */
@@ -110,7 +85,7 @@
synchronized(observers) { observers.remove(observer) }
}
- override fun notifyChange(@ChangeReason reason: Int) {
+ override fun notifyChange(reason: Int) {
// make a copy to avoid potential ConcurrentModificationException
val entries = synchronized(observers) { observers.entries.toTypedArray() }
for (entry in entries) {
diff --git a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SharedPreferencesStorage.kt b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SharedPreferencesStorage.kt
index 9f9c0d8..20a95d7 100644
--- a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SharedPreferencesStorage.kt
+++ b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SharedPreferencesStorage.kt
@@ -83,10 +83,10 @@
private val sharedPreferencesListener =
SharedPreferences.OnSharedPreferenceChangeListener { _, key ->
if (key != null) {
- notifyChange(key, ChangeReason.UPDATE)
+ notifyChange(key, DataChangeReason.UPDATE)
} else {
// On Android >= R, SharedPreferences.Editor.clear() will trigger this case
- notifyChange(ChangeReason.DELETE)
+ notifyChange(DataChangeReason.DELETE)
}
}
diff --git a/packages/SettingsLib/DataStore/tests/src/com/android/settingslib/datastore/BackupRestoreStorageManagerTest.kt b/packages/SettingsLib/DataStore/tests/src/com/android/settingslib/datastore/BackupRestoreStorageManagerTest.kt
index d8f5028..19c574a 100644
--- a/packages/SettingsLib/DataStore/tests/src/com/android/settingslib/datastore/BackupRestoreStorageManagerTest.kt
+++ b/packages/SettingsLib/DataStore/tests/src/com/android/settingslib/datastore/BackupRestoreStorageManagerTest.kt
@@ -157,9 +157,9 @@
manager.onRestoreFinished()
- verify(keyedObserver).onKeyChanged("key", ChangeReason.RESTORE)
- verify(anyKeyObserver).onKeyChanged(null, ChangeReason.RESTORE)
- verify(observer).onChanged(ChangeReason.RESTORE)
+ verify(keyedObserver).onKeyChanged("key", DataChangeReason.RESTORE)
+ verify(anyKeyObserver).onKeyChanged(null, DataChangeReason.RESTORE)
+ verify(observer).onChanged(DataChangeReason.RESTORE)
if (isRobolectric()) {
Shadows.shadowOf(BackupManager(application)).apply {
assertThat(isDataChanged).isFalse()
@@ -186,8 +186,8 @@
assertThat(dataChangedCount).isEqualTo(0)
}
- fileStorage.notifyChange(ChangeReason.UPDATE)
- verify(observer).onChanged(ChangeReason.UPDATE)
+ fileStorage.notifyChange(DataChangeReason.UPDATE)
+ verify(observer).onChanged(DataChangeReason.UPDATE)
verify(keyedObserver, never()).onKeyChanged(any(), any())
verify(anyKeyObserver, never()).onKeyChanged(any(), any())
reset(observer)
@@ -196,10 +196,10 @@
assertThat(dataChangedCount).isEqualTo(1)
}
- keyedStorage.notifyChange("key", ChangeReason.DELETE)
+ keyedStorage.notifyChange("key", DataChangeReason.DELETE)
verify(observer, never()).onChanged(any())
- verify(keyedObserver).onKeyChanged("key", ChangeReason.DELETE)
- verify(anyKeyObserver).onKeyChanged("key", ChangeReason.DELETE)
+ verify(keyedObserver).onKeyChanged("key", DataChangeReason.DELETE)
+ verify(anyKeyObserver).onKeyChanged("key", DataChangeReason.DELETE)
backupManager?.apply {
assertThat(isDataChanged).isTrue()
assertThat(dataChangedCount).isEqualTo(2)
@@ -207,11 +207,11 @@
reset(keyedObserver)
// backup manager is not notified for restore event
- fileStorage.notifyChange(ChangeReason.RESTORE)
- keyedStorage.notifyChange("key", ChangeReason.RESTORE)
- verify(observer).onChanged(ChangeReason.RESTORE)
- verify(keyedObserver).onKeyChanged("key", ChangeReason.RESTORE)
- verify(anyKeyObserver).onKeyChanged("key", ChangeReason.RESTORE)
+ fileStorage.notifyChange(DataChangeReason.RESTORE)
+ keyedStorage.notifyChange("key", DataChangeReason.RESTORE)
+ verify(observer).onChanged(DataChangeReason.RESTORE)
+ verify(keyedObserver).onKeyChanged("key", DataChangeReason.RESTORE)
+ verify(anyKeyObserver).onKeyChanged("key", DataChangeReason.RESTORE)
backupManager?.apply {
assertThat(isDataChanged).isTrue()
assertThat(dataChangedCount).isEqualTo(2)
diff --git a/packages/SettingsLib/DataStore/tests/src/com/android/settingslib/datastore/KeyedObserverTest.kt b/packages/SettingsLib/DataStore/tests/src/com/android/settingslib/datastore/KeyedObserverTest.kt
index 8638b2f..0fdecb0 100644
--- a/packages/SettingsLib/DataStore/tests/src/com/android/settingslib/datastore/KeyedObserverTest.kt
+++ b/packages/SettingsLib/DataStore/tests/src/com/android/settingslib/datastore/KeyedObserverTest.kt
@@ -77,7 +77,7 @@
var observer: KeyedObserver<Any?>? = KeyedObserver { _, _ -> counter.incrementAndGet() }
keyedObservable.addObserver(observer!!, executor1)
- keyedObservable.notifyChange(ChangeReason.UPDATE)
+ keyedObservable.notifyChange(DataChangeReason.UPDATE)
assertThat(counter.get()).isEqualTo(1)
// trigger GC, the observer callback should not be invoked
@@ -85,7 +85,7 @@
System.gc()
System.runFinalization()
- keyedObservable.notifyChange(ChangeReason.UPDATE)
+ keyedObservable.notifyChange(DataChangeReason.UPDATE)
assertThat(counter.get()).isEqualTo(1)
}
@@ -95,7 +95,7 @@
var keyObserver: KeyedObserver<Any>? = KeyedObserver { _, _ -> counter.incrementAndGet() }
keyedObservable.addObserver(key1, keyObserver!!, executor1)
- keyedObservable.notifyChange(key1, ChangeReason.UPDATE)
+ keyedObservable.notifyChange(key1, DataChangeReason.UPDATE)
assertThat(counter.get()).isEqualTo(1)
// trigger GC, the observer callback should not be invoked
@@ -103,7 +103,7 @@
System.gc()
System.runFinalization()
- keyedObservable.notifyChange(key1, ChangeReason.UPDATE)
+ keyedObservable.notifyChange(key1, DataChangeReason.UPDATE)
assertThat(counter.get()).isEqualTo(1)
}
@@ -112,16 +112,16 @@
keyedObservable.addObserver(observer1, executor1)
keyedObservable.addObserver(observer2, executor2)
- keyedObservable.notifyChange(ChangeReason.UPDATE)
- verify(observer1).onKeyChanged(null, ChangeReason.UPDATE)
- verify(observer2).onKeyChanged(null, ChangeReason.UPDATE)
+ keyedObservable.notifyChange(DataChangeReason.UPDATE)
+ verify(observer1).onKeyChanged(null, DataChangeReason.UPDATE)
+ verify(observer2).onKeyChanged(null, DataChangeReason.UPDATE)
reset(observer1, observer2)
keyedObservable.removeObserver(observer2)
- keyedObservable.notifyChange(ChangeReason.DELETE)
- verify(observer1).onKeyChanged(null, ChangeReason.DELETE)
- verify(observer2, never()).onKeyChanged(null, ChangeReason.DELETE)
+ keyedObservable.notifyChange(DataChangeReason.DELETE)
+ verify(observer1).onKeyChanged(null, DataChangeReason.DELETE)
+ verify(observer2, never()).onKeyChanged(null, DataChangeReason.DELETE)
}
@Test
@@ -129,16 +129,16 @@
keyedObservable.addObserver(key1, keyedObserver1, executor1)
keyedObservable.addObserver(key2, keyedObserver2, executor2)
- keyedObservable.notifyChange(key1, ChangeReason.UPDATE)
- verify(keyedObserver1).onKeyChanged(key1, ChangeReason.UPDATE)
- verify(keyedObserver2, never()).onKeyChanged(key2, ChangeReason.UPDATE)
+ keyedObservable.notifyChange(key1, DataChangeReason.UPDATE)
+ verify(keyedObserver1).onKeyChanged(key1, DataChangeReason.UPDATE)
+ verify(keyedObserver2, never()).onKeyChanged(key2, DataChangeReason.UPDATE)
reset(keyedObserver1, keyedObserver2)
keyedObservable.removeObserver(key1, keyedObserver1)
- keyedObservable.notifyChange(key1, ChangeReason.DELETE)
- verify(keyedObserver1, never()).onKeyChanged(key1, ChangeReason.DELETE)
- verify(keyedObserver2, never()).onKeyChanged(key2, ChangeReason.DELETE)
+ keyedObservable.notifyChange(key1, DataChangeReason.DELETE)
+ verify(keyedObserver1, never()).onKeyChanged(key1, DataChangeReason.DELETE)
+ verify(keyedObserver2, never()).onKeyChanged(key2, DataChangeReason.DELETE)
}
@Test
@@ -147,24 +147,24 @@
keyedObservable.addObserver(key1, keyedObserver1, executor1)
keyedObservable.addObserver(key2, keyedObserver2, executor1)
- keyedObservable.notifyChange(ChangeReason.UPDATE)
- verify(observer1).onKeyChanged(null, ChangeReason.UPDATE)
- verify(keyedObserver1).onKeyChanged(key1, ChangeReason.UPDATE)
- verify(keyedObserver2).onKeyChanged(key2, ChangeReason.UPDATE)
+ keyedObservable.notifyChange(DataChangeReason.UPDATE)
+ verify(observer1).onKeyChanged(null, DataChangeReason.UPDATE)
+ verify(keyedObserver1).onKeyChanged(key1, DataChangeReason.UPDATE)
+ verify(keyedObserver2).onKeyChanged(key2, DataChangeReason.UPDATE)
reset(observer1, keyedObserver1, keyedObserver2)
- keyedObservable.notifyChange(key1, ChangeReason.UPDATE)
+ keyedObservable.notifyChange(key1, DataChangeReason.UPDATE)
- verify(observer1).onKeyChanged(key1, ChangeReason.UPDATE)
- verify(keyedObserver1).onKeyChanged(key1, ChangeReason.UPDATE)
- verify(keyedObserver2, never()).onKeyChanged(key1, ChangeReason.UPDATE)
+ verify(observer1).onKeyChanged(key1, DataChangeReason.UPDATE)
+ verify(keyedObserver1).onKeyChanged(key1, DataChangeReason.UPDATE)
+ verify(keyedObserver2, never()).onKeyChanged(key1, DataChangeReason.UPDATE)
reset(observer1, keyedObserver1, keyedObserver2)
- keyedObservable.notifyChange(key2, ChangeReason.UPDATE)
+ keyedObservable.notifyChange(key2, DataChangeReason.UPDATE)
- verify(observer1).onKeyChanged(key2, ChangeReason.UPDATE)
- verify(keyedObserver1, never()).onKeyChanged(key2, ChangeReason.UPDATE)
- verify(keyedObserver2).onKeyChanged(key2, ChangeReason.UPDATE)
+ verify(observer1).onKeyChanged(key2, DataChangeReason.UPDATE)
+ verify(keyedObserver1, never()).onKeyChanged(key2, DataChangeReason.UPDATE)
+ verify(keyedObserver2).onKeyChanged(key2, DataChangeReason.UPDATE)
}
@Test
@@ -176,7 +176,7 @@
keyedObservable.addObserver(observer, executor1)
- keyedObservable.notifyChange(ChangeReason.UPDATE)
+ keyedObservable.notifyChange(DataChangeReason.UPDATE)
keyedObservable.removeObserver(observer)
}
@@ -189,7 +189,7 @@
keyedObservable.addObserver(key1, keyObserver, executor1)
- keyedObservable.notifyChange(key1, ChangeReason.UPDATE)
+ keyedObservable.notifyChange(key1, DataChangeReason.UPDATE)
keyedObservable.removeObserver(key1, keyObserver)
}
}
diff --git a/packages/SettingsLib/DataStore/tests/src/com/android/settingslib/datastore/ObserverTest.kt b/packages/SettingsLib/DataStore/tests/src/com/android/settingslib/datastore/ObserverTest.kt
index 173c2b1..5d0303c 100644
--- a/packages/SettingsLib/DataStore/tests/src/com/android/settingslib/datastore/ObserverTest.kt
+++ b/packages/SettingsLib/DataStore/tests/src/com/android/settingslib/datastore/ObserverTest.kt
@@ -58,7 +58,7 @@
var observer: Observer? = Observer { counter.incrementAndGet() }
observable.addObserver(observer!!, executor1)
- observable.notifyChange(ChangeReason.UPDATE)
+ observable.notifyChange(DataChangeReason.UPDATE)
assertThat(counter.get()).isEqualTo(1)
// trigger GC, the observer callback should not be invoked
@@ -66,7 +66,7 @@
System.gc()
System.runFinalization()
- observable.notifyChange(ChangeReason.UPDATE)
+ observable.notifyChange(DataChangeReason.UPDATE)
assertThat(counter.get()).isEqualTo(1)
}
@@ -75,17 +75,17 @@
observable.addObserver(observer1, executor1)
observable.addObserver(observer2, executor2)
- observable.notifyChange(ChangeReason.DELETE)
+ observable.notifyChange(DataChangeReason.DELETE)
- verify(observer1).onChanged(ChangeReason.DELETE)
- verify(observer2).onChanged(ChangeReason.DELETE)
+ verify(observer1).onChanged(DataChangeReason.DELETE)
+ verify(observer2).onChanged(DataChangeReason.DELETE)
reset(observer1, observer2)
observable.removeObserver(observer2)
- observable.notifyChange(ChangeReason.UPDATE)
- verify(observer1).onChanged(ChangeReason.UPDATE)
- verify(observer2, never()).onChanged(ChangeReason.UPDATE)
+ observable.notifyChange(DataChangeReason.UPDATE)
+ verify(observer1).onChanged(DataChangeReason.UPDATE)
+ verify(observer2, never()).onChanged(DataChangeReason.UPDATE)
}
@Test
@@ -93,7 +93,7 @@
// ConcurrentModificationException is raised if it is not implemented correctly
val observer = Observer { observable.addObserver(observer1, executor1) }
observable.addObserver(observer, executor1)
- observable.notifyChange(ChangeReason.UPDATE)
+ observable.notifyChange(DataChangeReason.UPDATE)
observable.removeObserver(observer)
}
}
diff --git a/packages/SettingsLib/DataStore/tests/src/com/android/settingslib/datastore/SharedPreferencesStorageTest.kt b/packages/SettingsLib/DataStore/tests/src/com/android/settingslib/datastore/SharedPreferencesStorageTest.kt
index fec7d75..a135d77 100644
--- a/packages/SettingsLib/DataStore/tests/src/com/android/settingslib/datastore/SharedPreferencesStorageTest.kt
+++ b/packages/SettingsLib/DataStore/tests/src/com/android/settingslib/datastore/SharedPreferencesStorageTest.kt
@@ -80,13 +80,13 @@
storage.addObserver("key", keyedObserver, executor)
storage.sharedPreferences.edit().putString("key", "string").applySync()
- verify(observer).onKeyChanged("key", ChangeReason.UPDATE)
- verify(keyedObserver).onKeyChanged("key", ChangeReason.UPDATE)
+ verify(observer).onKeyChanged("key", DataChangeReason.UPDATE)
+ verify(keyedObserver).onKeyChanged("key", DataChangeReason.UPDATE)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
storage.sharedPreferences.edit().clear().applySync()
- verify(observer).onKeyChanged(null, ChangeReason.DELETE)
- verify(keyedObserver).onKeyChanged("key", ChangeReason.DELETE)
+ verify(observer).onKeyChanged(null, DataChangeReason.DELETE)
+ verify(keyedObserver).onKeyChanged("key", DataChangeReason.DELETE)
}
}
diff --git a/packages/SettingsLib/ProfileSelector/res/values-cs/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-cs/strings.xml
index d50fc9a..3e5f526 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 628388d..b1bc69c 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 75668e8..b7aa61b 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 21419e6..c9faa3c3 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 07cf9c7..e8c2bf5 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 e1e68c7..1e4abc1 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 ee4212f..e0b1471 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 59f21c8..e4e2bdc 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/Spa/spa/src/com/android/settingslib/spa/framework/compose/LifecycleEffect.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/LifecycleEffect.kt
index e91fa65..e9f9689 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/LifecycleEffect.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/LifecycleEffect.kt
@@ -18,9 +18,9 @@
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
-import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
+import androidx.lifecycle.compose.LocalLifecycleOwner
@Composable
fun LifecycleEffect(
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/OnBackEffect.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/OnBackEffect.kt
index 3991f26..0b1c92d 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/OnBackEffect.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/OnBackEffect.kt
@@ -24,7 +24,7 @@
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
-import androidx.compose.ui.platform.LocalLifecycleOwner
+import androidx.lifecycle.compose.LocalLifecycleOwner
/**
* An effect for detecting presses of the system back button, and the back event will not be
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/slice/presenter/Demo.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/slice/presenter/Demo.kt
index ee24a09..007f47b 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/slice/presenter/Demo.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/slice/presenter/Demo.kt
@@ -21,8 +21,8 @@
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext
-import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.viewinterop.AndroidView
+import androidx.lifecycle.compose.LocalLifecycleOwner
import androidx.slice.widget.SliceLiveData
import androidx.slice.widget.SliceView
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/dialog/SettingsAlertDialog.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/dialog/SettingsAlertDialog.kt
index de080e3..022dded 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/dialog/SettingsAlertDialog.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/dialog/SettingsAlertDialog.kt
@@ -38,6 +38,7 @@
data class AlertDialogButton(
val text: String,
+ val enabled: Boolean = true,
val onClick: () -> Unit = {},
)
@@ -114,6 +115,7 @@
close()
button.onClick()
},
+ enabled = button.enabled,
) {
Text(button.text)
}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/editor/DropdownTextBox.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/editor/DropdownTextBox.kt
index b471e50..bdbe62c 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/editor/DropdownTextBox.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/editor/DropdownTextBox.kt
@@ -22,6 +22,7 @@
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExposedDropdownMenuBox
import androidx.compose.material3.ExposedDropdownMenuDefaults
+import androidx.compose.material3.MenuAnchorType
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@@ -65,7 +66,7 @@
OutlinedTextField(
// The `menuAnchor` modifier must be passed to the text field for correctness.
modifier = Modifier
- .menuAnchor()
+ .menuAnchor(MenuAnchorType.PrimaryNotEditable)
.fillMaxWidth(),
value = text,
onValueChange = { },
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/compose/LifecycleEffectTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/compose/LifecycleEffectTest.kt
index fe7baff..8b0efff 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/compose/LifecycleEffectTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/compose/LifecycleEffectTest.kt
@@ -18,9 +18,9 @@
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.compose.LocalLifecycleOwner
import androidx.lifecycle.testing.TestLifecycleOwner
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.common.truth.Truth.assertThat
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/dialog/SettingsAlertDialogTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/dialog/SettingsAlertDialogTest.kt
index 9468f95..20ea397 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/dialog/SettingsAlertDialogTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/dialog/SettingsAlertDialogTest.kt
@@ -20,6 +20,8 @@
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.assertIsEnabled
+import androidx.compose.ui.test.assertIsNotEnabled
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.performClick
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -67,7 +69,18 @@
rememberAlertDialogPresenter(confirmButton = AlertDialogButton(CONFIRM_TEXT))
}
- composeTestRule.onDialogText(CONFIRM_TEXT).assertIsDisplayed()
+ composeTestRule.onDialogText(CONFIRM_TEXT).assertIsDisplayed().assertIsEnabled()
+ }
+
+ @Test
+ fun confirmButton_disabled() {
+ setAndOpenDialog {
+ rememberAlertDialogPresenter(
+ confirmButton = AlertDialogButton(text = CONFIRM_TEXT, enabled = false)
+ )
+ }
+
+ composeTestRule.onDialogText(CONFIRM_TEXT).assertIsDisplayed().assertIsNotEnabled()
}
@Test
@@ -90,7 +103,18 @@
rememberAlertDialogPresenter(dismissButton = AlertDialogButton(DISMISS_TEXT))
}
- composeTestRule.onDialogText(DISMISS_TEXT).assertIsDisplayed()
+ composeTestRule.onDialogText(DISMISS_TEXT).assertIsDisplayed().assertIsEnabled()
+ }
+
+ @Test
+ fun dismissButton_disabled() {
+ setAndOpenDialog {
+ rememberAlertDialogPresenter(
+ dismissButton = AlertDialogButton(text = DISMISS_TEXT, enabled = false)
+ )
+ }
+
+ composeTestRule.onDialogText(DISMISS_TEXT).assertIsDisplayed().assertIsNotEnabled()
}
@Test
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/scaffold/RestrictedMenuItem.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/scaffold/RestrictedMenuItem.kt
index 977615b..f95cfc3 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/scaffold/RestrictedMenuItem.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/scaffold/RestrictedMenuItem.kt
@@ -30,22 +30,24 @@
@Composable
fun MoreOptionsScope.RestrictedMenuItem(
text: String,
+ enabled: Boolean = true,
restrictions: Restrictions,
onClick: () -> Unit,
) {
- RestrictedMenuItemImpl(text, restrictions, onClick, ::RestrictionsProviderImpl)
+ RestrictedMenuItemImpl(text, enabled, restrictions, onClick, ::RestrictionsProviderImpl)
}
@VisibleForTesting
@Composable
internal fun MoreOptionsScope.RestrictedMenuItemImpl(
text: String,
+ enabled: Boolean = true,
restrictions: Restrictions,
onClick: () -> Unit,
restrictionsProviderFactory: RestrictionsProviderFactory,
) {
val restrictedMode = restrictionsProviderFactory.rememberRestrictedMode(restrictions).value
- MenuItem(text = text, enabled = restrictedMode !== BaseUserRestricted) {
+ MenuItem(text = text, enabled = enabled && restrictedMode !== BaseUserRestricted) {
when (restrictedMode) {
is BlockedByAdmin -> restrictedMode.sendShowAdminSupportDetailsIntent()
is BlockedByEcm -> restrictedMode.showRestrictedSettingsDetails()
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/scaffold/RestrictedMenuItemTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/scaffold/RestrictedMenuItemTest.kt
index 556adc7..4068bce 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/scaffold/RestrictedMenuItemTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/scaffold/RestrictedMenuItemTest.kt
@@ -49,6 +49,15 @@
private var menuItemOnClickIsCalled = false
@Test
+ fun whenDisabled() {
+ val restrictions = Restrictions(userId = USER_ID, keys = emptyList())
+
+ setContent(restrictions, enabled = false)
+
+ composeTestRule.onNodeWithText(TEXT).assertIsDisplayed().assertIsNotEnabled()
+ }
+
+ @Test
fun whenRestrictionsKeysIsEmpty_enabled() {
val restrictions = Restrictions(userId = USER_ID, keys = emptyList())
@@ -153,13 +162,14 @@
assertThat(menuItemOnClickIsCalled).isFalse()
}
- private fun setContent(restrictions: Restrictions) {
+ private fun setContent(restrictions: Restrictions, enabled: Boolean = true) {
val fakeMoreOptionsScope = object : MoreOptionsScope() {
override fun dismiss() {}
}
composeTestRule.setContent {
fakeMoreOptionsScope.RestrictedMenuItemImpl(
text = TEXT,
+ enabled = enabled,
restrictions = restrictions,
onClick = { menuItemOnClickIsCalled = true },
restrictionsProviderFactory = { _, _ -> fakeRestrictionsProvider },
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index 3f39d4d..d021647 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 b9961b9..1533a19 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 240b0f0..194c616 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 f549ae2..94d4297 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 8f83216..f66499f 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 66be184..47cdcca 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 630dd64..b2456d3 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 04c8a40..c4677be 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 afda7cb..014ba26 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 c79db5f..6aea659 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 04922d6..c8992c3 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.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 @@
// 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 @@
@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 @@
+ 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 @@
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 @@
}
}
+ 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 @@
}
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 @@
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 @@
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 @@
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 @@
@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 @@
}
}
}
-
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 244c8c4..256b999 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 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 @@
.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 @@
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 @@
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 @@
.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 @@
@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 @@
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 @@
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 @@
.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 @@
.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 @@
"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 @@
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 @@
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 55edff6..d201071 100644
--- a/packages/SystemUI/aconfig/accessibility.aconfig
+++ b/packages/SystemUI/aconfig/accessibility.aconfig
@@ -81,3 +81,13 @@
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 36bad5e..7ce8f98 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -184,6 +184,13 @@
}
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 {
+ 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"
@@ -1012,3 +1026,13 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "notification_media_manager_background_execution"
+ namespace: "systemui"
+ description: "Decide whether to execute binder calls in background thread"
+ bug: "336612071"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
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 b124025..978943ae 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 @@
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/communal/ui/compose/CommunalHub.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
index cd27d57..9dd3d39 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
@@ -23,6 +23,7 @@
import android.view.View.IMPORTANT_FOR_ACCESSIBILITY_AUTO
import android.view.View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
import android.widget.FrameLayout
+import androidx.annotation.VisibleForTesting
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.AnimatedVisibilityScope
import androidx.compose.animation.ExperimentalAnimationApi
@@ -162,7 +163,6 @@
var removeButtonCoordinates: LayoutCoordinates? by remember { mutableStateOf(null) }
var toolbarSize: IntSize? by remember { mutableStateOf(null) }
var gridCoordinates: LayoutCoordinates? by remember { mutableStateOf(null) }
- var isDraggingToRemove by remember { mutableStateOf(false) }
val gridState = rememberLazyGridState()
val contentListState = rememberContentListState(widgetConfigurator, communalContent, viewModel)
val reorderingWidgets by viewModel.reorderingWidgets.collectAsStateWithLifecycle()
@@ -250,12 +250,11 @@
contentOffset = contentOffset,
setGridCoordinates = { gridCoordinates = it },
updateDragPositionForRemove = { offset ->
- isDraggingToRemove =
- isPointerWithinCoordinates(
- offset = gridCoordinates?.let { it.positionInWindow() + offset },
- containerToCheck = removeButtonCoordinates
- )
- isDraggingToRemove
+ isPointerWithinEnabledRemoveButton(
+ removeEnabled = removeButtonEnabled,
+ offset = gridCoordinates?.let { it.positionInWindow() + offset },
+ containerToCheck = removeButtonCoordinates
+ )
},
gridState = gridState,
contentListState = contentListState,
@@ -640,11 +639,16 @@
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 +662,7 @@
animationSpec =
tween(
durationMillis = 167,
- delayMillis = 500,
+ delayMillis = 83,
easing = LinearEasing
)
),
@@ -1195,11 +1199,13 @@
* Check whether the pointer position that the item is being dragged at is within the coordinates of
* the remove button in the toolbar. Returns true if the item is removable.
*/
-private fun isPointerWithinCoordinates(
+@VisibleForTesting
+fun isPointerWithinEnabledRemoveButton(
+ removeEnabled: Boolean,
offset: Offset?,
containerToCheck: LayoutCoordinates?
): Boolean {
- if (offset == null || containerToCheck == null) {
+ if (!removeEnabled || offset == null || containerToCheck == null) {
return false
}
val container = containerToCheck.boundsInWindow()
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlider.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlider.kt
index 271eb96..fbf91b7 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlider.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlider.kt
@@ -68,9 +68,7 @@
state.a11yClickDescription?.let {
customActions =
listOf(
- CustomAccessibilityAction(
- it,
- ) {
+ CustomAccessibilityAction(it) {
onIconTapped()
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 d2a1de3..f0fb9f6 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 @@
transition: TransitionState.Transition,
previousTransition: TransitionState.Transition,
) {
- val previousUniqueState = reconcileStates(element, previousTransition)
- if (previousUniqueState == null) {
- reconcileStates(element, transition)
- return
- }
+ val sceneStates = element.sceneStates
+ sceneStates[previousTransition.fromScene]?.selfUpdateValuesBeforeInterruption()
+ sceneStates[previousTransition.toScene]?.selfUpdateValuesBeforeInterruption()
+ sceneStates[transition.fromScene]?.selfUpdateValuesBeforeInterruption()
+ sceneStates[transition.toScene]?.selfUpdateValuesBeforeInterruption()
- 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)
- }
+ 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
- }
+) {
+ val fromSceneState = element.sceneStates[transition.fromScene] ?: return
+ val toSceneState = element.sceneStates[transition.toScene] ?: return
+ if (!isSharedElementEnabled(element.key, transition)) {
+ return
+ }
- // 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
- }
-
- // 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 bdeab79..079c1d9 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 @@
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.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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
*/
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 @@
textAnimator?.let {
it.setTextStyle(
weight = weight,
- textSize = textSize,
color = color,
animate = animate && isAnimationEnabled,
duration = duration,
@@ -474,7 +463,6 @@
onTextAnimatorInitialized = { textAnimator ->
textAnimator.setTextStyle(
weight = weight,
- textSize = textSize,
color = color,
animate = false,
duration = duration,
@@ -487,27 +475,6 @@
}
}
- 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/communal/data/repository/CommunalRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalRepositoryImplTest.kt
index 45e7d8a..fd0bf4d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalRepositoryImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalRepositoryImplTest.kt
@@ -41,6 +41,7 @@
private val underTest by lazy {
CommunalSceneRepositoryImpl(
kosmos.applicationCoroutineScope,
+ kosmos.applicationCoroutineScope,
kosmos.sceneDataSource,
)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/compose/CommunalHubUtilsTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/compose/CommunalHubUtilsTest.kt
new file mode 100644
index 0000000..643063e7
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/compose/CommunalHubUtilsTest.kt
@@ -0,0 +1,41 @@
+/*
+ * 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.communal.ui.compose
+
+import android.testing.TestableLooper
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.layout.LayoutCoordinates
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.mock
+
+@RunWith(AndroidJUnit4::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@SmallTest
+class CommunalHubUtilsTest : SysuiTestCase() {
+ @Test
+ fun isPointerWithinEnabledRemoveButton_ensureDisabledStatePriority() {
+ assertThat(
+ isPointerWithinEnabledRemoveButton(false, mock<Offset>(), mock<LayoutCoordinates>())
+ )
+ .isFalse()
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt
index a3a4952..ee8a22c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt
@@ -397,6 +397,9 @@
verify(mStateController).setOverlayActive(false)
verify(mStateController).setLowLightActive(false)
verify(mStateController).setEntryAnimationsFinished(false)
+
+ // Verify touch monitor destroyed
+ verify(mTouchMonitor).destroy()
}
@Test
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 29fbee0..7936ccc 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 @@
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 26fcb23..49d0399 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 @@
.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 99a0185..9ab1ac1 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.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 @@
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 567e0a9..159ce36 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.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.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 @@
.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 2d77f4f..78a1167 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 @@
.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
similarity index 78%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt
index 2b8a644..9dc930b 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.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 @@
}
@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/statusbar/NotificationMediaManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationMediaManagerTest.kt
index a67a8ab..fed6131 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationMediaManagerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationMediaManagerTest.kt
@@ -16,6 +16,10 @@
package com.android.systemui.statusbar
+import android.media.MediaMetadata
+import android.media.session.MediaController
+import android.media.session.MediaSession
+import android.os.fakeExecutorHandler
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.service.notification.NotificationListenerService
@@ -54,6 +58,7 @@
private val notifPipeline = kosmos.notifPipeline
private val notifCollection = kosmos.mockNotifCollection
private val dumpManager = kosmos.dumpManager
+ private val handler = kosmos.fakeExecutorHandler
private val mediaDataManager = mock<MediaDataManager>()
private val backgroundExecutor = FakeExecutor(FakeSystemClock())
@@ -72,7 +77,11 @@
mediaDataManager,
dumpManager,
backgroundExecutor,
+ handler,
)
+ val mediaSession = MediaSession(context, "TEST")
+ notificationMediaManager.mMediaController =
+ MediaController(context, mediaSession.sessionToken)
verify(mediaDataManager).addListener(listenerCaptor.capture())
}
@@ -114,4 +123,32 @@
verify(notifCollection).dismissNotification(notifEntryCaptor.capture(), any())
assertThat(notifEntryCaptor.lastValue.key).isEqualTo(KEY)
}
+
+ @Test
+ @EnableFlags(Flags.FLAG_NOTIFICATION_MEDIA_MANAGER_BACKGROUND_EXECUTION)
+ fun clearMediaNotification_flagOn_resetMediaMetadata() {
+ // set up media metadata.
+ notificationMediaManager.mMediaListener.onMetadataChanged(MediaMetadata.Builder().build())
+ backgroundExecutor.runAllReady()
+
+ // clear media notification.
+ notificationMediaManager.clearCurrentMediaNotification()
+ backgroundExecutor.runAllReady()
+
+ assertThat(notificationMediaManager.mediaMetadata).isNull()
+ assertThat(notificationMediaManager.mMediaController).isNull()
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_NOTIFICATION_MEDIA_MANAGER_BACKGROUND_EXECUTION)
+ fun clearMediaNotification_flagOff_resetMediaMetadata() {
+ // set up media metadata.
+ notificationMediaManager.mMediaListener.onMetadataChanged(MediaMetadata.Builder().build())
+
+ // clear media notification.
+ notificationMediaManager.clearCurrentMediaNotification()
+
+ assertThat(notificationMediaManager.mediaMetadata).isNull()
+ assertThat(notificationMediaManager.mMediaController).isNull()
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/interactor/AudioOutputInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/interactor/AudioOutputInteractorTest.kt
index cec8ccf..b83b93b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/interactor/AudioOutputInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/interactor/AudioOutputInteractorTest.kt
@@ -18,33 +18,26 @@
import android.bluetooth.BluetoothDevice
import android.graphics.drawable.TestStubDrawable
-import android.media.AudioDeviceInfo
-import android.media.AudioDevicePort
import android.media.AudioManager
import android.testing.TestableLooper
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.settingslib.R
import com.android.settingslib.bluetooth.CachedBluetoothDevice
-import com.android.settingslib.media.BluetoothMediaDevice
-import com.android.settingslib.media.MediaDevice
-import com.android.settingslib.media.PhoneMediaDevice
import com.android.systemui.SysuiTestCase
import com.android.systemui.bluetooth.bluetoothAdapter
import com.android.systemui.bluetooth.cachedBluetoothDeviceManager
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.testScope
import com.android.systemui.testKosmos
-import com.android.systemui.util.mockito.any
-import com.android.systemui.util.mockito.eq
-import com.android.systemui.util.mockito.mock
-import com.android.systemui.util.mockito.whenever
+import com.android.systemui.volume.data.repository.TestAudioDevicesFactory
import com.android.systemui.volume.data.repository.audioRepository
import com.android.systemui.volume.data.repository.audioSharingRepository
import com.android.systemui.volume.domain.model.AudioOutputDevice
import com.android.systemui.volume.localMediaController
import com.android.systemui.volume.localMediaRepository
import com.android.systemui.volume.mediaControllerRepository
+import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.TestMediaDevicesFactory
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runCurrent
@@ -52,6 +45,10 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.kotlin.any
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
@OptIn(ExperimentalCoroutinesApi::class)
@RunWith(AndroidJUnit4::class)
@@ -84,7 +81,7 @@
testScope.runTest {
with(audioRepository) {
setMode(AudioManager.MODE_IN_CALL)
- setCommunicationDevice(builtInDevice)
+ setCommunicationDevice(TestAudioDevicesFactory.builtInDevice())
}
val device by collectLastValue(underTest.currentAudioDevice)
@@ -104,7 +101,7 @@
testScope.runTest {
with(audioRepository) {
setMode(AudioManager.MODE_IN_CALL)
- setCommunicationDevice(wiredDevice)
+ setCommunicationDevice(TestAudioDevicesFactory.wiredDevice())
}
val device by collectLastValue(underTest.currentAudioDevice)
@@ -122,17 +119,18 @@
fun inCall_bluetooth_returnsCommunicationDevice() {
with(kosmos) {
testScope.runTest {
+ val btDevice = TestAudioDevicesFactory.bluetoothDevice()
with(audioRepository) {
setMode(AudioManager.MODE_IN_CALL)
setCommunicationDevice(btDevice)
}
val bluetoothDevice: BluetoothDevice = mock {
- whenever(address).thenReturn(btDevice.address)
+ on { address }.thenReturn(btDevice.address)
}
val cachedBluetoothDevice: CachedBluetoothDevice = mock {
- whenever(address).thenReturn(btDevice.address)
- whenever(name).thenReturn(btDevice.productName.toString())
- whenever(isHearingAidDevice).thenReturn(true)
+ on { address }.thenReturn(btDevice.address)
+ on { name }.thenReturn(btDevice.productName.toString())
+ on { isHearingAidDevice }.thenReturn(true)
}
whenever(bluetoothAdapter.getRemoteDevice(eq(btDevice.address)))
.thenReturn(bluetoothDevice)
@@ -156,7 +154,9 @@
testScope.runTest {
audioRepository.setMode(AudioManager.MODE_NORMAL)
mediaControllerRepository.setActiveSessions(listOf(localMediaController))
- localMediaRepository.updateCurrentConnectedDevice(builtInMediaDevice)
+ localMediaRepository.updateCurrentConnectedDevice(
+ TestMediaDevicesFactory.builtInMediaDevice()
+ )
val device by collectLastValue(underTest.currentAudioDevice)
@@ -175,7 +175,9 @@
testScope.runTest {
audioRepository.setMode(AudioManager.MODE_NORMAL)
mediaControllerRepository.setActiveSessions(listOf(localMediaController))
- localMediaRepository.updateCurrentConnectedDevice(wiredMediaDevice)
+ localMediaRepository.updateCurrentConnectedDevice(
+ TestMediaDevicesFactory.wiredMediaDevice()
+ )
val device by collectLastValue(underTest.currentAudioDevice)
@@ -194,7 +196,9 @@
testScope.runTest {
audioRepository.setMode(AudioManager.MODE_NORMAL)
mediaControllerRepository.setActiveSessions(listOf(localMediaController))
- localMediaRepository.updateCurrentConnectedDevice(bluetoothMediaDevice)
+ localMediaRepository.updateCurrentConnectedDevice(
+ TestMediaDevicesFactory.bluetoothMediaDevice()
+ )
val device by collectLastValue(underTest.currentAudioDevice)
@@ -208,48 +212,8 @@
}
private companion object {
+
val testIcon = TestStubDrawable()
- val builtInDevice =
- AudioDeviceInfo(
- AudioDevicePort.createForTesting(
- AudioDeviceInfo.TYPE_BUILTIN_SPEAKER,
- "built_in",
- ""
- )
- )
- val wiredDevice =
- AudioDeviceInfo(
- AudioDevicePort.createForTesting(AudioDeviceInfo.TYPE_WIRED_HEADPHONES, "wired", "")
- )
- val btDevice =
- AudioDeviceInfo(
- AudioDevicePort.createForTesting(
- AudioDeviceInfo.TYPE_BLE_HEADSET,
- "bt",
- "test_address"
- )
- )
- val builtInMediaDevice: MediaDevice =
- mock<PhoneMediaDevice> {
- whenever(name).thenReturn("built_in_media")
- whenever(icon).thenReturn(testIcon)
- }
- val wiredMediaDevice: MediaDevice =
- mock<PhoneMediaDevice> {
- whenever(deviceType)
- .thenReturn(MediaDevice.MediaDeviceType.TYPE_3POINT5_MM_AUDIO_DEVICE)
- whenever(name).thenReturn("wired_media")
- whenever(icon).thenReturn(testIcon)
- }
- val bluetoothMediaDevice: MediaDevice =
- mock<BluetoothMediaDevice> {
- whenever(name).thenReturn("bt_media")
- whenever(icon).thenReturn(testIcon)
- val cachedBluetoothDevice: CachedBluetoothDevice = mock {
- whenever(isHearingAidDevice).thenReturn(true)
- }
- whenever(cachedDevice).thenReturn(cachedBluetoothDevice)
- }
}
@Test
diff --git a/packages/SystemUI/res/drawable/ic_widgets.xml b/packages/SystemUI/res/drawable/ic_widgets.xml
new file mode 100644
index 0000000..b21d047
--- /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 0000000..627b92b
--- /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-sw600dp/biometric_prompt_constraint_layout.xml b/packages/SystemUI/res/layout-sw600dp/biometric_prompt_constraint_layout.xml
deleted file mode 100644
index 8b9eabc..0000000
--- a/packages/SystemUI/res/layout-sw600dp/biometric_prompt_constraint_layout.xml
+++ /dev/null
@@ -1,237 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- xmlns:tools="http://schemas.android.com/tools"
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
- android:id="@+id/biometric_prompt_constraint_layout"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <ImageView
- android:id="@+id/background"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:contentDescription="@string/biometric_dialog_empty_space_description"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent" />
-
- <View
- android:id="@+id/panel"
- style="@style/AuthCredentialPanelStyle"
- android:layout_width="0dp"
- android:layout_height="0dp"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toStartOf="@+id/rightGuideline"
- app:layout_constraintStart_toStartOf="@+id/leftGuideline"
- app:layout_constraintTop_toTopOf="@+id/topBarrier"
- app:layout_constraintWidth_max="640dp" />
-
- <include
- android:id="@+id/button_bar"
- layout="@layout/biometric_prompt_button_bar"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- app:layout_constraintBottom_toBottomOf="@id/bottomGuideline"
- app:layout_constraintEnd_toEndOf="@id/panel"
- app:layout_constraintStart_toStartOf="@id/panel" />
-
- <ScrollView
- android:id="@+id/scrollView"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:fadeScrollbars="false"
- android:fillViewport="true"
- android:paddingBottom="32dp"
- android:paddingHorizontal="32dp"
- android:paddingTop="24dp"
- app:layout_constrainedHeight="true"
- app:layout_constrainedWidth="true"
- app:layout_constraintBottom_toTopOf="@+id/scrollBarrier"
- app:layout_constraintEnd_toEndOf="@id/panel"
- app:layout_constraintStart_toStartOf="@id/panel"
- app:layout_constraintTop_toTopOf="@+id/topGuideline"
- app:layout_constraintVertical_bias="1.0">
-
- <androidx.constraintlayout.widget.ConstraintLayout
- android:id="@+id/innerConstraint"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
-
- <ImageView
- android:id="@+id/logo"
- android:layout_width="@dimen/biometric_prompt_logo_size"
- android:layout_height="@dimen/biometric_prompt_logo_size"
- android:layout_gravity="center"
- android:contentDescription="@string/biometric_dialog_logo"
- android:scaleType="fitXY"
- android:visibility="visible"
- app:layout_constraintBottom_toTopOf="@+id/logo_description"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent" />
-
- <TextView
- android:id="@+id/logo_description"
- style="@style/TextAppearance.AuthCredential.LogoDescription"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="16dp"
- app:layout_constraintBottom_toTopOf="@+id/title"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/logo" />
-
- <TextView
- android:id="@+id/title"
- style="@style/TextAppearance.AuthCredential.Title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="@integer/biometric_dialog_text_gravity"
- android:paddingTop="16dp"
- app:layout_constraintBottom_toTopOf="@+id/subtitle"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/logo_description" />
-
- <TextView
- android:id="@+id/subtitle"
- style="@style/TextAppearance.AuthCredential.Subtitle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="@integer/biometric_dialog_text_gravity"
- android:paddingTop="16dp"
- app:layout_constraintBottom_toTopOf="@+id/contentBarrier"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/title" />
-
- <LinearLayout
- android:id="@+id/customized_view_container"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center_vertical"
- android:orientation="vertical"
- android:paddingTop="24dp"
- android:visibility="gone"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/subtitle" />
-
- <TextView
- android:id="@+id/description"
- style="@style/TextAppearance.AuthCredential.Description"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="@integer/biometric_dialog_text_gravity"
- android:paddingTop="16dp"
- android:textAlignment="viewStart"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/subtitle" />
-
- <androidx.constraintlayout.widget.Barrier
- android:id="@+id/contentBarrier"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- app:barrierAllowsGoneWidgets="false"
- app:barrierDirection="top"
- app:constraint_referenced_ids="description, customized_view_container" />
-
- </androidx.constraintlayout.widget.ConstraintLayout>
- </ScrollView>
-
- <!-- Cancel Button, replaces negative button when biometric is accepted -->
- <TextView
- android:id="@+id/indicator"
- style="@style/TextAppearance.AuthCredential.Indicator"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="24dp"
- android:accessibilityLiveRegion="assertive"
- android:fadingEdge="horizontal"
- android:gravity="center_horizontal"
- android:scrollHorizontally="true"
- app:layout_constraintBottom_toTopOf="@+id/button_bar"
- app:layout_constraintEnd_toEndOf="@+id/panel"
- app:layout_constraintStart_toStartOf="@+id/panel"
- app:layout_constraintTop_toBottomOf="@+id/biometric_icon"
- app:layout_constraintVertical_bias="0.0" />
-
- <!-- "Use Credential" Button, replaces if device credential is allowed -->
-
- <!-- Positive Button -->
- <androidx.constraintlayout.widget.Barrier
- android:id="@+id/topBarrier"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- app:barrierAllowsGoneWidgets="false"
- app:barrierDirection="top"
- app:constraint_referenced_ids="scrollView" />
-
- <!-- Try Again Button -->
- <androidx.constraintlayout.widget.Barrier
- android:id="@+id/scrollBarrier"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- app:barrierAllowsGoneWidgets="false"
- app:barrierDirection="top"
- app:constraint_referenced_ids="biometric_icon, button_bar" />
-
- <!-- Guidelines for setting panel border -->
- <androidx.constraintlayout.widget.Guideline
- android:id="@+id/leftGuideline"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- app:layout_constraintGuide_begin="@dimen/biometric_dialog_border_padding" />
-
- <androidx.constraintlayout.widget.Guideline
- android:id="@+id/rightGuideline"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- app:layout_constraintGuide_end="@dimen/biometric_dialog_border_padding" />
-
- <androidx.constraintlayout.widget.Guideline
- android:id="@+id/bottomGuideline"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- app:layout_constraintGuide_end="40dp" />
-
- <androidx.constraintlayout.widget.Guideline
- android:id="@+id/topGuideline"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:orientation="horizontal"
- app:layout_constraintGuide_begin="56dp" />
-
- <com.android.systemui.biometrics.BiometricPromptLottieViewWrapper
- android:id="@+id/biometric_icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintVertical_bias="1.0"
- tools:srcCompat="@tools:sample/avatars" />
-
- <com.android.systemui.biometrics.BiometricPromptLottieViewWrapper
- android:id="@+id/biometric_icon_overlay"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:layout_gravity="center"
- android:contentDescription="@null"
- android:scaleType="fitXY"
- android:importantForAccessibility="no"
- app:layout_constraintBottom_toBottomOf="@+id/biometric_icon"
- app:layout_constraintEnd_toEndOf="@+id/biometric_icon"
- app:layout_constraintStart_toStartOf="@+id/biometric_icon"
- app:layout_constraintTop_toTopOf="@+id/biometric_icon" />
-
-</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/packages/SystemUI/res/layout/biometric_prompt_constraint_layout.xml b/packages/SystemUI/res/layout/biometric_prompt_one_pane_layout.xml
similarity index 92%
rename from packages/SystemUI/res/layout/biometric_prompt_constraint_layout.xml
rename to packages/SystemUI/res/layout/biometric_prompt_one_pane_layout.xml
index 9b5b59f..8d50bfa 100644
--- a/packages/SystemUI/res/layout/biometric_prompt_constraint_layout.xml
+++ b/packages/SystemUI/res/layout/biometric_prompt_one_pane_layout.xml
@@ -22,9 +22,11 @@
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toEndOf="@id/rightGuideline"
+ app:layout_constraintEnd_toStartOf="@id/rightGuideline"
app:layout_constraintStart_toStartOf="@id/leftGuideline"
- app:layout_constraintTop_toTopOf="@id/topBarrier" />
+ app:layout_constraintTop_toTopOf="@id/topBarrier"
+ app:layout_constraintWidth_max="@dimen/biometric_prompt_panel_max_width" />
+
<include
android:id="@+id/button_bar"
@@ -41,8 +43,8 @@
android:layout_height="wrap_content"
android:fillViewport="true"
android:fadeScrollbars="false"
- android:paddingBottom="24dp"
- android:paddingHorizontal="24dp"
+ android:paddingBottom="@dimen/biometric_prompt_top_scroll_view_bottom_padding"
+ android:paddingHorizontal="@dimen/biometric_prompt_top_scroll_view_horizontal_padding"
android:paddingTop="24dp"
app:layout_constrainedHeight="true"
app:layout_constrainedWidth="true"
@@ -76,7 +78,7 @@
style="@style/TextAppearance.AuthCredential.LogoDescription"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingTop="8dp"
+ android:paddingTop="@dimen/biometric_prompt_logo_description_top_padding"
app:layout_constraintBottom_toTopOf="@+id/title"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
@@ -180,14 +182,14 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
- app:layout_constraintGuide_begin="0dp" />
+ app:layout_constraintGuide_begin="@dimen/biometric_prompt_one_pane_medium_horizontal_guideline_padding" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/rightGuideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
- app:layout_constraintGuide_end="0dp" />
+ app:layout_constraintGuide_end="@dimen/biometric_prompt_one_pane_medium_horizontal_guideline_padding" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/bottomGuideline"
@@ -201,7 +203,7 @@
android:layout_width="0dp"
android:layout_height="0dp"
android:orientation="horizontal"
- app:layout_constraintGuide_begin="119dp" />
+ app:layout_constraintGuide_begin="@dimen/biometric_prompt_one_pane_medium_top_guideline_padding" />
<com.android.systemui.biometrics.BiometricPromptLottieViewWrapper
android:id="@+id/biometric_icon"
diff --git a/packages/SystemUI/res/layout-land/biometric_prompt_constraint_layout.xml b/packages/SystemUI/res/layout/biometric_prompt_two_pane_layout.xml
similarity index 100%
rename from packages/SystemUI/res/layout-land/biometric_prompt_constraint_layout.xml
rename to packages/SystemUI/res/layout/biometric_prompt_two_pane_layout.xml
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 0000000..be063a9
--- /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 2bf6f80..4a7bef9 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 0000000..84462d0
--- /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/layout/ongoing_activity_chip.xml b/packages/SystemUI/res/layout/ongoing_activity_chip.xml
index a33be12..cd5c37d 100644
--- a/packages/SystemUI/res/layout/ongoing_activity_chip.xml
+++ b/packages/SystemUI/res/layout/ongoing_activity_chip.xml
@@ -40,6 +40,7 @@
<ImageView
android:src="@*android:drawable/ic_phone"
+ android:id="@+id/ongoing_activity_chip_icon"
android:layout_width="@dimen/ongoing_activity_chip_icon_size"
android:layout_height="@dimen/ongoing_activity_chip_icon_size"
android:tint="?android:attr/colorPrimary"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index e19b3fe..63aa97f 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 b257f0f..58940bb 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 d145ee9..b74b6cc 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 33c0b7e..e25a19e 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 5ff6b1a..f7c252e 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 aa34a88..6008438 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 4b305ae9..efaa31f 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 87d5ffe..6decb61 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 2b80eef..1aea982 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 66875ca..8229e4b 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 706076c..85cef4b6 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 8c36447..07a07a8 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 11c3481..a1dd5f9 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 6df88b9..4ac0efe 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 8354cc7..67c332e 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 32c242d..c6d206b 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 9a5f70a..76effd1 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 2697eb3..f2bae1b 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 945d353..e216c84 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 913d65f..1ccab5d 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 b6b2730..e096fff 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 639a307..d8c7dcd 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 6a53ad1..19625bd 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 d0b87da..7099033 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 66dd606..c539407 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 a72cae7..5af06e8 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 d19e9a1..71d0c6b 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 f29dee0..d6dc93c 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 e37c16b..2670e45 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 2618198..c709bbe 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 88259f3..042e748 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 cd14d0e..8b1ab5f 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 0622dc5..bec3cc1 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 7b7ba80..001f6a0 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 b9571ce..12bf568 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 18fc5b4..d165242 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 57e58fa..017a6c8 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 651d498..23e4559 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 edfbf09..dbcfaa3 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 f6650ee..29a5e73 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 3886e78..6245575 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 c8422cb..e8e6f09 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 b399cfa..b6614c6 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 a79818f..d6fa6ab 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 28d3220..3de4225 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 051690b..cb8cf5b 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 13bf885..2b851b4 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 2fec9aa..0d1614f 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 1be2de1..670a85c 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-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 2cfba01..664fbeb 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -102,6 +102,17 @@
<dimen name="lockscreen_shade_status_bar_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
<dimen name="lockscreen_shade_keyguard_transition_distance">@dimen/lockscreen_shade_media_transition_distance</dimen>
+ <!-- Dimensions for biometric prompt panel padding -->
+ <dimen name="biometric_prompt_one_pane_medium_top_guideline_padding">56dp</dimen>
+ <dimen name="biometric_prompt_one_pane_medium_horizontal_guideline_padding">@dimen/biometric_dialog_border_padding</dimen>
+
+ <!-- Dimensions for biometric prompt scroll view padding -->
+ <dimen name="biometric_prompt_top_scroll_view_bottom_padding">32dp</dimen>
+ <dimen name="biometric_prompt_top_scroll_view_horizontal_padding">32dp</dimen>
+
+ <!-- Dimensions for biometric prompt custom content view. -->
+ <dimen name="biometric_prompt_logo_description_top_padding">16dp</dimen>
+
<!-- Biometric Auth pattern view size, better to align keyguard_security_width -->
<dimen name="biometric_auth_pattern_view_size">348dp</dimen>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index f716e61..224ed398 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 241e952..26bb871 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 b063a8f..02ee017 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 9bc0cc0..db84644 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 2f64812..1afcf2a 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 e8d2cf4..d7c4c88 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 810fa4a..1a3055c 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 f253d4e..6644b53 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 638785402..fb88364 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 7d7a5d4..380a79e 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1119,11 +1119,18 @@
<dimen name="biometric_dialog_height">240dp</dimen>
<!-- Dimensions for biometric prompt panel padding -->
- <dimen name="biometric_prompt_small_horizontal_guideline_padding">344dp</dimen>
- <dimen name="biometric_prompt_udfps_horizontal_guideline_padding">114dp</dimen>
- <dimen name="biometric_prompt_udfps_mid_guideline_padding">409dp</dimen>
- <dimen name="biometric_prompt_medium_horizontal_guideline_padding">640dp</dimen>
- <dimen name="biometric_prompt_medium_mid_guideline_padding">330dp</dimen>
+ <dimen name="biometric_prompt_panel_max_width">640dp</dimen>
+ <dimen name="biometric_prompt_land_small_horizontal_guideline_padding">344dp</dimen>
+ <dimen name="biometric_prompt_two_pane_udfps_horizontal_guideline_padding">114dp</dimen>
+ <dimen name="biometric_prompt_two_pane_udfps_mid_guideline_padding">409dp</dimen>
+ <dimen name="biometric_prompt_two_pane_medium_horizontal_guideline_padding">640dp</dimen>
+ <dimen name="biometric_prompt_two_pane_medium_mid_guideline_padding">330dp</dimen>
+ <dimen name="biometric_prompt_one_pane_medium_top_guideline_padding">119dp</dimen>
+ <dimen name="biometric_prompt_one_pane_medium_horizontal_guideline_padding">0dp</dimen>
+
+ <!-- Dimensions for biometric prompt scroll view padding -->
+ <dimen name="biometric_prompt_top_scroll_view_bottom_padding">24dp</dimen>
+ <dimen name="biometric_prompt_top_scroll_view_horizontal_padding">24dp</dimen>
<!-- Dimensions for biometric prompt icon padding -->
<dimen name="biometric_prompt_portrait_small_bottom_padding">60dp</dimen>
@@ -1136,6 +1143,7 @@
<!-- Dimensions for biometric prompt custom content view. -->
<dimen name="biometric_prompt_logo_size">32dp</dimen>
+ <dimen name="biometric_prompt_logo_description_top_padding">8dp</dimen>
<dimen name="biometric_prompt_content_corner_radius">28dp</dimen>
<dimen name="biometric_prompt_content_padding_horizontal">24dp</dimen>
<dimen name="biometric_prompt_content_padding_vertical">16dp</dimen>
@@ -1778,6 +1786,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 6f2806d..c038a82 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/shared/biometrics/src/com/android/systemui/biometrics/shared/model/PromptKind.kt b/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/PromptKind.kt
index b99c514..44f2059 100644
--- a/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/PromptKind.kt
+++ b/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/PromptKind.kt
@@ -22,15 +22,28 @@
data class Biometric(
/** The available modalities for the authentication on the prompt. */
val activeModalities: BiometricModalities = BiometricModalities(),
- // TODO(b/330908557): Use this value to decide whether to show two pane layout, instead of
- // simply depending on rotations.
- val showTwoPane: Boolean = false,
- ) : PromptKind
+ val paneType: PaneType = PaneType.ONE_PANE_PORTRAIT,
+ ) : PromptKind {
+ enum class PaneType {
+ TWO_PANE_LANDSCAPE,
+ ONE_PANE_PORTRAIT,
+ ONE_PANE_NO_SENSOR_LANDSCAPE,
+ ONE_PANE_LARGE_SCREEN_LANDSCAPE
+ }
+ }
- object Pin : PromptKind
- object Pattern : PromptKind
- object Password : PromptKind
+ data object Pin : PromptKind
+ data object Pattern : PromptKind
+ data object Password : PromptKind
fun isBiometric() = this is Biometric
- fun isCredential() = (this is Pin) or (this is Pattern) or (this is Password)
+ fun isTwoPaneLandscapeBiometric(): Boolean =
+ (this as? Biometric)?.paneType == Biometric.PaneType.TWO_PANE_LANDSCAPE
+ fun isOnePanePortraitBiometric() =
+ (this as? Biometric)?.paneType == Biometric.PaneType.ONE_PANE_PORTRAIT
+ fun isOnePaneNoSensorLandscapeBiometric() =
+ (this as? Biometric)?.paneType == Biometric.PaneType.ONE_PANE_NO_SENSOR_LANDSCAPE
+ fun isOnePaneLargeScreenLandscapeBiometric() =
+ (this as? Biometric)?.paneType == Biometric.PaneType.ONE_PANE_LARGE_SCREEN_LANDSCAPE
+ fun isCredential() = (this is Pin) || (this is Pattern) || (this is Password)
}
diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
index 3f3bb0b..86c807b 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 @@
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 @@
}
}
- 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 @@
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 @@
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 27b2b92..63ad41a 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.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 @@
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/hearingaid/HearingDevicesDialogDelegate.java b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java
index 28dd233..961d6aa 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.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.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.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 @@
*/
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 @@
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 @@
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 @@
}
}
+ 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 @@
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 0000000..2006726
--- /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/tests/utils/src/com/android/systemui/qs/panels/data/repository/IconLabelVisibilityRepositoryKosmos.kt b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/ToolItem.kt
similarity index 71%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/IconLabelVisibilityRepositoryKosmos.kt
copy to packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/ToolItem.kt
index 277dbb7..66bb2b5 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/IconLabelVisibilityRepositoryKosmos.kt
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/ToolItem.kt
@@ -14,8 +14,13 @@
* limitations under the License.
*/
-package com.android.systemui.qs.panels.data.repository
+package com.android.systemui.accessibility.hearingaid
-import com.android.systemui.kosmos.Kosmos
+import android.content.Intent
+import android.graphics.drawable.Drawable
-val Kosmos.iconLabelVisibilityRepository by Kosmos.Fixture { IconLabelVisibilityRepository() }
+data class ToolItem(
+ var toolName: String = "",
+ var toolIcon: Drawable,
+ var toolIntent: Intent,
+)
diff --git a/packages/SystemUI/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandler.java b/packages/SystemUI/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandler.java
index 019f498..f905241 100644
--- a/packages/SystemUI/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandler.java
@@ -269,6 +269,7 @@
}
mScrimManager.removeCallback(mScrimManagerCallback);
mCapture = null;
+ mTouchSession = null;
if (!Flags.communalBouncerDoNotModifyPluginOpen()) {
mNotificationShadeWindowController.setForcePluginOpen(false, this);
diff --git a/packages/SystemUI/src/com/android/systemui/ambient/touch/TouchMonitor.java b/packages/SystemUI/src/com/android/systemui/ambient/touch/TouchMonitor.java
index 227e4db..61b4401 100644
--- a/packages/SystemUI/src/com/android/systemui/ambient/touch/TouchMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/ambient/touch/TouchMonitor.java
@@ -49,11 +49,14 @@
import com.google.common.util.concurrent.ListenableFuture;
+import kotlinx.coroutines.Job;
+
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
+import java.util.concurrent.CancellationException;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
import java.util.stream.Collectors;
@@ -78,15 +81,7 @@
private final Lifecycle mLifecycle;
private Rect mExclusionRect = null;
- private ISystemGestureExclusionListener mGestureExclusionListener =
- new ISystemGestureExclusionListener.Stub() {
- @Override
- public void onSystemGestureExclusionChanged(int displayId,
- Region systemGestureExclusion,
- Region systemGestureExclusionUnrestricted) {
- mExclusionRect = systemGestureExclusion.getBounds();
- }
- };
+ private ISystemGestureExclusionListener mGestureExclusionListener;
private Consumer<Rect> mMaxBoundsConsumer = rect -> mMaxBounds = rect;
@@ -274,6 +269,14 @@
if (bouncerAreaExclusion()) {
mBackgroundExecutor.execute(() -> {
try {
+ mGestureExclusionListener = new ISystemGestureExclusionListener.Stub() {
+ @Override
+ public void onSystemGestureExclusionChanged(int displayId,
+ Region systemGestureExclusion,
+ Region systemGestureExclusionUnrestricted) {
+ mExclusionRect = systemGestureExclusion.getBounds();
+ }
+ };
mWindowManagerService.registerSystemGestureExclusionListener(
mGestureExclusionListener, mDisplayId);
} catch (RemoteException e) {
@@ -298,8 +301,11 @@
if (bouncerAreaExclusion()) {
mBackgroundExecutor.execute(() -> {
try {
- mWindowManagerService.unregisterSystemGestureExclusionListener(
- mGestureExclusionListener, mDisplayId);
+ if (mGestureExclusionListener != null) {
+ mWindowManagerService.unregisterSystemGestureExclusionListener(
+ mGestureExclusionListener, mDisplayId);
+ mGestureExclusionListener = null;
+ }
} catch (RemoteException e) {
// Handle the exception
Log.e(TAG, "unregisterSystemGestureExclusionListener: failed", e);
@@ -494,6 +500,10 @@
private Rect mMaxBounds;
+ private Job mBoundsFlow;
+
+ private boolean mInitialized;
+
/**
* Designated constructor for {@link TouchMonitor}
@@ -535,10 +545,35 @@
* Initializes the monitor. should only be called once after creation.
*/
public void init() {
+ if (mInitialized) {
+ throw new IllegalStateException("TouchMonitor already initialized");
+ }
+
mLifecycle.addObserver(mLifecycleObserver);
if (Flags.ambientTouchMonitorListenToDisplayChanges()) {
- collectFlow(mLifecycle, mConfigurationInteractor.getMaxBounds(), mMaxBoundsConsumer);
+ mBoundsFlow = collectFlow(mLifecycle, mConfigurationInteractor.getMaxBounds(),
+ mMaxBoundsConsumer);
}
+
+ mInitialized = true;
+ }
+
+ /**
+ * Called when the TouchMonitor should be discarded and will not be used anymore.
+ */
+ public void destroy() {
+ if (!mInitialized) {
+ throw new IllegalStateException("TouchMonitor not initialized");
+ }
+
+ stopMonitoring(true);
+
+ mLifecycle.removeObserver(mLifecycleObserver);
+ if (Flags.ambientTouchMonitorListenToDisplayChanges()) {
+ mBoundsFlow.cancel(new CancellationException());
+ }
+
+ mInitialized = false;
}
private void isolate(Set<TouchSessionImpl> sessions) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index b75b292..1ee4908 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -29,6 +29,7 @@
import android.annotation.Nullable;
import android.app.AlertDialog;
import android.content.Context;
+import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.PixelFormat;
@@ -360,15 +361,23 @@
Utils.findFirstSensorProperties(fpProps, mConfig.mSensorIds),
Utils.findFirstSensorProperties(faceProps, mConfig.mSensorIds));
+ final boolean isLandscape = mContext.getResources().getConfiguration().orientation
+ == Configuration.ORIENTATION_LANDSCAPE;
mPromptSelectorInteractorProvider = promptSelectorInteractorProvider;
mPromptSelectorInteractorProvider.get().setPrompt(mConfig.mPromptInfo, mEffectiveUserId,
getRequestId(), biometricModalities, mConfig.mOperationId, mConfig.mOpPackageName,
- false /*onSwitchToCredential*/);
+ false /*onSwitchToCredential*/, isLandscape);
final LayoutInflater layoutInflater = LayoutInflater.from(mContext);
- if (constraintBp() && mPromptViewModel.getPromptKind().getValue().isBiometric()) {
- mLayout = (ConstraintLayout) layoutInflater.inflate(
- R.layout.biometric_prompt_constraint_layout, this, false /* attachToRoot */);
+ final PromptKind kind = mPromptViewModel.getPromptKind().getValue();
+ if (constraintBp() && kind.isBiometric()) {
+ if (kind.isTwoPaneLandscapeBiometric()) {
+ mLayout = (ConstraintLayout) layoutInflater.inflate(
+ R.layout.biometric_prompt_two_pane_layout, this, false /* attachToRoot */);
+ } else {
+ mLayout = (ConstraintLayout) layoutInflater.inflate(
+ R.layout.biometric_prompt_one_pane_layout, this, false /* attachToRoot */);
+ }
} else {
mLayout = (FrameLayout) layoutInflater.inflate(
R.layout.auth_container_view, this, false /* attachToRoot */);
@@ -631,7 +640,7 @@
if (fpProp != null && fpProp.isAnyUdfpsType()) {
maybeUpdatePositionForUdfps(forceInvalidate /* invalidate */);
}
- if (faceProp != null && mBiometricView.isFaceOnly()) {
+ if (faceProp != null && mBiometricView != null && mBiometricView.isFaceOnly()) {
alwaysUpdatePositionAtScreenBottom(forceInvalidate /* invalidate */);
}
if (fpProp != null && fpProp.sensorType == TYPE_POWER_BUTTON) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/DisplayStateRepository.kt b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/DisplayStateRepository.kt
index 8e5a97b..9b14d6f 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/DisplayStateRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/DisplayStateRepository.kt
@@ -29,11 +29,10 @@
import com.android.systemui.display.data.repository.DeviceStateRepository.DeviceState.REAR_DISPLAY
import com.android.systemui.display.data.repository.DisplayRepository
import javax.inject.Inject
+import kotlin.math.min
import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
@@ -58,7 +57,7 @@
val currentDisplaySize: StateFlow<Size>
/** Provides whether the current display is large screen */
- val isLargeScreen: Flow<Boolean>
+ val isLargeScreen: StateFlow<Boolean>
}
@SysUISingleton
@@ -127,16 +126,29 @@
),
)
- override val isLargeScreen: Flow<Boolean> =
+ override val isLargeScreen: StateFlow<Boolean> =
currentDisplayInfo
.map {
- // TODO: This works, but investigate better way to handle this
- it.logicalWidth * 160 / it.logicalDensityDpi > DisplayMetrics.DENSITY_XXXHIGH &&
- it.logicalHeight * 160 / it.logicalDensityDpi > DisplayMetrics.DENSITY_XXHIGH
+ // copied from systemui/shared/...Utilities.java
+ val smallestWidth =
+ dpiFromPx(
+ min(it.logicalWidth, it.logicalHeight).toFloat(),
+ context.resources.configuration.densityDpi
+ )
+ smallestWidth >= LARGE_SCREEN_MIN_DPS
}
- .distinctUntilChanged()
+ .stateIn(
+ backgroundScope,
+ started = SharingStarted.WhileSubscribed(),
+ initialValue = false,
+ )
+ private fun dpiFromPx(size: Float, densityDpi: Int): Float {
+ val densityRatio = densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT
+ return size / densityRatio
+ }
companion object {
const val TAG = "DisplayStateRepositoryImpl"
+ const val LARGE_SCREEN_MIN_DPS = 600f
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/DisplayStateInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/DisplayStateInteractor.kt
index 591da40..40313e3 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/DisplayStateInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/DisplayStateInteractor.kt
@@ -65,7 +65,8 @@
/** Called on configuration changes, used to keep the display state in sync */
fun onConfigurationChanged(newConfig: Configuration)
- val isLargeScreen: Flow<Boolean>
+ /** Provides whether the current display is large screen */
+ val isLargeScreen: StateFlow<Boolean>
}
/** Encapsulates logic for interacting with the display state. */
@@ -127,7 +128,7 @@
override val isDefaultDisplayOff = displayRepository.defaultDisplayOff
- override val isLargeScreen: Flow<Boolean> = displayStateRepository.isLargeScreen
+ override val isLargeScreen: StateFlow<Boolean> = displayStateRepository.isLargeScreen
companion object {
private const val TAG = "DisplayStateInteractor"
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt
index dc338d0..c08756f 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt
@@ -91,6 +91,7 @@
challenge: Long,
opPackageName: String,
onSwitchToCredential: Boolean,
+ isLandscape: Boolean,
)
/** Unset the current authentication request. */
@@ -102,6 +103,7 @@
@Inject
constructor(
fingerprintPropertyRepository: FingerprintPropertyRepository,
+ private val displayStateInteractor: DisplayStateInteractor,
private val promptRepository: PromptRepository,
private val lockPatternUtils: LockPatternUtils,
) : PromptSelectorInteractor {
@@ -166,7 +168,9 @@
modalities,
promptRepository.challenge.value!!,
promptRepository.opPackageName.value!!,
- true /*onSwitchToCredential*/
+ onSwitchToCredential = true,
+ // isLandscape value is not important when onSwitchToCredential is true
+ isLandscape = false,
)
}
@@ -178,6 +182,7 @@
challenge: Long,
opPackageName: String,
onSwitchToCredential: Boolean,
+ isLandscape: Boolean,
) {
val hasCredentialViewShown = promptKind.value.isCredential()
val showBpForCredential =
@@ -189,11 +194,30 @@
!promptInfo.isContentViewMoreOptionsButtonUsed
val showBpWithoutIconForCredential = showBpForCredential && !hasCredentialViewShown
var kind: PromptKind = PromptKind.None
+
if (onSwitchToCredential) {
kind = getCredentialType(lockPatternUtils, effectiveUserId)
} else if (Utils.isBiometricAllowed(promptInfo) || showBpWithoutIconForCredential) {
- // TODO(b/330908557): check to show one pane or two pane
- kind = PromptKind.Biometric(modalities)
+ // TODO(b/330908557): Subscribe to
+ // displayStateInteractor.currentRotation.value.isDefaultOrientation() for checking
+ // `isLandscape` after removing AuthContinerView.
+ kind =
+ if (isLandscape) {
+ val paneType =
+ when {
+ displayStateInteractor.isLargeScreen.value ->
+ PromptKind.Biometric.PaneType.ONE_PANE_LARGE_SCREEN_LANDSCAPE
+ showBpWithoutIconForCredential ->
+ PromptKind.Biometric.PaneType.ONE_PANE_NO_SENSOR_LANDSCAPE
+ else -> PromptKind.Biometric.PaneType.TWO_PANE_LANDSCAPE
+ }
+ PromptKind.Biometric(
+ modalities,
+ paneType = paneType,
+ )
+ } else {
+ PromptKind.Biometric(modalities)
+ }
} else if (isDeviceCredentialAllowed(promptInfo)) {
kind = getCredentialType(lockPatternUtils, effectiveUserId)
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt
index 47174c0..c836f89 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt
@@ -93,6 +93,7 @@
if (constraintBp()) {
val leftGuideline = view.requireViewById<Guideline>(R.id.leftGuideline)
+ val topGuideline = view.requireViewById<Guideline>(R.id.topGuideline)
val rightGuideline = view.requireViewById<Guideline>(R.id.rightGuideline)
val midGuideline = view.findViewById<Guideline>(R.id.midGuideline)
@@ -355,6 +356,18 @@
)
}
+ if (bounds.top >= 0) {
+ mediumConstraintSet.setGuidelineBegin(topGuideline.id, bounds.top)
+ smallConstraintSet.setGuidelineBegin(topGuideline.id, bounds.top)
+ } else if (bounds.top < 0) {
+ mediumConstraintSet.setGuidelineEnd(
+ topGuideline.id,
+ abs(bounds.top)
+ )
+ smallConstraintSet.setGuidelineEnd(topGuideline.id, abs(bounds.top))
+ }
+
+ // Use rect bottom to set mid guideline of two-pane.
if (midGuideline != null) {
if (bounds.bottom >= 0) {
midGuideline.setGuidelineEnd(bounds.bottom)
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
index 156ec6b..c17b83d 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
@@ -261,10 +261,13 @@
combine(
_forceLargeSize,
displayStateInteractor.isLargeScreen,
- displayStateInteractor.currentRotation
+ displayStateInteractor.currentRotation,
) { forceLarge, isLargeScreen, rotation ->
when {
- forceLarge || isLargeScreen -> PromptPosition.Bottom
+ forceLarge ||
+ isLargeScreen ||
+ promptKind.value.isOnePaneNoSensorLandscapeBiometric() ->
+ PromptPosition.Bottom
rotation == DisplayRotation.ROTATION_90 -> PromptPosition.Right
rotation == DisplayRotation.ROTATION_270 -> PromptPosition.Left
rotation == DisplayRotation.ROTATION_180 -> PromptPosition.Top
@@ -297,23 +300,27 @@
/** Prompt panel size padding */
private val smallHorizontalGuidelinePadding =
context.resources.getDimensionPixelSize(
- R.dimen.biometric_prompt_small_horizontal_guideline_padding
+ R.dimen.biometric_prompt_land_small_horizontal_guideline_padding
)
private val udfpsHorizontalGuidelinePadding =
context.resources.getDimensionPixelSize(
- R.dimen.biometric_prompt_udfps_horizontal_guideline_padding
+ R.dimen.biometric_prompt_two_pane_udfps_horizontal_guideline_padding
)
private val udfpsMidGuidelinePadding =
context.resources.getDimensionPixelSize(
- R.dimen.biometric_prompt_udfps_mid_guideline_padding
+ R.dimen.biometric_prompt_two_pane_udfps_mid_guideline_padding
+ )
+ private val mediumTopGuidelinePadding =
+ context.resources.getDimensionPixelSize(
+ R.dimen.biometric_prompt_one_pane_medium_top_guideline_padding
)
private val mediumHorizontalGuidelinePadding =
context.resources.getDimensionPixelSize(
- R.dimen.biometric_prompt_medium_horizontal_guideline_padding
+ R.dimen.biometric_prompt_two_pane_medium_horizontal_guideline_padding
)
private val mediumMidGuidelinePadding =
context.resources.getDimensionPixelSize(
- R.dimen.biometric_prompt_medium_mid_guideline_padding
+ R.dimen.biometric_prompt_two_pane_medium_mid_guideline_padding
)
/** Rect for positioning biometric icon */
@@ -416,9 +423,9 @@
* asset to be loaded before determining the prompt size.
*/
val isIconViewLoaded: Flow<Boolean> =
- combine(modalities, _isIconViewLoaded.asStateFlow()) { modalities, isIconViewLoaded ->
- val noIcon = modalities.isEmpty
- noIcon || isIconViewLoaded
+ combine(hideSensorIcon, _isIconViewLoaded.asStateFlow()) { hideSensorIcon, isIconViewLoaded
+ ->
+ hideSensorIcon || isIconViewLoaded
}
.distinctUntilChanged()
@@ -448,17 +455,24 @@
* from opposite side of the screen
*/
val guidelineBounds: Flow<Rect> =
- combine(iconPosition, size, position, modalities) { _, size, position, modalities ->
+ combine(iconPosition, promptKind, size, position, modalities) {
+ _,
+ promptKind,
+ size,
+ position,
+ modalities ->
when (position) {
- PromptPosition.Bottom -> Rect(0, 0, 0, 0)
+ PromptPosition.Bottom ->
+ if (promptKind.isOnePaneNoSensorLandscapeBiometric()) {
+ Rect(0, 0, 0, 0)
+ } else {
+ Rect(0, mediumTopGuidelinePadding, 0, 0)
+ }
PromptPosition.Right ->
if (size.isSmall) {
Rect(-smallHorizontalGuidelinePadding, 0, 0, 0)
} else if (modalities.hasUdfps) {
Rect(udfpsHorizontalGuidelinePadding, 0, 0, udfpsMidGuidelinePadding)
- } else if (modalities.isEmpty) {
- // TODO: Temporary fix until no biometric landscape layout is added
- Rect(-mediumHorizontalGuidelinePadding, 0, 0, 6)
} else {
Rect(-mediumHorizontalGuidelinePadding, 0, 0, mediumMidGuidelinePadding)
}
@@ -467,9 +481,6 @@
Rect(0, 0, -smallHorizontalGuidelinePadding, 0)
} else if (modalities.hasUdfps) {
Rect(0, 0, udfpsHorizontalGuidelinePadding, -udfpsMidGuidelinePadding)
- } else if (modalities.isEmpty) {
- // TODO: Temporary fix until no biometric landscape layout is added
- Rect(0, 0, -mediumHorizontalGuidelinePadding, -6)
} else {
Rect(
0,
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSceneRepository.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSceneRepository.kt
index d6d08b4..260dcba 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSceneRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSceneRepository.kt
@@ -22,6 +22,7 @@
import com.android.systemui.communal.dagger.Communal
import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.scene.shared.model.SceneDataSource
import javax.inject.Inject
@@ -34,6 +35,7 @@
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.launch
/** Encapsulates the state of communal mode. */
interface CommunalSceneRepository {
@@ -64,6 +66,7 @@
class CommunalSceneRepositoryImpl
@Inject
constructor(
+ @Application private val applicationScope: CoroutineScope,
@Background backgroundScope: CoroutineScope,
@Communal private val sceneDataSource: SceneDataSource,
) : CommunalSceneRepository {
@@ -82,11 +85,19 @@
)
override fun changeScene(toScene: SceneKey, transitionKey: TransitionKey?) {
- sceneDataSource.changeScene(toScene, transitionKey)
+ applicationScope.launch {
+ // SceneTransitionLayout state updates must be triggered on the thread the STL was
+ // created on.
+ sceneDataSource.changeScene(toScene, transitionKey)
+ }
}
override fun snapToScene(toScene: SceneKey) {
- sceneDataSource.snapToScene(toScene)
+ applicationScope.launch {
+ // SceneTransitionLayout state updates must be triggered on the thread the STL was
+ // created on.
+ sceneDataSource.snapToScene(toScene)
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/complication/DreamHomeControlsComplication.java b/packages/SystemUI/src/com/android/systemui/complication/DreamHomeControlsComplication.java
index afa2375..e284bc7 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 @@
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 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 @@
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 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 @@
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 0000000..3cf22b1
--- /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 0000000..501601e
--- /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 6f1b098..edb5ff7 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.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 @@
subcomponents = {
DreamClockTimeComplicationComponent.class,
DreamHomeControlsComplicationComponent.class,
+ OpenHubComplicationComponent.class,
DreamMediaEntryComplicationComponent.class
})
public interface RegisteredComplicationsModule {
@@ -46,6 +48,8 @@
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 @@
}
/**
+ * 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 @@
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 3e98fc1..7aab37e 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.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 @@
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 339e8f0..2ebb94f 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.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 @@
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/DreamOverlayService.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
index aa7a7da..96e708f 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
@@ -543,7 +543,11 @@
mStateController.setEntryAnimationsFinished(false);
mDreamOverlayContainerViewController = null;
- mTouchMonitor = null;
+
+ if (mTouchMonitor != null) {
+ mTouchMonitor.destroy();
+ mTouchMonitor = null;
+ }
mWindow = null;
mStarted = false;
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 1c047dd..04fda33 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 @@
// 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 2e49919..c084340 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 @@
@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 @@
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 c32c226..306f4ff 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.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 @@
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,
@@ -105,7 +103,6 @@
private val smartspaceViewModel: KeyguardSmartspaceViewModel,
private val lockscreenContentViewModel: LockscreenContentViewModel,
private val lockscreenSceneBlueprintsLazy: Lazy<Set<LockscreenSceneBlueprint>>,
- private val keyguardBlueprintViewBinder: KeyguardBlueprintViewBinder,
private val clockInteractor: KeyguardClockInteractor,
private val keyguardViewMediator: KeyguardViewMediator,
) : CoreStartable {
@@ -152,7 +149,7 @@
cs.connect(composeView.id, BOTTOM, PARENT_ID, BOTTOM)
keyguardRootView.addView(composeView)
} else {
- keyguardBlueprintViewBinder.bind(
+ KeyguardBlueprintViewBinder.bind(
keyguardRootView,
keyguardBlueprintViewModel,
keyguardClockViewModel,
@@ -160,7 +157,6 @@
)
}
}
- keyguardBlueprintCommandListener.start()
}
fun bindIndicationArea() {
@@ -200,12 +196,14 @@
KeyguardRootViewBinder.bind(
keyguardRootView,
keyguardRootViewModel,
+ keyguardBlueprintViewModel,
configuration,
occludingAppDeviceEntryMessageViewModel,
chipbarCoordinator,
screenOffAnimationController,
shadeInteractor,
clockInteractor,
+ keyguardClockViewModel,
interactionJankMonitor,
deviceEntryHapticsInteractor,
vibratorHelper,
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 80675d3..0863cd7 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 @@
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 0000000..d09b9f6
--- /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 4556195..93296f0 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 @@
camera: CameraQuickAffordanceConfig,
doNotDisturb: DoNotDisturbQuickAffordanceConfig,
flashlight: FlashlightQuickAffordanceConfig,
+ glanceableHub: GlanceableHubQuickAffordanceConfig,
home: HomeControlsKeyguardQuickAffordanceConfig,
mute: MuteQuickAffordanceConfig,
quickAccessWallet: QuickAccessWalletKeyguardQuickAffordanceConfig,
@@ -46,6 +47,7 @@
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 deedbdb..0748979 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 @@
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 @@
@Application private val context: Context,
private val userFileManager: UserFileManager,
private val userTracker: UserTracker,
+ private val systemSettings: SystemSettings,
broadcastDispatcher: BroadcastDispatcher,
) : KeyguardQuickAffordanceSelectionManager {
@@ -70,6 +73,22 @@
}
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 c11c49c..b826a00 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 @@
*/
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 53a0c32..76a8223 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 @@
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 @@
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 7cee258..41c3959 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.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 @@
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 @@
}
}
- 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 @@
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 fb65a6d..88e6602 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.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 @@
}
.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 @@
*/
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 7ca2eba..6d579f3 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 @@
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()
+ }
+ }
- sections.subtract(prevSections).forEach {
+ /** 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
+ }
+
+ 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 52d7519..bec8f3d 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
@@ -17,17 +17,12 @@
package com.android.systemui.keyguard.ui.binder
-import android.os.Handler
-import android.transition.Transition
-import android.transition.TransitionManager
import android.util.Log
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
import com.android.app.tracing.coroutines.launch
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.KeyguardBottomAreaRefactor
import com.android.systemui.keyguard.shared.model.KeyguardBlueprint
import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.BaseBlueprintTransition
@@ -40,47 +35,9 @@
import com.android.systemui.res.R
import com.android.systemui.shared.R as sharedR
import com.android.systemui.util.kotlin.pairwise
-import javax.inject.Inject
-import kotlin.math.max
-@SysUISingleton
-class KeyguardBlueprintViewBinder
-@Inject
-constructor(
- @Main private val handler: Handler,
-) {
- private var runningPriority = -1
- private val runningTransitions = mutableSetOf<Transition>()
- private val isTransitionRunning: Boolean
- get() = runningTransitions.size > 0
- private val transitionListener =
- object : Transition.TransitionListener {
- override fun onTransitionCancel(transition: Transition) {
- if (DEBUG) Log.e(TAG, "onTransitionCancel: ${transition::class.simpleName}")
- runningTransitions.remove(transition)
- }
-
- override fun onTransitionEnd(transition: Transition) {
- if (DEBUG) Log.e(TAG, "onTransitionEnd: ${transition::class.simpleName}")
- runningTransitions.remove(transition)
- }
-
- override fun onTransitionPause(transition: Transition) {
- if (DEBUG) Log.i(TAG, "onTransitionPause: ${transition::class.simpleName}")
- runningTransitions.remove(transition)
- }
-
- override fun onTransitionResume(transition: Transition) {
- if (DEBUG) Log.i(TAG, "onTransitionResume: ${transition::class.simpleName}")
- runningTransitions.add(transition)
- }
-
- override fun onTransitionStart(transition: Transition) {
- if (DEBUG) Log.i(TAG, "onTransitionStart: ${transition::class.simpleName}")
- runningTransitions.add(transition)
- }
- }
-
+object KeyguardBlueprintViewBinder {
+ @JvmStatic
fun bind(
constraintLayout: ConstraintLayout,
viewModel: KeyguardBlueprintViewModel,
@@ -95,17 +52,8 @@
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 +62,37 @@
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)
+ viewModel.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 +100,21 @@
}
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(
+ viewModel.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)
}
@@ -163,50 +124,6 @@
}
}
- private fun runTransition(
- constraintLayout: ConstraintLayout,
- transition: Transition,
- config: Config,
- apply: () -> Unit,
- ) {
- val currentPriority = if (isTransitionRunning) runningPriority else -1
- if (config.checkPriority && config.type.priority < currentPriority) {
- if (DEBUG) {
- Log.w(
- TAG,
- "runTransition: skipping ${transition::class.simpleName}: " +
- "currentPriority=$currentPriority; config=$config"
- )
- }
- apply()
- return
- }
-
- if (DEBUG) {
- Log.i(
- TAG,
- "runTransition: running ${transition::class.simpleName}: " +
- "currentPriority=$currentPriority; config=$config"
- )
- }
-
- // beginDelayedTransition makes a copy, so we temporarially add the uncopied transition to
- // the running set until the copy is started by the handler.
- runningTransitions.add(transition)
- transition.addListener(transitionListener)
- runningPriority = max(currentPriority, config.type.priority)
-
- handler.post {
- if (config.terminatePrevious) {
- TransitionManager.endTransitions(constraintLayout)
- }
-
- TransitionManager.beginDelayedTransition(constraintLayout, transition)
- runningTransitions.remove(transition)
- apply()
- }
- }
-
private fun logAlphaVisibilityOfAppliedConstraintSet(
cs: ConstraintSet,
viewModel: KeyguardClockViewModel
@@ -233,8 +150,6 @@
)
}
- companion object {
- private const val TAG = "KeyguardBlueprintViewBinder"
- private const val DEBUG = false
- }
+ private const val TAG = "KeyguardBlueprintViewBinder"
+ private const val DEBUG = false
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
index 39db22d..fc92afe 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
@@ -22,6 +22,7 @@
import android.annotation.SuppressLint
import android.graphics.Point
import android.graphics.Rect
+import android.util.Log
import android.view.HapticFeedbackConstants
import android.view.View
import android.view.View.OnLayoutChangeListener
@@ -56,8 +57,11 @@
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.ui.viewmodel.BurnInParameters
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardBlueprintViewModel
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel
import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel
import com.android.systemui.keyguard.ui.viewmodel.OccludingAppDeviceEntryMessageViewModel
+import com.android.systemui.keyguard.ui.viewmodel.TransitionData
import com.android.systemui.keyguard.ui.viewmodel.ViewStateAccessor
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.plugins.FalsingManager
@@ -93,12 +97,14 @@
fun bind(
view: ViewGroup,
viewModel: KeyguardRootViewModel,
+ blueprintViewModel: KeyguardBlueprintViewModel,
configuration: ConfigurationState,
occludingAppDeviceEntryMessageViewModel: OccludingAppDeviceEntryMessageViewModel?,
chipbarCoordinator: ChipbarCoordinator?,
screenOffAnimationController: ScreenOffAnimationController,
shadeInteractor: ShadeInteractor,
clockInteractor: KeyguardClockInteractor,
+ clockViewModel: KeyguardClockViewModel,
interactionJankMonitor: InteractionJankMonitor?,
deviceEntryHapticsInteractor: DeviceEntryHapticsInteractor?,
vibratorHelper: VibratorHelper?,
@@ -348,7 +354,16 @@
}
}
- disposables += view.onLayoutChanged(OnLayoutChange(viewModel, childViews, burnInParams))
+ disposables +=
+ view.onLayoutChanged(
+ OnLayoutChange(
+ viewModel,
+ blueprintViewModel,
+ clockViewModel,
+ childViews,
+ burnInParams
+ )
+ )
// Views will be added or removed after the call to bind(). This is needed to avoid many
// calls to findViewById
@@ -404,9 +419,13 @@
private class OnLayoutChange(
private val viewModel: KeyguardRootViewModel,
+ private val blueprintViewModel: KeyguardBlueprintViewModel,
+ private val clockViewModel: KeyguardClockViewModel,
private val childViews: Map<Int, View>,
private val burnInParams: MutableStateFlow<BurnInParameters>,
) : OnLayoutChangeListener {
+ var prevTransition: TransitionData? = null
+
override fun onLayoutChange(
view: View,
left: Int,
@@ -418,11 +437,21 @@
oldRight: Int,
oldBottom: Int
) {
+ // After layout, ensure the notifications are positioned correctly
childViews[nsslPlaceholderId]?.let { notificationListPlaceholder ->
- // After layout, ensure the notifications are positioned correctly
+ // Do not update a second time while a blueprint transition is running
+ val transition = blueprintViewModel.currentTransition.value
+ val shouldAnimate = transition != null && transition.config.type.animateNotifChanges
+ if (prevTransition == transition && shouldAnimate) {
+ if (DEBUG) Log.w(TAG, "Skipping; layout during transition")
+ return
+ }
+
+ prevTransition = transition
viewModel.onNotificationContainerBoundsChanged(
notificationListPlaceholder.top.toFloat(),
notificationListPlaceholder.bottom.toFloat(),
+ animate = shouldAnimate
)
}
@@ -585,4 +614,6 @@
private const val ID = "occluding_app_device_entry_unlock_msg"
private const val AOD_ICONS_APPEAR_DURATION: Long = 200
+ private const val TAG = "KeyguardRootViewBinder"
+ private const val DEBUG = false
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
index fb1853f..777c873 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
@@ -68,7 +68,9 @@
import com.android.systemui.keyguard.ui.binder.KeyguardRootViewBinder
import com.android.systemui.keyguard.ui.view.KeyguardRootView
import com.android.systemui.keyguard.ui.view.layout.sections.DefaultShortcutsSection
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardBlueprintViewModel
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel
import com.android.systemui.keyguard.ui.viewmodel.KeyguardPreviewClockViewModel
import com.android.systemui.keyguard.ui.viewmodel.KeyguardPreviewSmartspaceViewModel
import com.android.systemui.keyguard.ui.viewmodel.KeyguardQuickAffordancesCombinedViewModel
@@ -134,6 +136,7 @@
private val vibratorHelper: VibratorHelper,
private val indicationController: KeyguardIndicationController,
private val keyguardRootViewModel: KeyguardRootViewModel,
+ private val keyguardBlueprintViewModel: KeyguardBlueprintViewModel,
@Assisted bundle: Bundle,
private val occludingAppDeviceEntryMessageViewModel: OccludingAppDeviceEntryMessageViewModel,
private val chipbarCoordinator: ChipbarCoordinator,
@@ -143,6 +146,7 @@
private val communalTutorialViewModel: CommunalTutorialIndicatorViewModel,
private val defaultShortcutsSection: DefaultShortcutsSection,
private val keyguardClockInteractor: KeyguardClockInteractor,
+ private val keyguardClockViewModel: KeyguardClockViewModel,
) {
val hostToken: IBinder? = bundle.getBinder(KEY_HOST_TOKEN)
private val width: Int = bundle.getInt(KEY_VIEW_WIDTH)
@@ -379,12 +383,14 @@
KeyguardRootViewBinder.bind(
keyguardRootView,
keyguardRootViewModel,
+ keyguardBlueprintViewModel,
configuration,
occludingAppDeviceEntryMessageViewModel,
chipbarCoordinator,
screenOffAnimationController,
shadeInteractor,
keyguardClockInteractor,
+ keyguardClockViewModel,
null, // jank monitor not required for preview mode
null, // device entry haptics not required preview mode
null, // device entry haptics not required for preview mode
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 962cdf1..c026656 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 @@
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 04ac7bf..2dc9301 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 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 c69d868..39f1ebe 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
@@ -30,22 +31,23 @@
enum class Type(
val priority: Int,
+ val animateNotifChanges: Boolean,
) {
- ClockSize(100),
- ClockCenter(99),
- DefaultClockStepping(98),
- AodNotifIconsTransition(97),
- SmartspaceVisibility(2),
- DefaultTransition(1),
+ ClockSize(100, true),
+ ClockCenter(99, false),
+ DefaultClockStepping(98, false),
+ SmartspaceVisibility(2, true),
+ DefaultTransition(1, false),
// When transition between blueprint, we don't need any duration or interpolator but we need
// all elements go to correct state
- NoTransition(0),
+ NoTransition(0, false),
}
data class Config(
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/AodNotificationIconsSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodNotificationIconsSection.kt
index 2832e9d..d77b548 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodNotificationIconsSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodNotificationIconsSection.kt
@@ -19,6 +19,8 @@
import android.content.Context
import android.view.View
+import android.view.View.GONE
+import android.view.View.VISIBLE
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
import androidx.constraintlayout.widget.ConstraintSet.BOTTOM
@@ -29,6 +31,7 @@
import com.android.systemui.common.ui.ConfigurationState
import com.android.systemui.keyguard.MigrateClocksToBlueprint
import com.android.systemui.keyguard.shared.model.KeyguardSection
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel
import com.android.systemui.res.R
import com.android.systemui.statusbar.notification.icon.ui.viewbinder.AlwaysOnDisplayNotificationIconViewStore
import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerViewBinder
@@ -38,6 +41,7 @@
import com.android.systemui.statusbar.phone.NotificationIconAreaController
import com.android.systemui.statusbar.phone.NotificationIconContainer
import com.android.systemui.statusbar.ui.SystemBarUtilsState
+import com.android.systemui.util.ui.value
import javax.inject.Inject
import kotlinx.coroutines.DisposableHandle
@@ -51,6 +55,7 @@
private val nicAodIconViewStore: AlwaysOnDisplayNotificationIconViewStore,
private val notificationIconAreaController: NotificationIconAreaController,
private val systemBarUtilsState: SystemBarUtilsState,
+ private val rootViewModel: KeyguardRootViewModel,
) : KeyguardSection() {
private var nicBindingDisposable: DisposableHandle? = null
@@ -101,20 +106,14 @@
if (!MigrateClocksToBlueprint.isEnabled) {
return
}
+
val bottomMargin =
context.resources.getDimensionPixelSize(R.dimen.keyguard_status_view_bottom_margin)
-
- val useSplitShade = context.resources.getBoolean(R.bool.config_use_split_notification_shade)
-
- val topAlignment =
- if (useSplitShade) {
- TOP
- } else {
- BOTTOM
- }
+ val isVisible = rootViewModel.isNotifIconContainerVisible.value
constraintSet.apply {
connect(nicId, TOP, R.id.smart_space_barrier_bottom, BOTTOM, bottomMargin)
setGoneMargin(nicId, BOTTOM, bottomMargin)
+ setVisibility(nicId, if (isVisible.value) VISIBLE else GONE)
connect(
nicId,
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 b367715..34a1da5 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.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 @@
alpha: Float,
) = views.forEach { view -> this.setAlpha(view.id, alpha) }
+@SysUISingleton
class ClockSection
@Inject
constructor(
@@ -72,6 +74,7 @@
if (!MigrateClocksToBlueprint.isEnabled) {
return
}
+
KeyguardClockViewBinder.bind(
this,
constraintLayout,
@@ -86,6 +89,7 @@
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 0b8376a..c5fab8f 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 @@
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 487c2e9..2d6690f 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 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 dagger.Lazy
import javax.inject.Inject
+@SysUISingleton
open class SmartspaceSection
@Inject
constructor(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt
index 7c745bc..f17dbd2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt
@@ -369,6 +369,21 @@
addTarget(R.id.status_view_media_container)
}
+ override fun mutateBounds(
+ view: View,
+ fromIsVis: Boolean,
+ toIsVis: Boolean,
+ fromBounds: Rect,
+ toBounds: Rect,
+ fromSSBounds: Rect?,
+ toSSBounds: Rect?
+ ) {
+ // If view is changing visibility, hold it in place
+ if (fromIsVis == toIsVis) return
+ if (DEBUG) Log.i(TAG, "Holding position of ${view.id}")
+ toBounds.set(fromBounds)
+ }
+
companion object {
const val STATUS_AREA_MOVE_UP_MILLIS = 967L
const val STATUS_AREA_MOVE_DOWN_MILLIS = 467L
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModel.kt
index b1f1898..7ac03bf 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModel.kt
@@ -17,15 +17,119 @@
package com.android.systemui.keyguard.ui.viewmodel
+import android.os.Handler
+import android.transition.Transition
+import android.transition.TransitionManager
+import android.util.Log
+import androidx.constraintlayout.widget.ConstraintLayout
+import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor
+import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition.Config
import javax.inject.Inject
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+
+data class TransitionData(
+ val config: Config,
+ val start: Long = System.currentTimeMillis(),
+)
class KeyguardBlueprintViewModel
@Inject
constructor(
+ @Main private val handler: Handler,
keyguardBlueprintInteractor: KeyguardBlueprintInteractor,
) {
val blueprint = keyguardBlueprintInteractor.blueprint
val blueprintId = keyguardBlueprintInteractor.blueprintId
val refreshTransition = keyguardBlueprintInteractor.refreshTransition
+
+ private val _currentTransition = MutableStateFlow<TransitionData?>(null)
+ val currentTransition = _currentTransition.asStateFlow()
+
+ private val runningTransitions = mutableSetOf<Transition>()
+ private val transitionListener =
+ object : Transition.TransitionListener {
+ override fun onTransitionCancel(transition: Transition) {
+ if (DEBUG) Log.e(TAG, "onTransitionCancel: ${transition::class.simpleName}")
+ updateTransitions(null) { remove(transition) }
+ }
+
+ override fun onTransitionEnd(transition: Transition) {
+ if (DEBUG) Log.e(TAG, "onTransitionEnd: ${transition::class.simpleName}")
+ updateTransitions(null) { remove(transition) }
+ }
+
+ override fun onTransitionPause(transition: Transition) {
+ if (DEBUG) Log.i(TAG, "onTransitionPause: ${transition::class.simpleName}")
+ updateTransitions(null) { remove(transition) }
+ }
+
+ override fun onTransitionResume(transition: Transition) {
+ if (DEBUG) Log.i(TAG, "onTransitionResume: ${transition::class.simpleName}")
+ updateTransitions(null) { add(transition) }
+ }
+
+ override fun onTransitionStart(transition: Transition) {
+ if (DEBUG) Log.i(TAG, "onTransitionStart: ${transition::class.simpleName}")
+ updateTransitions(null) { add(transition) }
+ }
+ }
+
+ fun updateTransitions(data: TransitionData?, mutate: MutableSet<Transition>.() -> Unit) {
+ runningTransitions.mutate()
+
+ if (runningTransitions.size <= 0) _currentTransition.value = null
+ else if (data != null) _currentTransition.value = data
+ }
+
+ fun runTransition(
+ constraintLayout: ConstraintLayout,
+ transition: Transition,
+ config: Config,
+ apply: () -> Unit,
+ ) {
+ val currentPriority = currentTransition.value?.let { it.config.type.priority } ?: -1
+ if (config.checkPriority && config.type.priority < currentPriority) {
+ if (DEBUG) {
+ Log.w(
+ TAG,
+ "runTransition: skipping ${transition::class.simpleName}: " +
+ "currentPriority=$currentPriority; config=$config"
+ )
+ }
+ apply()
+ return
+ }
+
+ if (DEBUG) {
+ Log.i(
+ TAG,
+ "runTransition: running ${transition::class.simpleName}: " +
+ "currentPriority=$currentPriority; config=$config"
+ )
+ }
+
+ // beginDelayedTransition makes a copy, so we temporarially add the uncopied transition to
+ // the running set until the copy is started by the handler.
+ updateTransitions(TransitionData(config)) { add(transition) }
+ transition.addListener(transitionListener)
+
+ handler.post {
+ if (config.terminatePrevious) {
+ TransitionManager.endTransitions(constraintLayout)
+ }
+
+ TransitionManager.beginDelayedTransition(constraintLayout, transition)
+ apply()
+
+ // Delay removal until after copied transition has started
+ handler.post { updateTransitions(null) { remove(transition) } }
+ }
+ }
+
+ companion object {
+ private const val TAG = "KeyguardBlueprintViewModel"
+ private const val DEBUG = true
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
index aaec69f..1ec2a49 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
@@ -58,6 +58,8 @@
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.combineTransform
@@ -67,13 +69,14 @@
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.flow.stateIn
@OptIn(ExperimentalCoroutinesApi::class)
@SysUISingleton
class KeyguardRootViewModel
@Inject
constructor(
- @Application private val scope: CoroutineScope,
+ @Application private val applicationScope: CoroutineScope,
private val deviceEntryInteractor: DeviceEntryInteractor,
private val dozeParameters: DozeParameters,
private val keyguardInteractor: KeyguardInteractor,
@@ -280,7 +283,7 @@
burnInJob?.cancel()
burnInJob =
- scope.launch("$TAG#aodBurnInViewModel") {
+ applicationScope.launch("$TAG#aodBurnInViewModel") {
aodBurnInViewModel.movement(params).collect { _burnInModel.value = it }
}
}
@@ -294,7 +297,7 @@
}
/** Is the notification icon container visible? */
- val isNotifIconContainerVisible: Flow<AnimatedValue<Boolean>> =
+ val isNotifIconContainerVisible: StateFlow<AnimatedValue<Boolean>> =
combine(
goneToAodTransitionRunning,
keyguardTransitionInteractor.finishedKeyguardState.map {
@@ -336,11 +339,15 @@
}
}
}
- .distinctUntilChanged()
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.WhileSubscribed(),
+ initialValue = AnimatedValue.NotAnimating(false),
+ )
- fun onNotificationContainerBoundsChanged(top: Float, bottom: Float) {
+ fun onNotificationContainerBoundsChanged(top: Float, bottom: Float, animate: Boolean = false) {
keyguardInteractor.setNotificationContainerBounds(
- NotificationContainerBounds(top = top, bottom = bottom)
+ NotificationContainerBounds(top = top, bottom = bottom, isAnimated = animate)
)
}
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 486d4d4..aa93df7 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.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 @@
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 @@
@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 @@
}
}
+ 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/IconLabelVisibilityRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/IconLabelVisibilityRepository.kt
deleted file mode 100644
index 686e5f4..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/IconLabelVisibilityRepository.kt
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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.dagger.SysUISingleton
-import javax.inject.Inject
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.asStateFlow
-
-/** 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()
-
- fun setShowLabels(showLabels: Boolean) {
- _showLabels.value = showLabels
- }
-}
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 0000000..f3e5b8f
--- /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 a871531..6a899b0 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.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 @@
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/domain/interactor/QSPreferencesInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/QSPreferencesInteractor.kt
new file mode 100644
index 0000000..811be80
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/QSPreferencesInteractor.kt
@@ -0,0 +1,31 @@
+/*
+ * 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 com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.qs.panels.data.repository.QSPreferencesRepository
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+
+@SysUISingleton
+class QSPreferencesInteractor @Inject constructor(private val repo: QSPreferencesRepository) {
+ val showLabels: Flow<Boolean> = repo.showLabels
+
+ fun setShowLabels(showLabels: Boolean) {
+ 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 5d4b8f1..12cbde2 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 @@
@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/tiles/dialog/InternetDialogController.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
index 7bc76af..c091ac3de 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 @@
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 22aa492..1d8b7e5b 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.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 @@
*
* 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/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index 03c6670..6d34a0f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar;
import static com.android.systemui.Flags.mediaControlsUserInitiatedDeleteintent;
+import static com.android.systemui.Flags.notificationMediaManagerBackgroundExecution;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -26,12 +27,16 @@
import android.media.session.MediaController;
import android.media.session.MediaSession;
import android.media.session.PlaybackState;
+import android.os.Handler;
import android.service.notification.NotificationStats;
import android.service.notification.StatusBarNotification;
import android.util.Log;
+import androidx.annotation.VisibleForTesting;
+
import com.android.systemui.Dumpable;
import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.media.controls.domain.pipeline.MediaDataManager;
import com.android.systemui.media.controls.shared.model.MediaData;
@@ -48,6 +53,7 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
+import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.Executor;
@@ -80,13 +86,16 @@
private final ArrayList<MediaListener> mMediaListeners;
private final Executor mBackgroundExecutor;
+ private final Handler mHandler;
protected NotificationPresenter mPresenter;
- private MediaController mMediaController;
+ @VisibleForTesting
+ MediaController mMediaController;
private String mMediaNotificationKey;
private MediaMetadata mMediaMetadata;
- private final MediaController.Callback mMediaListener = new MediaController.Callback() {
+ @VisibleForTesting
+ final MediaController.Callback mMediaListener = new MediaController.Callback() {
@Override
public void onPlaybackStateChanged(PlaybackState state) {
super.onPlaybackStateChanged(state);
@@ -107,11 +116,20 @@
if (DEBUG_MEDIA) {
Log.v(TAG, "DEBUG_MEDIA: onMetadataChanged: " + metadata);
}
- mMediaMetadata = metadata;
+ if (notificationMediaManagerBackgroundExecution()) {
+ mBackgroundExecutor.execute(() -> setMediaMetadata(metadata));
+ } else {
+ setMediaMetadata(metadata);
+ }
+
dispatchUpdateMediaMetaData();
}
};
+ private void setMediaMetadata(MediaMetadata metadata) {
+ mMediaMetadata = metadata;
+ }
+
/**
* Injected constructor. See {@link CentralSurfacesModule}.
*/
@@ -122,7 +140,9 @@
NotifCollection notifCollection,
MediaDataManager mediaDataManager,
DumpManager dumpManager,
- @Background Executor backgroundExecutor) {
+ @Background Executor backgroundExecutor,
+ @Main Handler handler
+ ) {
mContext = context;
mMediaListeners = new ArrayList<>();
mVisibilityProvider = visibilityProvider;
@@ -130,6 +150,7 @@
mNotifPipeline = notifPipeline;
mNotifCollection = notifCollection;
mBackgroundExecutor = backgroundExecutor;
+ mHandler = handler;
setupNotifPipeline();
@@ -262,6 +283,14 @@
public void addCallback(MediaListener callback) {
mMediaListeners.add(callback);
+ if (notificationMediaManagerBackgroundExecution()) {
+ mBackgroundExecutor.execute(() -> updateMediaMetaData(callback));
+ } else {
+ updateMediaMetaData(callback);
+ }
+ }
+
+ private void updateMediaMetaData(MediaListener callback) {
callback.onPrimaryMetadataOrStateChanged(mMediaMetadata,
getMediaControllerPlaybackState(mMediaController));
}
@@ -273,7 +302,11 @@
public void findAndUpdateMediaNotifications() {
// TODO(b/169655907): get the semi-filtered notifications for current user
Collection<NotificationEntry> allNotifications = mNotifPipeline.getAllNotifs();
- findPlayingMediaNotification(allNotifications);
+ if (notificationMediaManagerBackgroundExecution()) {
+ mBackgroundExecutor.execute(() -> findPlayingMediaNotification(allNotifications));
+ } else {
+ findPlayingMediaNotification(allNotifications);
+ }
dispatchUpdateMediaMetaData();
}
@@ -312,7 +345,7 @@
// We have a new media session
clearCurrentMediaNotificationSession();
mMediaController = controller;
- mMediaController.registerCallback(mMediaListener);
+ mMediaController.registerCallback(mMediaListener, mHandler);
mMediaMetadata = mMediaController.getMetadata();
if (DEBUG_MEDIA) {
Log.v(TAG, "DEBUG_MEDIA: insert listener, found new controller: "
@@ -331,13 +364,29 @@
}
public void clearCurrentMediaNotification() {
+ if (notificationMediaManagerBackgroundExecution()) {
+ mBackgroundExecutor.execute(this::clearMediaNotification);
+ } else {
+ clearMediaNotification();
+ }
+ }
+
+ private void clearMediaNotification() {
mMediaNotificationKey = null;
clearCurrentMediaNotificationSession();
}
private void dispatchUpdateMediaMetaData() {
- @PlaybackState.State int state = getMediaControllerPlaybackState(mMediaController);
ArrayList<MediaListener> callbacks = new ArrayList<>(mMediaListeners);
+ if (notificationMediaManagerBackgroundExecution()) {
+ mBackgroundExecutor.execute(() -> updateMediaMetaData(callbacks));
+ } else {
+ updateMediaMetaData(callbacks);
+ }
+ }
+
+ private void updateMediaMetaData(List<MediaListener> callbacks) {
+ @PlaybackState.State int state = getMediaControllerPlaybackState(mMediaController);
for (int i = 0; i < callbacks.size(); i++) {
callbacks.get(i).onPrimaryMetadataOrStateChanged(mMediaMetadata, state);
}
@@ -393,7 +442,6 @@
Log.v(TAG, "DEBUG_MEDIA: Disconnecting from old controller: "
+ mMediaController.getPackageName());
}
- // TODO(b/336612071): move to background thread
mMediaController.unregisterCallback(mMediaListener);
}
mMediaController = null;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractor.kt
new file mode 100644
index 0000000..ac16d26
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractor.kt
@@ -0,0 +1,79 @@
+/*
+ * 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.statusbar.chips.mediaprojection.domain.interactor
+
+import com.android.systemui.common.shared.model.ContentDescription
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.mediaprojection.data.model.MediaProjectionState
+import com.android.systemui.mediaprojection.data.repository.MediaProjectionRepository
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.chips.domain.interactor.OngoingActivityChipInteractor
+import com.android.systemui.statusbar.chips.domain.model.OngoingActivityChipModel
+import com.android.systemui.util.time.SystemClock
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.stateIn
+
+/**
+ * Interactor for media-projection-related chips in the status bar.
+ *
+ * There are two kinds of media projection events that will show chips in the status bar:
+ * 1) Share-to-app: Sharing your phone screen content to another app on the same device. (Triggered
+ * from within each individual app.)
+ * 2) Cast-to-other-device: Sharing your phone screen content to a different device. (Triggered from
+ * the Quick Settings Cast tile or from the Settings app.) This interactor handles both of those
+ * event types (though maybe not audio-only casting -- see b/342169876).
+ */
+@SysUISingleton
+class MediaProjectionChipInteractor
+@Inject
+constructor(
+ @Application scope: CoroutineScope,
+ mediaProjectionRepository: MediaProjectionRepository,
+ val systemClock: SystemClock,
+) : OngoingActivityChipInteractor {
+ override val chip: StateFlow<OngoingActivityChipModel> =
+ mediaProjectionRepository.mediaProjectionState
+ .map { state ->
+ when (state) {
+ is MediaProjectionState.NotProjecting -> OngoingActivityChipModel.Hidden
+ is MediaProjectionState.EntireScreen,
+ is MediaProjectionState.SingleTask -> {
+ // TODO(b/332662551): Distinguish between cast-to-other-device and
+ // share-to-app.
+ OngoingActivityChipModel.Shown(
+ icon =
+ Icon.Resource(
+ R.drawable.ic_cast_connected,
+ ContentDescription.Resource(R.string.accessibility_casting)
+ ),
+ // TODO(b/332662551): See if we can use a MediaProjection API to fetch
+ // this time.
+ startTimeMs = systemClock.elapsedRealtime()
+ ) {
+ // TODO(b/332662551): Implement the pause dialog.
+ }
+ }
+ }
+ }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), OngoingActivityChipModel.Hidden)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractor.kt
index bff5686..585ff5f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractor.kt
@@ -34,7 +34,7 @@
/** Interactor for the screen recording chip shown in the status bar. */
@SysUISingleton
-open class ScreenRecordChipInteractor
+class ScreenRecordChipInteractor
@Inject
constructor(
@Application scope: CoroutineScope,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/ChipChronometerBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/ChipChronometerBinder.kt
new file mode 100644
index 0000000..2032ec8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/ChipChronometerBinder.kt
@@ -0,0 +1,33 @@
+/*
+ * 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.statusbar.chips.ui.binder
+
+import com.android.systemui.statusbar.chips.ui.view.ChipChronometer
+
+object ChipChronometerBinder {
+ /**
+ * Updates the given [view] chronometer with a new start time and starts it.
+ *
+ * @param startTimeMs the time this event started, relative to
+ * [com.android.systemui.util.time.SystemClock.elapsedRealtime]. See
+ * [android.widget.Chronometer.setBase].
+ */
+ fun bind(startTimeMs: Long, view: ChipChronometer) {
+ view.base = startTimeMs
+ view.start()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt
index 208eb50..edb2983 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt
@@ -20,6 +20,7 @@
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.statusbar.chips.call.domain.interactor.CallChipInteractor
import com.android.systemui.statusbar.chips.domain.model.OngoingActivityChipModel
+import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.MediaProjectionChipInteractor
import com.android.systemui.statusbar.chips.screenrecord.domain.interactor.ScreenRecordChipInteractor
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -40,6 +41,7 @@
constructor(
@Application scope: CoroutineScope,
screenRecordChipInteractor: ScreenRecordChipInteractor,
+ mediaProjectionChipInteractor: MediaProjectionChipInteractor,
callChipInteractor: CallChipInteractor,
) {
@@ -51,10 +53,19 @@
* actually displaying the chip.
*/
val chip: StateFlow<OngoingActivityChipModel> =
- combine(screenRecordChipInteractor.chip, callChipInteractor.chip) { screenRecord, call ->
+ combine(
+ screenRecordChipInteractor.chip,
+ mediaProjectionChipInteractor.chip,
+ callChipInteractor.chip
+ ) { screenRecord, mediaProjection, call ->
// This `when` statement shows the priority order of the chips
when {
+ // Screen recording also activates the media projection APIs, so whenever the
+ // screen recording chip is active, the media projection chip would also be
+ // active. We want the screen-recording-specific chip shown in this case, so we
+ // give the screen recording chip priority. See b/296461748.
screenRecord is OngoingActivityChipModel.Shown -> screenRecord
+ mediaProjection is OngoingActivityChipModel.Shown -> mediaProjection
else -> call
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
index 0524589..7df7ef1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
@@ -19,6 +19,7 @@
import static com.android.systemui.Flags.predictiveBackAnimateDialogs;
import android.content.Context;
+import android.os.Handler;
import android.os.RemoteException;
import android.service.dreams.IDreamManager;
import android.util.Log;
@@ -99,7 +100,8 @@
NotifCollection notifCollection,
MediaDataManager mediaDataManager,
DumpManager dumpManager,
- @Background Executor backgroundExecutor) {
+ @Background Executor backgroundExecutor,
+ @Main Handler handler) {
return new NotificationMediaManager(
context,
visibilityProvider,
@@ -107,7 +109,8 @@
notifCollection,
mediaDataManager,
dumpManager,
- backgroundExecutor);
+ backgroundExecutor,
+ handler);
}
/** */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
index 5bbd77e..60d846e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
@@ -23,6 +23,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
+import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
import android.app.ActivityTaskManager.RootTaskInfo;
import android.app.AppGlobals;
@@ -271,13 +272,16 @@
.addFlags(Intent.FLAG_IGNORE_EPHEMERAL)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ ActivityOptions options = ActivityOptions.makeBasic()
+ .setPendingIntentCreatorBackgroundActivityStartMode(
+ ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
PendingIntent pendingIntent =
PendingIntent.getActivityAsUser(
mContext,
0 /* requestCode */,
browserIntent,
PendingIntent.FLAG_IMMUTABLE /* flags */,
- null,
+ options.toBundle(),
user);
ComponentName aiaComponent = null;
try {
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 84b7478..fe22cc6 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_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;
@@ -2844,23 +2843,15 @@
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
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 7b7a35b..05a4391 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 @@
@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 5ab56ae..a7b5484 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 @@
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 e0da2fe..78a8036 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.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 @@
private final ColorExtractor.OnColorsChangedListener mOnColorsChangedListener =
(extractor, which) -> updateTheme();
private final BrightnessMirrorShowingInteractor mBrightnessMirrorShowingInteractor;
+ private final GlanceableHubContainerController mGlanceableHubContainerController;
/**
* Public constructor for CentralSurfaces.
@@ -707,7 +709,8 @@
UserTracker userTracker,
Provider<FingerprintManager> fingerprintManager,
ActivityStarter activityStarter,
- BrightnessMirrorShowingInteractor brightnessMirrorShowingInteractor
+ BrightnessMirrorShowingInteractor brightnessMirrorShowingInteractor,
+ GlanceableHubContainerController glanceableHubContainerController
) {
mContext = context;
mNotificationsController = notificationsController;
@@ -802,6 +805,7 @@
mFingerprintManager = fingerprintManager;
mActivityStarter = activityStarter;
mBrightnessMirrorShowingInteractor = brightnessMirrorShowingInteractor;
+ mGlanceableHubContainerController = glanceableHubContainerController;
mLockscreenShadeTransitionController = lockscreenShadeTransitionController;
mStartingSurfaceOptional = startingSurfaceOptional;
@@ -2951,6 +2955,11 @@
}
@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/fragment/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
index 97f9e06..aac211a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
@@ -39,6 +39,7 @@
import com.android.app.animation.InterpolatorsAndroidX;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.Dumpable;
+import com.android.systemui.Flags;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.demomode.DemoMode;
import com.android.systemui.demomode.DemoModeController;
@@ -51,7 +52,6 @@
import com.android.systemui.statusbar.OperatorNameView;
import com.android.systemui.statusbar.OperatorNameViewController;
import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModel;
import com.android.systemui.statusbar.disableflags.DisableFlagsLogger.DisableState;
import com.android.systemui.statusbar.events.SystemStatusAnimationCallback;
import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
@@ -135,8 +135,6 @@
private final CollapsedStatusBarFragmentLogger mCollapsedStatusBarFragmentLogger;
private final OperatorNameViewController.Factory mOperatorNameViewControllerFactory;
private final OngoingCallController mOngoingCallController;
- // TODO(b/332662551): Use this view model to show the ongoing activity chips.
- private final OngoingActivityChipsViewModel mOngoingActivityChipsViewModel;
private final SystemStatusAnimationScheduler mAnimationScheduler;
private final StatusBarLocationPublisher mLocationPublisher;
private final NotificationIconAreaController mNotificationIconAreaController;
@@ -207,6 +205,11 @@
private boolean mTransitionFromLockscreenToDreamStarted = false;
/**
+ * True if there's an active ongoing activity that should be showing a chip and false otherwise.
+ */
+ private boolean mHasOngoingActivity;
+
+ /**
* Listener that updates {@link #mWaitingForWindowStateChangeAfterCameraLaunch} when it receives
* a new status bar window state.
*/
@@ -216,11 +219,12 @@
};
private DisposableHandle mNicBindingDisposable;
+ private boolean mAnimationsEnabled = true;
+
@Inject
public CollapsedStatusBarFragment(
StatusBarFragmentComponent.Factory statusBarFragmentComponentFactory,
OngoingCallController ongoingCallController,
- OngoingActivityChipsViewModel ongoingActivityChipsViewModel,
SystemStatusAnimationScheduler animationScheduler,
StatusBarLocationPublisher locationPublisher,
NotificationIconAreaController notificationIconAreaController,
@@ -246,7 +250,6 @@
DemoModeController demoModeController) {
mStatusBarFragmentComponentFactory = statusBarFragmentComponentFactory;
mOngoingCallController = ongoingCallController;
- mOngoingActivityChipsViewModel = ongoingActivityChipsViewModel;
mAnimationScheduler = animationScheduler;
mLocationPublisher = locationPublisher;
mNotificationIconAreaController = notificationIconAreaController;
@@ -401,6 +404,17 @@
return mBlockedIcons;
}
+
+ @VisibleForTesting
+ void enableAnimationsForTesting() {
+ mAnimationsEnabled = true;
+ }
+
+ @VisibleForTesting
+ void disableAnimationsForTesting() {
+ mAnimationsEnabled = false;
+ }
+
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
@@ -476,7 +490,7 @@
notificationIconArea.addView(mNotificationIconAreaInner);
}
- updateNotificationIconAreaAndCallChip(/* animate= */ false);
+ updateNotificationIconAreaAndOngoingActivityChip(/* animate= */ false);
Trace.endSection();
}
@@ -493,15 +507,21 @@
private StatusBarVisibilityChangeListener mStatusBarVisibilityChangeListener =
new StatusBarVisibilityChangeListener() {
- @Override
- public void onStatusBarVisibilityMaybeChanged() {
- updateStatusBarVisibilities(/* animate= */ true);
- }
+ @Override
+ public void onStatusBarVisibilityMaybeChanged() {
+ updateStatusBarVisibilities(/* animate= */ true);
+ }
- @Override
- public void onTransitionFromLockscreenToDreamStarted() {
- mTransitionFromLockscreenToDreamStarted = true;
- }
+ @Override
+ public void onTransitionFromLockscreenToDreamStarted() {
+ mTransitionFromLockscreenToDreamStarted = true;
+ }
+
+ @Override
+ public void onOngoingActivityStatusChanged(boolean hasOngoingActivity) {
+ mHasOngoingActivity = hasOngoingActivity;
+ updateStatusBarVisibilities(/* animate= */ true);
+ }
};
@Override
@@ -532,11 +552,14 @@
}
}
- // The ongoing call chip and notification icon visibilities are intertwined, so update both
- // if either change.
- if (newModel.getShowNotificationIcons() != previousModel.getShowNotificationIcons()
- || newModel.getShowOngoingCallChip() != previousModel.getShowOngoingCallChip()) {
- updateNotificationIconAreaAndCallChip(animate);
+ // The ongoing activity chip and notification icon visibilities are intertwined, so update
+ // both if either change.
+ boolean notifsChanged =
+ newModel.getShowNotificationIcons() != previousModel.getShowNotificationIcons();
+ boolean ongoingActivityChanged =
+ newModel.getShowOngoingActivityChip() != previousModel.getShowOngoingActivityChip();
+ if (notifsChanged || ongoingActivityChanged) {
+ updateNotificationIconAreaAndOngoingActivityChip(animate);
}
// The clock may have already been hidden, but we might want to shift its
@@ -566,45 +589,58 @@
return new StatusBarVisibilityModel(
/* showClock= */ false,
/* showNotificationIcons= */ false,
- /* showOngoingCallChip= */ false,
+ /* showOngoingActivityChip= */ false,
/* showSystemInfo= */ false);
}
boolean showClock = externalModel.getShowClock() && !headsUpVisible;
- boolean showOngoingCallChip = mOngoingCallController.hasOngoingCall() && !headsUpVisible;
+
+ boolean showOngoingActivityChip;
+ if (Flags.statusBarScreenSharingChips()) {
+ // If this flag is on, the ongoing activity status comes from
+ // CollapsedStatusBarViewBinder, which updates the mHasOngoingActivity variable.
+ showOngoingActivityChip = mHasOngoingActivity;
+ } else {
+ // If this flag is off, the only ongoing activity is the ongoing call, and we pull it
+ // from the controller directly.
+ showOngoingActivityChip = mOngoingCallController.hasOngoingCall();
+ }
+
return new StatusBarVisibilityModel(
showClock,
externalModel.getShowNotificationIcons(),
- showOngoingCallChip,
+ showOngoingActivityChip && !headsUpVisible,
externalModel.getShowSystemInfo());
}
/**
- * Updates the visibility of the notification icon area and ongoing call chip based on disabled1
- * state.
+ * Updates the visibility of the notification icon area and ongoing activity chip based on
+ * mLastModifiedVisibility.
*/
- private void updateNotificationIconAreaAndCallChip(boolean animate) {
+ private void updateNotificationIconAreaAndOngoingActivityChip(boolean animate) {
StatusBarVisibilityModel visibilityModel = mLastModifiedVisibility;
boolean disableNotifications = !visibilityModel.getShowNotificationIcons();
- boolean hasOngoingCall = visibilityModel.getShowOngoingCallChip();
+ boolean hasOngoingActivity = visibilityModel.getShowOngoingActivityChip();
- // Hide notifications if the disable flag is set or we have an ongoing call.
- if (disableNotifications || hasOngoingCall) {
- hideNotificationIconArea(animate && !hasOngoingCall);
+ // Hide notifications if the disable flag is set or we have an ongoing activity.
+ if (disableNotifications || hasOngoingActivity) {
+ hideNotificationIconArea(animate && !hasOngoingActivity);
} else {
showNotificationIconArea(animate);
}
- // Show the ongoing call chip only if there is an ongoing call *and* notification icons
- // are allowed. (The ongoing call chip occupies the same area as the notification icons,
- // so if the icons are disabled then the call chip should be, too.)
- boolean showOngoingCallChip = hasOngoingCall && !disableNotifications;
- if (showOngoingCallChip) {
+ // Show the ongoing activity chip only if there is an ongoing activity *and* notification
+ // icons are allowed. (The ongoing activity chip occupies the same area as the notification,
+ // icons so if the icons are disabled then the activity chip should be, too.)
+ boolean showOngoingActivityChip = hasOngoingActivity && !disableNotifications;
+ if (showOngoingActivityChip) {
showOngoingActivityChip(animate);
} else {
hideOngoingActivityChip(animate);
}
- mOngoingCallController.notifyChipVisibilityChanged(showOngoingCallChip);
+ if (!Flags.statusBarScreenSharingChips()) {
+ mOngoingCallController.notifyChipVisibilityChanged(showOngoingActivityChip);
+ }
}
private boolean shouldHideStatusBar() {
@@ -702,8 +738,9 @@
/**
* Displays the ongoing activity chip.
*
- * For now, this chip will only ever contain the ongoing call information, but after b/332662551
- * feature is implemented, it will support different kinds of ongoing activities.
+ * If Flags.statusBarScreenSharingChips is disabled, this chip will only ever contain the
+ * ongoing call information, If that flag is enabled, it will support different kinds of ongoing
+ * activities. See b/332662551.
*/
private void showOngoingActivityChip(boolean animate) {
animateShow(mOngoingActivityChip, animate);
@@ -746,7 +783,7 @@
*/
private void animateHiddenState(final View v, int state, boolean animate) {
v.animate().cancel();
- if (!animate) {
+ if (!animate || !mAnimationsEnabled) {
v.setAlpha(0f);
v.setVisibility(state);
return;
@@ -773,7 +810,7 @@
private void animateShow(View v, boolean animate) {
v.animate().cancel();
v.setVisibility(View.VISIBLE);
- if (!animate) {
+ if (!animate || !mAnimationsEnabled) {
v.setAlpha(1f);
return;
}
@@ -872,6 +909,8 @@
@Override
public void dump(PrintWriter printWriter, String[] args) {
IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, /* singleIndent= */" ");
+ pw.println("mHasOngoingActivity=" + mHasOngoingActivity);
+ pw.println("mAnimationsEnabled=" + mAnimationsEnabled);
StatusBarFragmentComponent component = mStatusBarFragmentComponent;
if (component == null) {
pw.println("StatusBarFragmentComponent is null");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLogger.kt
index 7cdb9c0..0a19023 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLogger.kt
@@ -59,13 +59,13 @@
{
bool1 = model.showClock
bool2 = model.showNotificationIcons
- bool3 = model.showOngoingCallChip
+ bool3 = model.showOngoingActivityChip
bool4 = model.showSystemInfo
},
{ "New visibilities calculated internally. " +
"showClock=$bool1 " +
"showNotificationIcons=$bool2 " +
- "showOngoingCallChip=$bool3 " +
+ "showOngoingActivityChip=$bool3 " +
"showSystemInfo=$bool4"
}
)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarVisibilityModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarVisibilityModel.kt
index cf54cb7..fe24fae 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarVisibilityModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarVisibilityModel.kt
@@ -26,7 +26,7 @@
data class StatusBarVisibilityModel(
val showClock: Boolean,
val showNotificationIcons: Boolean,
- val showOngoingCallChip: Boolean,
+ val showOngoingActivityChip: Boolean,
val showSystemInfo: Boolean,
) {
companion object {
@@ -48,7 +48,7 @@
showNotificationIcons = (disabled1 and DISABLE_NOTIFICATION_ICONS) == 0,
// TODO(b/279899176): [CollapsedStatusBarFragment] always overwrites this with the
// value of [OngoingCallController]. Do we need to process the flag here?
- showOngoingCallChip = (disabled1 and DISABLE_ONGOING_CALL_CHIP) == 0,
+ showOngoingActivityChip = (disabled1 and DISABLE_ONGOING_CALL_CHIP) == 0,
showSystemInfo =
(disabled1 and DISABLE_SYSTEM_INFO) == 0 &&
(disabled2 and DISABLE2_SYSTEM_ICONS) == 0
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt
index 7d7f49b..a2ec1f2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt
@@ -19,11 +19,17 @@
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.view.View
+import android.widget.ImageView
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
+import com.android.systemui.Flags
+import com.android.systemui.common.ui.binder.IconViewBinder
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.res.R
+import com.android.systemui.statusbar.chips.domain.model.OngoingActivityChipModel
+import com.android.systemui.statusbar.chips.ui.binder.ChipChronometerBinder
+import com.android.systemui.statusbar.chips.ui.view.ChipChronometer
import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor
import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.CollapsedStatusBarViewModel
import javax.inject.Inject
@@ -75,6 +81,35 @@
}
}
}
+
+ if (Flags.statusBarScreenSharingChips()) {
+ val chipView: View = view.requireViewById(R.id.ongoing_activity_chip)
+ val chipIconView: ImageView =
+ chipView.requireViewById(R.id.ongoing_activity_chip_icon)
+ val chipTimeView: ChipChronometer =
+ chipView.requireViewById(R.id.ongoing_activity_chip_time)
+ launch {
+ viewModel.ongoingActivityChip.collect { chipModel ->
+ when (chipModel) {
+ is OngoingActivityChipModel.Shown -> {
+ IconViewBinder.bind(chipModel.icon, chipIconView)
+ ChipChronometerBinder.bind(chipModel.startTimeMs, chipTimeView)
+ // TODO(b/332662551): Attach click listener to chip
+
+ listener.onOngoingActivityStatusChanged(
+ hasOngoingActivity = true
+ )
+ }
+ is OngoingActivityChipModel.Hidden -> {
+ chipTimeView.stop()
+ listener.onOngoingActivityStatusChanged(
+ hasOngoingActivity = false
+ )
+ }
+ }
+ }
+ }
+ }
}
}
}
@@ -120,4 +155,7 @@
/** Called when a transition from lockscreen to dream has started. */
fun onTransitionFromLockscreenToDreamStarted()
+
+ /** Called when the status of the ongoing activity chip (active or not active) has changed. */
+ fun onOngoingActivityStatusChanged(hasOngoingActivity: Boolean)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModel.kt
index 0a6e95e..bb3a67e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModel.kt
@@ -24,6 +24,8 @@
import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
import com.android.systemui.keyguard.shared.model.KeyguardState.OCCLUDED
import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.statusbar.chips.domain.model.OngoingActivityChipModel
+import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModel
import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor
import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor
import com.android.systemui.statusbar.phone.domain.interactor.LightsOutInteractor
@@ -59,6 +61,9 @@
/** Emits whenever a transition from lockscreen to dream has started. */
val transitionFromLockscreenToDreamStartedEvent: Flow<Unit>
+ /** The ongoing activity chip that should be shown on the left-hand side of the status bar. */
+ val ongoingActivityChip: StateFlow<OngoingActivityChipModel>
+
/**
* Apps can request a low profile mode [android.view.View.SYSTEM_UI_FLAG_LOW_PROFILE] where
* status bar and navigation icons dim. In this mode, a notification dot appears where the
@@ -78,6 +83,7 @@
private val lightsOutInteractor: LightsOutInteractor,
private val notificationsInteractor: ActiveNotificationsInteractor,
keyguardTransitionInteractor: KeyguardTransitionInteractor,
+ ongoingActivityChipsViewModel: OngoingActivityChipsViewModel,
@Application coroutineScope: CoroutineScope,
) : CollapsedStatusBarViewModel {
override val isTransitioningFromLockscreenToOccluded: StateFlow<Boolean> =
@@ -91,6 +97,8 @@
.filter { it.transitionState == TransitionState.STARTED }
.map {}
+ override val ongoingActivityChip = ongoingActivityChipsViewModel.chip
+
override fun areNotificationsLightsOut(displayId: Int): Flow<Boolean> =
if (NotificationsLiveDataStoreRefactor.isUnexpectedlyInLegacyMode()) {
emptyFlow()
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 58b82f1..da928a3 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 androidx.annotation.NonNull;
import com.android.internal.camera.flags.Flags;
+import com.android.systemui.util.ListenerSet;
import java.util.Set;
@@ -43,7 +44,7 @@
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 @@
@Override
public void addCallback(@NonNull Callback listener) {
- mCallbacks.add(listener);
+ mCallbacks.addIfAbsent(listener);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/JavaAdapter.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/JavaAdapter.kt
index 1ec86a4..8c46f9a 100644
--- a/packages/SystemUI/src/com/android/systemui/util/kotlin/JavaAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/JavaAdapter.kt
@@ -88,8 +88,8 @@
flow: Flow<T>,
consumer: Consumer<T>,
state: Lifecycle.State = Lifecycle.State.CREATED,
-) {
- lifecycle.coroutineScope.launch {
+): Job {
+ return lifecycle.coroutineScope.launch {
lifecycle.repeatOnLifecycle(state) { flow.collect { consumer.accept(it) } }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/domain/interactor/AudioOutputInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/domain/interactor/AudioOutputInteractor.kt
index b6246da..c6b0dc5 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/domain/interactor/AudioOutputInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/domain/interactor/AudioOutputInteractor.kt
@@ -30,7 +30,6 @@
import com.android.settingslib.volume.domain.interactor.AudioModeInteractor
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.volume.domain.model.AudioOutputDevice
-import com.android.systemui.volume.panel.component.mediaoutput.data.repository.LocalMediaRepositoryFactory
import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaOutputInteractor
import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope
import javax.inject.Inject
@@ -58,8 +57,7 @@
private val bluetoothAdapter: BluetoothAdapter?,
private val deviceIconInteractor: DeviceIconInteractor,
private val mediaOutputInteractor: MediaOutputInteractor,
- private val localMediaRepositoryFactory: LocalMediaRepositoryFactory,
- private val audioSharingRepository: AudioSharingRepository,
+ audioSharingRepository: AudioSharingRepository,
) {
val currentAudioDevice: Flow<AudioOutputDevice> =
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModel.kt
index fd01b48..850162e 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModel.kt
@@ -146,14 +146,18 @@
isEnabled = isEnabled,
a11yStep = volumeRange.step,
a11yClickDescription =
- context.getString(
- if (isMuted) {
- R.string.volume_panel_hint_unmute
- } else {
- R.string.volume_panel_hint_mute
- },
- label,
- ),
+ if (isAffectedByMute) {
+ context.getString(
+ if (isMuted) {
+ R.string.volume_panel_hint_unmute
+ } else {
+ R.string.volume_panel_hint_mute
+ },
+ label,
+ )
+ } else {
+ null
+ },
a11yStateDescription =
if (volume == volumeRange.first) {
context.getString(
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 03c8af90..99f95648 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 @@
}
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/hearingaid/HearingDevicesDialogDelegateTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java
index 8895a5e..0db0de2 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.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.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.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 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 @@
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 @@
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 @@
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 @@
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 0000000..7172923
--- /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/ambient/touch/TouchMonitorTest.java b/packages/SystemUI/tests/src/com/android/systemui/ambient/touch/TouchMonitorTest.java
index d01d57e..358e8cb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ambient/touch/TouchMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ambient/touch/TouchMonitorTest.java
@@ -22,6 +22,8 @@
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
@@ -45,6 +47,7 @@
import androidx.annotation.NonNull;
import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LifecycleRegistry;
import androidx.test.filters.SmallTest;
@@ -67,6 +70,7 @@
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
+import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ExecutionException;
@@ -119,6 +123,8 @@
private final KosmosJavaAdapter mKosmos;
+ private ArrayList<LifecycleObserver> mLifecycleObservers = new ArrayList<>();
+
Environment(Set<TouchHandler> handlers, KosmosJavaAdapter kosmos) {
mLifecycleOwner = new SimpleLifecycleOwner();
@@ -147,8 +153,14 @@
mMonitor = new TouchMonitor(mExecutor, mBackgroundExecutor, mLifecycleRegistry,
mInputFactory, mDisplayHelper, mKosmos.getConfigurationInteractor(),
handlers, mIWindowManager, 0);
+ clearInvocations(mLifecycleRegistry);
mMonitor.init();
+ ArgumentCaptor<LifecycleObserver> observerCaptor =
+ ArgumentCaptor.forClass(LifecycleObserver.class);
+ verify(mLifecycleRegistry, atLeast(1)).addObserver(observerCaptor.capture());
+ mLifecycleObservers.addAll(observerCaptor.getAllValues());
+
updateLifecycle(Lifecycle.State.RESUMED);
// Capture creation request.
@@ -187,6 +199,16 @@
verify(mInputSession).dispose();
Mockito.clearInvocations(mInputSession);
}
+
+ void destroyMonitor() {
+ mMonitor.destroy();
+ }
+
+ void verifyLifecycleObserversUnregistered() {
+ for (LifecycleObserver observer : mLifecycleObservers) {
+ verify(mLifecycleRegistry).removeObserver(observer);
+ }
+ }
}
@Test
@@ -642,6 +664,16 @@
verify(callback).onRemoved();
}
+ @Test
+ public void testDestroy_cleansUpLifecycleObserver() {
+ final TouchHandler touchHandler = createTouchHandler();
+
+ final Environment environment = new Environment(Stream.of(touchHandler)
+ .collect(Collectors.toCollection(HashSet::new)), mKosmos);
+ environment.destroyMonitor();
+ environment.verifyLifecycleObserversUnregistered();
+ }
+
private GestureDetector.OnGestureListener registerGestureListener(TouchHandler handler) {
final GestureDetector.OnGestureListener gestureListener = Mockito.mock(
GestureDetector.OnGestureListener.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
index e81369d..9a99ed7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
@@ -18,6 +18,7 @@
import android.app.ActivityTaskManager
import android.app.admin.DevicePolicyManager
import android.content.pm.PackageManager
+import android.content.res.Configuration
import android.hardware.biometrics.BiometricAuthenticator
import android.hardware.biometrics.BiometricConstants
import android.hardware.biometrics.BiometricManager
@@ -127,6 +128,12 @@
private lateinit var packageManager: PackageManager
@Mock private lateinit var activityTaskManager: ActivityTaskManager
+ private lateinit var displayRepository: FakeDisplayRepository
+ private lateinit var displayStateInteractor: DisplayStateInteractor
+ private lateinit var udfpsOverlayInteractor: UdfpsOverlayInteractor
+ private lateinit var biometricStatusInteractor: BiometricStatusInteractor
+ private lateinit var iconProvider: IconProvider
+
private val testScope = TestScope(StandardTestDispatcher())
private val fakeExecutor = FakeExecutor(FakeSystemClock())
private val biometricPromptRepository = FakePromptRepository()
@@ -142,17 +149,12 @@
private val promptSelectorInteractor by lazy {
PromptSelectorInteractorImpl(
fingerprintRepository,
+ displayStateInteractor,
biometricPromptRepository,
lockPatternUtils,
)
}
- private lateinit var displayRepository: FakeDisplayRepository
- private lateinit var displayStateInteractor: DisplayStateInteractor
- private lateinit var udfpsOverlayInteractor: UdfpsOverlayInteractor
- private lateinit var biometricStatusInteractor: BiometricStatusInteractor
- private lateinit var iconProvider: IconProvider
-
private val credentialViewModel = CredentialViewModel(mContext, bpCredentialInteractor)
private val defaultLogoIcon = context.getDrawable(R.drawable.ic_android)
@@ -392,6 +394,33 @@
}
@Test
+ fun testAnimateToCredentialUI_rotateCredentialUI() {
+ val container = initializeFingerprintContainer(
+ authenticators = BiometricManager.Authenticators.BIOMETRIC_WEAK or
+ BiometricManager.Authenticators.DEVICE_CREDENTIAL
+ )
+ container.animateToCredentialUI(false)
+ waitForIdleSync()
+
+ assertThat(container.hasCredentialView()).isTrue()
+ assertThat(container.hasBiometricPrompt()).isFalse()
+
+ // Check credential view persists after new attachment
+ container.onAttachedToWindow()
+
+ assertThat(container.hasCredentialView()).isTrue()
+ assertThat(container.hasBiometricPrompt()).isFalse()
+
+ val configuration = Configuration(context.resources.configuration)
+ configuration.orientation = Configuration.ORIENTATION_LANDSCAPE
+ container.dispatchConfigurationChanged(configuration)
+ waitForIdleSync()
+
+ assertThat(container.hasCredentialView()).isTrue()
+ assertThat(container.hasBiometricPrompt()).isFalse()
+ }
+
+ @Test
fun testShowBiometricUI() {
mSetFlagsRule.disableFlags(FLAG_CONSTRAINT_BP)
val container = initializeFingerprintContainer()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorImplTest.kt
index 3102a84..6e78e33 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorImplTest.kt
@@ -25,13 +25,16 @@
import androidx.test.filters.SmallTest
import com.android.internal.widget.LockPatternUtils
import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.data.repository.FakeDisplayStateRepository
import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
import com.android.systemui.biometrics.data.repository.FakePromptRepository
import com.android.systemui.biometrics.faceSensorPropertiesInternal
import com.android.systemui.biometrics.fingerprintSensorPropertiesInternal
import com.android.systemui.biometrics.shared.model.BiometricModalities
+import com.android.systemui.biometrics.shared.model.DisplayRotation
import com.android.systemui.biometrics.shared.model.PromptKind
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.display.data.repository.FakeDisplayRepository
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.whenever
@@ -75,12 +78,30 @@
private val promptRepository = FakePromptRepository()
private val fakeExecutor = FakeExecutor(FakeSystemClock())
+ private lateinit var displayStateRepository: FakeDisplayStateRepository
+ private lateinit var displayRepository: FakeDisplayRepository
+ private lateinit var displayStateInteractor: DisplayStateInteractor
private lateinit var interactor: PromptSelectorInteractor
@Before
fun setup() {
+ displayStateRepository = FakeDisplayStateRepository()
+ displayRepository = FakeDisplayRepository()
+ displayStateInteractor =
+ DisplayStateInteractorImpl(
+ testScope.backgroundScope,
+ mContext,
+ fakeExecutor,
+ displayStateRepository,
+ displayRepository,
+ )
interactor =
- PromptSelectorInteractorImpl(fingerprintRepository, promptRepository, lockPatternUtils)
+ PromptSelectorInteractorImpl(
+ fingerprintRepository,
+ displayStateInteractor,
+ promptRepository,
+ lockPatternUtils
+ )
}
private fun basicPromptInfo() =
@@ -155,7 +176,8 @@
modalities,
CHALLENGE,
OP_PACKAGE_NAME,
- false /*onSwitchToCredential*/
+ onSwitchToCredential = false,
+ isLandscape = false,
)
assertThat(currentPrompt).isNotNull()
@@ -200,22 +222,49 @@
fun promptKind_isBiometric_whenBiometricAllowed() =
testScope.runTest {
setUserCredentialType(isPassword = true)
- val info = basicPromptInfo()
val promptKind by collectLastValue(interactor.promptKind)
assertThat(promptKind).isEqualTo(PromptKind.None)
- interactor.setPrompt(
- info,
- USER_ID,
- REQUEST_ID,
- modalities,
- CHALLENGE,
- OP_PACKAGE_NAME,
- false /*onSwitchToCredential*/
- )
+ setPrompt()
- assertThat(promptKind?.isBiometric()).isTrue()
+ assertThat(promptKind?.isOnePanePortraitBiometric()).isTrue()
+
+ interactor.resetPrompt(REQUEST_ID)
+ verifyUnset()
+ }
+
+ @Test
+ fun promptKind_isBiometricTwoPane_whenBiometricAllowed_landscape() =
+ testScope.runTest {
+ setUserCredentialType(isPassword = true)
+ displayStateRepository.setIsLargeScreen(false)
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_90)
+
+ val promptKind by collectLastValue(interactor.promptKind)
+ assertThat(promptKind).isEqualTo(PromptKind.None)
+
+ setPrompt()
+
+ assertThat(promptKind?.isTwoPaneLandscapeBiometric()).isTrue()
+
+ interactor.resetPrompt(REQUEST_ID)
+ verifyUnset()
+ }
+
+ @Test
+ fun promptKind_isBiometricOnePane_whenBiometricAllowed_largeScreenLandscape() =
+ testScope.runTest {
+ setUserCredentialType(isPassword = true)
+ displayStateRepository.setIsLargeScreen(true)
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_90)
+
+ val promptKind by collectLastValue(interactor.promptKind)
+ assertThat(promptKind).isEqualTo(PromptKind.None)
+
+ setPrompt()
+
+ assertThat(promptKind?.isOnePaneLargeScreenLandscapeBiometric()).isTrue()
interactor.resetPrompt(REQUEST_ID)
verifyUnset()
@@ -225,20 +274,11 @@
fun promptKind_isCredential_onSwitchToCredential() =
testScope.runTest {
setUserCredentialType(isPassword = true)
- val info = basicPromptInfo()
val promptKind by collectLastValue(interactor.promptKind)
assertThat(promptKind).isEqualTo(PromptKind.None)
- interactor.setPrompt(
- info,
- USER_ID,
- REQUEST_ID,
- modalities,
- CHALLENGE,
- OP_PACKAGE_NAME,
- true /*onSwitchToCredential*/
- )
+ setPrompt(onSwitchToCredential = true)
assertThat(promptKind).isEqualTo(PromptKind.Password)
@@ -259,15 +299,7 @@
val promptKind by collectLastValue(interactor.promptKind)
assertThat(promptKind).isEqualTo(PromptKind.None)
- interactor.setPrompt(
- info,
- USER_ID,
- REQUEST_ID,
- modalities,
- CHALLENGE,
- OP_PACKAGE_NAME,
- false /*onSwitchToCredential*/
- )
+ setPrompt(info)
assertThat(promptKind).isEqualTo(PromptKind.Password)
@@ -292,15 +324,7 @@
val promptKind by collectLastValue(interactor.promptKind)
assertThat(promptKind).isEqualTo(PromptKind.None)
- interactor.setPrompt(
- info,
- USER_ID,
- REQUEST_ID,
- modalities,
- CHALLENGE,
- OP_PACKAGE_NAME,
- false /*onSwitchToCredential*/
- )
+ setPrompt(info)
assertThat(promptKind).isEqualTo(PromptKind.Password)
@@ -312,6 +336,7 @@
fun promptKind_isBiometric_whenBiometricIsNotAllowed_withVerticalList() =
testScope.runTest {
setUserCredentialType(isPassword = true)
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_90)
val info =
basicPromptInfo().apply {
isDeviceCredentialAllowed = true
@@ -322,22 +347,32 @@
val promptKind by collectLastValue(interactor.promptKind)
assertThat(promptKind).isEqualTo(PromptKind.None)
- interactor.setPrompt(
- info,
- USER_ID,
- REQUEST_ID,
- modalities,
- CHALLENGE,
- OP_PACKAGE_NAME,
- false /*onSwitchToCredential*/
- )
+ setPrompt(info)
- assertThat(promptKind?.isBiometric()).isTrue()
+ assertThat(promptKind?.isOnePaneNoSensorLandscapeBiometric()).isTrue()
interactor.resetPrompt(REQUEST_ID)
verifyUnset()
}
+ private fun setPrompt(
+ info: PromptInfo = basicPromptInfo(),
+ onSwitchToCredential: Boolean = false
+ ) {
+ interactor.setPrompt(
+ info,
+ USER_ID,
+ REQUEST_ID,
+ modalities,
+ CHALLENGE,
+ OP_PACKAGE_NAME,
+ onSwitchToCredential = onSwitchToCredential,
+ isLandscape =
+ displayStateRepository.currentRotation.value == DisplayRotation.ROTATION_90 ||
+ displayStateRepository.currentRotation.value == DisplayRotation.ROTATION_270,
+ )
+ }
+
private fun TestScope.useCredentialAndReset(kind: PromptKind) {
setUserCredentialType(
isPin = kind == PromptKind.Pin,
@@ -366,7 +401,8 @@
BiometricModalities(),
CHALLENGE,
OP_PACKAGE_NAME,
- false /*onSwitchToCredential*/
+ onSwitchToCredential = false,
+ isLandscape = false,
)
// not using biometrics, should be null with no fallback option
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
index c177511..1167fce 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
@@ -1407,7 +1407,12 @@
runningTaskInfo.topActivity = topActivity
whenever(activityTaskManager.getTasks(1)).thenReturn(listOf(runningTaskInfo))
selector =
- PromptSelectorInteractorImpl(fingerprintRepository, promptRepository, lockPatternUtils)
+ PromptSelectorInteractorImpl(
+ fingerprintRepository,
+ displayStateInteractor,
+ promptRepository,
+ lockPatternUtils
+ )
selector.resetPrompt(REQUEST_ID)
viewModel =
@@ -1643,7 +1648,8 @@
BiometricModalities(fingerprintProperties = fingerprint, faceProperties = face),
CHALLENGE,
packageName,
- false /*onUseDeviceCredential*/
+ onSwitchToCredential = false,
+ isLandscape = false,
)
}
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 07c980b..18bd960b 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 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 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 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 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 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 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 36bfa09..90ac05f 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 @@
.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 0bdf47a..f0ad510 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.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.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 @@
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,20 +108,6 @@
}
@Test
- @DisableFlags(Flags.FLAG_COMPOSE_LOCKSCREEN)
- fun fingerprintPropertyInitialized_updatesBlueprint() {
- testScope.runTest {
- assertThat(kosmos.keyguardBlueprintRepository.targetTransitionConfig).isNull()
-
- fingerprintPropertyRepository.supportsUdfps() // initialize properties
-
- runCurrent()
- advanceUntilIdle()
- assertThat(kosmos.keyguardBlueprintRepository.targetTransitionConfig).isNotNull()
- }
- }
-
- @Test
@EnableFlags(Flags.FLAG_COMPOSE_LOCKSCREEN)
fun testDoesNotApplySplitShadeBlueprint() {
testScope.runTest {
@@ -132,15 +123,31 @@
}
@Test
+ @DisableFlags(Flags.FLAG_COMPOSE_LOCKSCREEN)
+ fun fingerprintPropertyInitialized_updatesBlueprint() {
+ testScope.runTest {
+ underTest.start()
+ reset(keyguardBlueprintRepository)
+
+ fingerprintPropertyRepository.supportsUdfps() // initialize properties
+
+ runCurrent()
+ advanceUntilIdle()
+ 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 35659c1..14d9548 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 @@
.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 ef3183a8..ced3526 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 @@
.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 616aac7..344e0fc 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.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 @@
@RunWith(AndroidTestingRunner::class)
@RunWithLooper(setAsMainLooper = true)
+@ExperimentalCoroutinesApi
@SmallTest
class DefaultKeyguardBlueprintTest : SysuiTestCase() {
private lateinit var underTest: DefaultKeyguardBlueprint
@@ -112,17 +114,66 @@
@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(mDefaultDeviceEntrySection).addViews(constraintLayout)
- verify(someSection).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)
+ }
+
+ rebuildSections.forEach {
+ verify(it).addViews(constraintLayout)
+ verify(it).removeViews(constraintLayout)
+ }
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModelTest.kt
index a18b033..ec2a1d3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModelTest.kt
@@ -17,9 +17,11 @@
package com.android.systemui.keyguard.ui.viewmodel
+import android.os.fakeExecutorHandler
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor
+import com.android.systemui.testKosmos
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -33,12 +35,16 @@
class KeyguardBlueprintViewModelTest : SysuiTestCase() {
@Mock private lateinit var keyguardBlueprintInteractor: KeyguardBlueprintInteractor
private lateinit var undertest: KeyguardBlueprintViewModel
+ private val kosmos = testKosmos()
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
undertest =
- KeyguardBlueprintViewModel(keyguardBlueprintInteractor = keyguardBlueprintInteractor)
+ KeyguardBlueprintViewModel(
+ handler = kosmos.fakeExecutorHandler,
+ keyguardBlueprintInteractor = keyguardBlueprintInteractor,
+ )
}
@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 16421a0..bdc5fc3 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 @@
.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 83382207..8a12a90 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 @@
.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 d2701dd..16d8819 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.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.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 @@
@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 @@
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 @@
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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
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 @@
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 @@
@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 @@
}
@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 @@
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 @@
@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/mediaprojection/data/repository/MediaProjectionManagerRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepositoryTest.kt
index ef73e2e..e487780 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepositoryTest.kt
@@ -28,7 +28,6 @@
import com.android.systemui.mediaprojection.taskswitcher.FakeActivityTaskManager.Companion.createToken
import com.android.systemui.mediaprojection.taskswitcher.fakeActivityTaskManager
import com.android.systemui.mediaprojection.taskswitcher.fakeMediaProjectionManager
-import com.android.systemui.mediaprojection.taskswitcher.mediaProjectionManagerRepository
import com.android.systemui.mediaprojection.taskswitcher.taskSwitcherKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runTest
@@ -45,7 +44,7 @@
private val fakeMediaProjectionManager = kosmos.fakeMediaProjectionManager
private val fakeActivityTaskManager = kosmos.fakeActivityTaskManager
- private val repo = kosmos.mediaProjectionManagerRepository
+ private val repo = kosmos.realMediaProjectionRepository
@Test
fun switchProjectedTask_stateIsUpdatedWithNewTask() =
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 0000000..b0aa6dd
--- /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 0000000..9b08432e
--- /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 9798562..29487cd 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 @@
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/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractorTest.kt
new file mode 100644
index 0000000..0f33b9d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractorTest.kt
@@ -0,0 +1,100 @@
+/*
+ * 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.statusbar.chips.mediaprojection.domain.interactor
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.mediaprojection.data.model.MediaProjectionState
+import com.android.systemui.mediaprojection.data.repository.fakeMediaProjectionRepository
+import com.android.systemui.mediaprojection.taskswitcher.FakeActivityTaskManager.Companion.createTask
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.chips.domain.model.OngoingActivityChipModel
+import com.android.systemui.statusbar.chips.ui.viewmodel.mediaProjectionChipInteractor
+import com.android.systemui.util.time.fakeSystemClock
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.Test
+import kotlinx.coroutines.test.runTest
+
+@SmallTest
+class MediaProjectionChipInteractorTest : SysuiTestCase() {
+ private val kosmos = Kosmos()
+ private val testScope = kosmos.testScope
+ private val mediaProjectionRepo = kosmos.fakeMediaProjectionRepository
+ private val systemClock = kosmos.fakeSystemClock
+
+ private val underTest = kosmos.mediaProjectionChipInteractor
+
+ @Test
+ fun chip_notProjectingState_isHidden() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.chip)
+
+ mediaProjectionRepo.mediaProjectionState.value = MediaProjectionState.NotProjecting
+
+ assertThat(latest).isInstanceOf(OngoingActivityChipModel.Hidden::class.java)
+ }
+
+ @Test
+ fun chip_singleTaskState_isShownWithIcon() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.chip)
+
+ mediaProjectionRepo.mediaProjectionState.value =
+ MediaProjectionState.SingleTask(createTask(taskId = 1))
+
+ assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java)
+ val icon = (latest as OngoingActivityChipModel.Shown).icon
+ assertThat((icon as Icon.Resource).res).isEqualTo(R.drawable.ic_cast_connected)
+ }
+
+ @Test
+ fun chip_entireScreenState_isShownWithIcon() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.chip)
+
+ mediaProjectionRepo.mediaProjectionState.value = MediaProjectionState.EntireScreen
+
+ assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java)
+ val icon = (latest as OngoingActivityChipModel.Shown).icon
+ assertThat((icon as Icon.Resource).res).isEqualTo(R.drawable.ic_cast_connected)
+ }
+
+ @Test
+ fun chip_timeResetsOnEachNewShare() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.chip)
+
+ systemClock.setElapsedRealtime(1234)
+ mediaProjectionRepo.mediaProjectionState.value = MediaProjectionState.EntireScreen
+
+ assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java)
+ assertThat((latest as OngoingActivityChipModel.Shown).startTimeMs).isEqualTo(1234)
+
+ mediaProjectionRepo.mediaProjectionState.value = MediaProjectionState.NotProjecting
+ assertThat(latest).isInstanceOf(OngoingActivityChipModel.Hidden::class.java)
+
+ systemClock.setElapsedRealtime(5678)
+ mediaProjectionRepo.mediaProjectionState.value = MediaProjectionState.EntireScreen
+
+ assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java)
+ assertThat((latest as OngoingActivityChipModel.Shown).startTimeMs).isEqualTo(5678)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt
index 1260f07..121229c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt
@@ -23,6 +23,9 @@
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.testScope
+import com.android.systemui.mediaprojection.data.model.MediaProjectionState
+import com.android.systemui.mediaprojection.data.repository.fakeMediaProjectionRepository
+import com.android.systemui.mediaprojection.taskswitcher.FakeActivityTaskManager.Companion.createTask
import com.android.systemui.res.R
import com.android.systemui.screenrecord.data.model.ScreenRecordModel
import com.android.systemui.screenrecord.data.repository.screenRecordRepository
@@ -35,13 +38,20 @@
class OngoingActivityChipsViewModelTest : SysuiTestCase() {
private val kosmos = Kosmos()
+ private val testScope = kosmos.testScope
+
+ private val screenRecordState = kosmos.screenRecordRepository.screenRecordState
+ private val mediaProjectionState = kosmos.fakeMediaProjectionRepository.mediaProjectionState
+ private val callState = kosmos.callChipInteractor.chip
+
private val underTest = kosmos.ongoingActivityChipsViewModel
@Test
fun chip_allHidden_hidden() =
- kosmos.testScope.runTest {
- kosmos.screenRecordRepository.screenRecordState.value = ScreenRecordModel.DoingNothing
- kosmos.callChipInteractor.chip.value = OngoingActivityChipModel.Hidden
+ testScope.runTest {
+ screenRecordState.value = ScreenRecordModel.DoingNothing
+ mediaProjectionState.value = MediaProjectionState.NotProjecting
+ callState.value = OngoingActivityChipModel.Hidden
val latest by collectLastValue(underTest.chip)
@@ -50,9 +60,10 @@
@Test
fun chip_screenRecordShow_restHidden_screenRecordShown() =
- kosmos.testScope.runTest {
- kosmos.screenRecordRepository.screenRecordState.value = ScreenRecordModel.Recording
- kosmos.callChipInteractor.chip.value = OngoingActivityChipModel.Hidden
+ testScope.runTest {
+ screenRecordState.value = ScreenRecordModel.Recording
+ mediaProjectionState.value = MediaProjectionState.NotProjecting
+ callState.value = OngoingActivityChipModel.Hidden
val latest by collectLastValue(underTest.chip)
@@ -61,15 +72,15 @@
@Test
fun chip_screenRecordShowAndCallShow_screenRecordShown() =
- kosmos.testScope.runTest {
- kosmos.screenRecordRepository.screenRecordState.value = ScreenRecordModel.Recording
+ testScope.runTest {
+ screenRecordState.value = ScreenRecordModel.Recording
val callChip =
OngoingActivityChipModel.Shown(
Icon.Resource(R.drawable.ic_call, ContentDescription.Loaded("icon")),
startTimeMs = 600L,
) {}
- kosmos.callChipInteractor.chip.value = callChip
+ callState.value = callChip
val latest by collectLastValue(underTest.chip)
@@ -77,16 +88,46 @@
}
@Test
- fun chip_screenRecordHideAndCallShown_callShown() =
- kosmos.testScope.runTest {
- kosmos.screenRecordRepository.screenRecordState.value = ScreenRecordModel.DoingNothing
+ fun chip_screenRecordShowAndMediaProjectionShow_screenRecordShown() =
+ testScope.runTest {
+ screenRecordState.value = ScreenRecordModel.Recording
+ mediaProjectionState.value = MediaProjectionState.EntireScreen
+ callState.value = OngoingActivityChipModel.Hidden
+
+ val latest by collectLastValue(underTest.chip)
+
+ assertIsScreenRecordChip(latest)
+ }
+
+ @Test
+ fun chip_mediaProjectionShowAndCallShow_mediaProjectionShown() =
+ testScope.runTest {
+ screenRecordState.value = ScreenRecordModel.DoingNothing
+ mediaProjectionState.value = MediaProjectionState.EntireScreen
+ val callChip =
+ OngoingActivityChipModel.Shown(
+ Icon.Resource(R.drawable.ic_call, ContentDescription.Loaded("icon")),
+ startTimeMs = 600L,
+ ) {}
+ callState.value = callChip
+
+ val latest by collectLastValue(underTest.chip)
+
+ assertIsMediaProjectionChip(latest)
+ }
+
+ @Test
+ fun chip_screenRecordAndMediaProjectionHideAndCallShown_callShown() =
+ testScope.runTest {
+ screenRecordState.value = ScreenRecordModel.DoingNothing
+ mediaProjectionState.value = MediaProjectionState.NotProjecting
val callChip =
OngoingActivityChipModel.Shown(
Icon.Resource(R.drawable.ic_call, ContentDescription.Loaded("icon")),
startTimeMs = 600L,
) {}
- kosmos.callChipInteractor.chip.value = callChip
+ callState.value = callChip
val latest by collectLastValue(underTest.chip)
@@ -95,22 +136,29 @@
@Test
fun chip_higherPriorityChipAdded_lowerPriorityChipReplaced() =
- kosmos.testScope.runTest {
+ testScope.runTest {
// Start with just the lower priority call chip
val callChip =
OngoingActivityChipModel.Shown(
Icon.Resource(R.drawable.ic_call, ContentDescription.Loaded("icon")),
startTimeMs = 600L,
) {}
- kosmos.callChipInteractor.chip.value = callChip
- kosmos.screenRecordRepository.screenRecordState.value = ScreenRecordModel.DoingNothing
+ callState.value = callChip
+ mediaProjectionState.value = MediaProjectionState.NotProjecting
+ screenRecordState.value = ScreenRecordModel.DoingNothing
val latest by collectLastValue(underTest.chip)
assertThat(latest).isEqualTo(callChip)
+ // WHEN the higher priority media projection chip is added
+ mediaProjectionState.value = MediaProjectionState.SingleTask(createTask(taskId = 1))
+
+ // THEN the higher priority media projection chip is used
+ assertIsMediaProjectionChip(latest)
+
// WHEN the higher priority screen record chip is added
- kosmos.screenRecordRepository.screenRecordState.value = ScreenRecordModel.Recording
+ screenRecordState.value = ScreenRecordModel.Recording
// THEN the higher priority screen record chip is used
assertIsScreenRecordChip(latest)
@@ -118,31 +166,47 @@
@Test
fun chip_highestPriorityChipRemoved_showsNextPriorityChip() =
- kosmos.testScope.runTest {
- // Start with both the higher priority screen record chip and lower priority call chip
- kosmos.screenRecordRepository.screenRecordState.value = ScreenRecordModel.Recording
+ testScope.runTest {
+ // WHEN all chips are active
+ screenRecordState.value = ScreenRecordModel.Recording
+ mediaProjectionState.value = MediaProjectionState.EntireScreen
val callChip =
OngoingActivityChipModel.Shown(
Icon.Resource(R.drawable.ic_call, ContentDescription.Loaded("icon")),
startTimeMs = 600L,
) {}
- kosmos.callChipInteractor.chip.value = callChip
+ callState.value = callChip
val latest by collectLastValue(underTest.chip)
+ // THEN the highest priority screen record is used
assertIsScreenRecordChip(latest)
// WHEN the higher priority screen record is removed
- kosmos.screenRecordRepository.screenRecordState.value = ScreenRecordModel.DoingNothing
+ screenRecordState.value = ScreenRecordModel.DoingNothing
+
+ // THEN the lower priority media projection is used
+ assertIsMediaProjectionChip(latest)
+
+ // WHEN the higher priority media projection is removed
+ mediaProjectionState.value = MediaProjectionState.NotProjecting
// THEN the lower priority call is used
assertThat(latest).isEqualTo(callChip)
}
- private fun assertIsScreenRecordChip(latest: OngoingActivityChipModel?) {
- assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java)
- val icon = (latest as OngoingActivityChipModel.Shown).icon
- assertThat((icon as Icon.Resource).res).isEqualTo(R.drawable.stat_sys_screen_record)
+ companion object {
+ fun assertIsScreenRecordChip(latest: OngoingActivityChipModel?) {
+ assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java)
+ val icon = (latest as OngoingActivityChipModel.Shown).icon
+ assertThat((icon as Icon.Resource).res).isEqualTo(R.drawable.stat_sys_screen_record)
+ }
+
+ fun assertIsMediaProjectionChip(latest: OngoingActivityChipModel?) {
+ assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java)
+ val icon = (latest as OngoingActivityChipModel.Shown).icon
+ assertThat((icon as Icon.Resource).res).isEqualTo(R.drawable.ic_cast_connected)
+ }
}
}
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 f461e2f..12f3ef3 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 @@
// 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 62804ed1..cb9790b 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.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 @@
@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 @@
mUserTracker,
() -> mFingerprintManager,
mActivityStarter,
- mBrightnessMirrorShowingInteractor
+ mBrightnessMirrorShowingInteractor,
+ mGlanceableHubContainerController
);
mScreenLifecycle.addObserver(mCentralSurfaces.mScreenObserver);
mCentralSurfaces.initShadeVisibilityListener();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLoggerTest.kt
index 87d813c..e0f1e1a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLoggerTest.kt
@@ -63,7 +63,7 @@
StatusBarVisibilityModel(
showClock = false,
showNotificationIcons = true,
- showOngoingCallChip = false,
+ showOngoingActivityChip = false,
showSystemInfo = true,
)
)
@@ -74,7 +74,7 @@
assertThat(actualString).contains("showClock=false")
assertThat(actualString).contains("showNotificationIcons=true")
- assertThat(actualString).contains("showOngoingCallChip=false")
+ assertThat(actualString).contains("showOngoingActivityChip=false")
assertThat(actualString).contains("showSystemInfo=true")
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
index ff182ad..ee27cea 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
@@ -16,6 +16,7 @@
import static android.view.Display.DEFAULT_DISPLAY;
+import static com.android.systemui.Flags.FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS;
import static com.android.systemui.shade.ShadeExpansionStateManagerKt.STATE_CLOSED;
import static com.android.systemui.shade.ShadeExpansionStateManagerKt.STATE_OPEN;
@@ -33,6 +34,8 @@
import android.content.Context;
import android.os.Bundle;
import android.os.UserHandle;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
@@ -46,7 +49,6 @@
import com.android.systemui.animation.AnimatorTestRule;
import com.android.systemui.demomode.DemoModeController;
import com.android.systemui.dump.DumpManager;
-import com.android.systemui.kosmos.KosmosJavaAdapter;
import com.android.systemui.log.LogBuffer;
import com.android.systemui.log.LogcatEchoTracker;
import com.android.systemui.plugins.DarkIconDispatcher;
@@ -56,7 +58,6 @@
import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.OperatorNameViewController;
-import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModel;
import com.android.systemui.statusbar.disableflags.DisableFlagsLogger;
import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerStatusBarViewBinder;
@@ -92,11 +93,9 @@
@RunWithLooper(setAsMainLooper = true)
@SmallTest
public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
- private final KosmosJavaAdapter mKosmos = new KosmosJavaAdapter();
private NotificationIconAreaController mMockNotificationAreaController;
private ShadeExpansionStateManager mShadeExpansionStateManager;
private OngoingCallController mOngoingCallController;
- private OngoingActivityChipsViewModel mOngoingActivityChipsViewModel;
private SystemStatusAnimationScheduler mAnimationScheduler;
private StatusBarLocationPublisher mLocationPublisher;
// Set in instantiate()
@@ -421,6 +420,7 @@
}
@Test
+ @DisableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
public void disable_noOngoingCall_chipHidden() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -433,6 +433,7 @@
}
@Test
+ @DisableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
public void disable_hasOngoingCall_chipDisplayedAndNotificationIconsHidden() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -446,6 +447,7 @@
}
@Test
+ @DisableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
public void disable_hasOngoingCallButNotificationIconsDisabled_chipHidden() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -459,6 +461,7 @@
}
@Test
+ @DisableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
public void disable_hasOngoingCallButAlsoHun_chipHidden() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -472,6 +475,7 @@
}
@Test
+ @DisableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
public void disable_ongoingCallEnded_chipHidden() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -498,8 +502,11 @@
}
@Test
+ @DisableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
public void disable_hasOngoingCall_hidesNotifsWithoutAnimation() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
+ // Enable animations for testing so that we can verify we still aren't animating
+ fragment.enableAnimationsForTesting();
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
// Ongoing call started
@@ -512,6 +519,161 @@
}
@Test
+ @DisableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
+ public void screenSharingChipsDisabled_ignoresNewCallback() {
+ CollapsedStatusBarFragment fragment = resumeAndGetFragment();
+
+ // WHEN there *is* an ongoing call via old callback
+ when(mOngoingCallController.hasOngoingCall()).thenReturn(true);
+ fragment.disable(DEFAULT_DISPLAY, 0, 0, true);
+
+ // WHEN there's *no* ongoing activity via new callback
+ mCollapsedStatusBarViewBinder.getListener().onOngoingActivityStatusChanged(
+ /* hasOngoingActivity= */ false);
+
+ // THEN the old callback value is used, so the view is shown
+ assertEquals(View.VISIBLE,
+ mFragment.getView().findViewById(R.id.ongoing_activity_chip).getVisibility());
+
+ // WHEN there's *no* ongoing call via old callback
+ when(mOngoingCallController.hasOngoingCall()).thenReturn(false);
+ fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
+
+ // WHEN there *is* an ongoing activity via new callback
+ mCollapsedStatusBarViewBinder.getListener().onOngoingActivityStatusChanged(
+ /* hasOngoingActivity= */ true);
+
+ // THEN the old callback value is used, so the view is hidden
+ assertEquals(View.GONE,
+ mFragment.getView().findViewById(R.id.ongoing_activity_chip).getVisibility());
+ }
+
+ @Test
+ @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
+ public void noOngoingActivity_chipHidden() {
+ resumeAndGetFragment();
+
+ // TODO(b/332662551): We *should* be able to just set a value on
+ // mCollapsedStatusBarViewModel.getOngoingActivityChip() instead of manually invoking the
+ // listener, but I'm unable to get the fragment to get attached so that the binder starts
+ // listening to flows.
+ mCollapsedStatusBarViewBinder.getListener().onOngoingActivityStatusChanged(
+ /* hasOngoingActivity= */ false);
+
+ assertEquals(View.GONE,
+ mFragment.getView().findViewById(R.id.ongoing_activity_chip).getVisibility());
+ }
+
+ @Test
+ @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
+ public void hasOngoingActivity_chipDisplayedAndNotificationIconsHidden() {
+ resumeAndGetFragment();
+
+ mCollapsedStatusBarViewBinder.getListener().onOngoingActivityStatusChanged(
+ /* hasOngoingActivity= */ true);
+
+ assertEquals(View.VISIBLE,
+ mFragment.getView().findViewById(R.id.ongoing_activity_chip).getVisibility());
+ assertEquals(View.INVISIBLE, getNotificationAreaView().getVisibility());
+ }
+
+ @Test
+ @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
+ public void hasOngoingActivityButNotificationIconsDisabled_chipHidden() {
+ CollapsedStatusBarFragment fragment = resumeAndGetFragment();
+
+ mCollapsedStatusBarViewBinder.getListener().onOngoingActivityStatusChanged(
+ /* hasOngoingActivity= */ true);
+
+ fragment.disable(DEFAULT_DISPLAY,
+ StatusBarManager.DISABLE_NOTIFICATION_ICONS, 0, false);
+
+ assertEquals(View.GONE,
+ mFragment.getView().findViewById(R.id.ongoing_activity_chip).getVisibility());
+ }
+
+ @Test
+ @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
+ public void hasOngoingActivityButAlsoHun_chipHidden() {
+ CollapsedStatusBarFragment fragment = resumeAndGetFragment();
+
+ mCollapsedStatusBarViewBinder.getListener().onOngoingActivityStatusChanged(
+ /* hasOngoingActivity= */ true);
+ when(mHeadsUpAppearanceController.shouldBeVisible()).thenReturn(true);
+
+ fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
+
+ assertEquals(View.GONE,
+ mFragment.getView().findViewById(R.id.ongoing_activity_chip).getVisibility());
+ }
+
+ @Test
+ @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
+ public void ongoingActivityEnded_chipHidden() {
+ resumeAndGetFragment();
+
+ // Ongoing activity started
+ mCollapsedStatusBarViewBinder.getListener().onOngoingActivityStatusChanged(
+ /* hasOngoingActivity= */ true);
+
+ assertEquals(View.VISIBLE,
+ mFragment.getView().findViewById(R.id.ongoing_activity_chip).getVisibility());
+
+ // Ongoing activity ended
+ mCollapsedStatusBarViewBinder.getListener().onOngoingActivityStatusChanged(
+ /* hasOngoingActivity= */ false);
+
+ assertEquals(View.GONE,
+ mFragment.getView().findViewById(R.id.ongoing_activity_chip).getVisibility());
+ }
+
+ @Test
+ @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
+ public void hasOngoingActivity_hidesNotifsWithoutAnimation() {
+ CollapsedStatusBarFragment fragment = resumeAndGetFragment();
+ // Enable animations for testing so that we can verify we still aren't animating
+ fragment.enableAnimationsForTesting();
+
+ // Ongoing call started
+ mCollapsedStatusBarViewBinder.getListener().onOngoingActivityStatusChanged(
+ /* hasOngoingActivity= */ true);
+
+ // Notification area is hidden without delay
+ assertEquals(0f, getNotificationAreaView().getAlpha(), 0.01);
+ assertEquals(View.INVISIBLE, getNotificationAreaView().getVisibility());
+ }
+
+ @Test
+ @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
+ public void screenSharingChipsEnabled_ignoresOngoingCallController() {
+ CollapsedStatusBarFragment fragment = resumeAndGetFragment();
+
+ // WHEN there *is* an ongoing call via old callback
+ when(mOngoingCallController.hasOngoingCall()).thenReturn(true);
+ fragment.disable(DEFAULT_DISPLAY, 0, 0, true);
+
+ // WHEN there's *no* ongoing activity via new callback
+ mCollapsedStatusBarViewBinder.getListener().onOngoingActivityStatusChanged(
+ /* hasOngoingActivity= */ false);
+
+ // THEN the new callback value is used, so the view is hidden
+ assertEquals(View.GONE,
+ mFragment.getView().findViewById(R.id.ongoing_activity_chip).getVisibility());
+
+ // WHEN there's *no* ongoing call via old callback
+ when(mOngoingCallController.hasOngoingCall()).thenReturn(false);
+ fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
+
+ // WHEN there *is* an ongoing activity via new callback
+ mCollapsedStatusBarViewBinder.getListener().onOngoingActivityStatusChanged(
+ /* hasOngoingActivity= */ true);
+
+ // THEN the new callback value is used, so the view is shown
+ assertEquals(View.VISIBLE,
+ mFragment.getView().findViewById(R.id.ongoing_activity_chip).getVisibility());
+ }
+
+ @Test
public void disable_isDozing_clockAndSystemInfoVisible() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
when(mStatusBarStateController.isDozing()).thenReturn(true);
@@ -670,7 +832,6 @@
MockitoAnnotations.initMocks(this);
setUpDaggerComponent();
mOngoingCallController = mock(OngoingCallController.class);
- mOngoingActivityChipsViewModel = mKosmos.getOngoingActivityChipsViewModel();
mAnimationScheduler = mock(SystemStatusAnimationScheduler.class);
mLocationPublisher = mock(StatusBarLocationPublisher.class);
mStatusBarIconController = mock(StatusBarIconController.class);
@@ -691,7 +852,6 @@
return new CollapsedStatusBarFragment(
mStatusBarFragmentComponentFactory,
mOngoingCallController,
- mOngoingActivityChipsViewModel,
mAnimationScheduler,
mLocationPublisher,
mMockNotificationAreaController,
@@ -773,7 +933,9 @@
private CollapsedStatusBarFragment resumeAndGetFragment() {
mFragments.dispatchResume();
processAllMessages();
- return (CollapsedStatusBarFragment) mFragment;
+ CollapsedStatusBarFragment fragment = (CollapsedStatusBarFragment) mFragment;
+ fragment.disableAnimationsForTesting();
+ return fragment;
}
private View getUserChipView() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/StatusBarVisibilityModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/StatusBarVisibilityModelTest.kt
index 8e789cb..022b5d2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/StatusBarVisibilityModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/StatusBarVisibilityModelTest.kt
@@ -36,7 +36,7 @@
StatusBarVisibilityModel(
showClock = true,
showNotificationIcons = true,
- showOngoingCallChip = true,
+ showOngoingActivityChip = true,
showSystemInfo = true,
)
@@ -72,17 +72,17 @@
}
@Test
- fun createModelFromFlags_ongoingCallChipNotDisabled_showOngoingCallChipTrue() {
+ fun createModelFromFlags_ongoingCallChipNotDisabled_showOngoingActivityChipTrue() {
val result = createModelFromFlags(disabled1 = 0, disabled2 = 0)
- assertThat(result.showOngoingCallChip).isTrue()
+ assertThat(result.showOngoingActivityChip).isTrue()
}
@Test
- fun createModelFromFlags_ongoingCallChipDisabled_showOngoingCallChipFalse() {
+ fun createModelFromFlags_ongoingCallChipDisabled_showOngoingActivityChipFalse() {
val result = createModelFromFlags(disabled1 = DISABLE_ONGOING_CALL_CHIP, disabled2 = 0)
- assertThat(result.showOngoingCallChip).isFalse()
+ assertThat(result.showOngoingActivityChip).isFalse()
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt
index 606feab..c9fe449 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt
@@ -32,6 +32,14 @@
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.kosmos.testScope
import com.android.systemui.log.assertLogsWtf
+import com.android.systemui.mediaprojection.data.model.MediaProjectionState
+import com.android.systemui.mediaprojection.data.repository.fakeMediaProjectionRepository
+import com.android.systemui.screenrecord.data.model.ScreenRecordModel
+import com.android.systemui.screenrecord.data.repository.screenRecordRepository
+import com.android.systemui.statusbar.chips.domain.model.OngoingActivityChipModel
+import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModelTest.Companion.assertIsMediaProjectionChip
+import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModelTest.Companion.assertIsScreenRecordChip
+import com.android.systemui.statusbar.chips.ui.viewmodel.ongoingActivityChipsViewModel
import com.android.systemui.statusbar.data.model.StatusBarMode
import com.android.systemui.statusbar.data.repository.FakeStatusBarModeRepository.Companion.DISPLAY_ID
import com.android.systemui.statusbar.data.repository.fakeStatusBarModeRepository
@@ -65,6 +73,7 @@
kosmos.lightsOutInteractor,
kosmos.activeNotificationsInteractor,
kosmos.keyguardTransitionInteractor,
+ kosmos.ongoingActivityChipsViewModel,
kosmos.applicationCoroutineScope,
)
@@ -382,6 +391,25 @@
}
}
+ @Test
+ fun ongoingActivityChip_matchesViewModel() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.ongoingActivityChip)
+
+ kosmos.screenRecordRepository.screenRecordState.value = ScreenRecordModel.Recording
+
+ assertIsScreenRecordChip(latest)
+
+ kosmos.screenRecordRepository.screenRecordState.value = ScreenRecordModel.DoingNothing
+
+ assertThat(latest).isEqualTo(OngoingActivityChipModel.Hidden)
+
+ kosmos.fakeMediaProjectionRepository.mediaProjectionState.value =
+ MediaProjectionState.EntireScreen
+
+ assertIsMediaProjectionChip(latest)
+ }
+
private fun activeNotificationsStore(notifications: List<ActiveNotificationModel>) =
ActiveNotificationsStore.Builder()
.apply { notifications.forEach(::addIndividualNotif) }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewModel.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewModel.kt
index bc50f79..c3c9907 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewModel.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewModel.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.pipeline.shared.ui.viewmodel
+import com.android.systemui.statusbar.chips.domain.model.OngoingActivityChipModel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
@@ -27,6 +28,9 @@
override val transitionFromLockscreenToDreamStartedEvent = MutableSharedFlow<Unit>()
+ override val ongoingActivityChip: MutableStateFlow<OngoingActivityChipModel> =
+ MutableStateFlow(OngoingActivityChipModel.Hidden)
+
override fun areNotificationsLightsOut(displayId: Int): Flow<Boolean> = areNotificationLightsOut
fun setNotificationLightsOut(lightsOut: Boolean) {
diff --git a/packages/SystemUI/tests/utils/src/android/graphics/drawable/TestStubDrawable.kt b/packages/SystemUI/tests/utils/src/android/graphics/drawable/TestStubDrawable.kt
index 1a9f4b4..430fb59 100644
--- a/packages/SystemUI/tests/utils/src/android/graphics/drawable/TestStubDrawable.kt
+++ b/packages/SystemUI/tests/utils/src/android/graphics/drawable/TestStubDrawable.kt
@@ -27,8 +27,11 @@
class TestStubDrawable(private val name: String? = null) : Drawable() {
override fun draw(canvas: Canvas) = Unit
+
override fun setAlpha(alpha: Int) = Unit
+
override fun setColorFilter(colorFilter: ColorFilter?) = Unit
+
override fun getOpacity(): Int = PixelFormat.UNKNOWN
override fun toString(): String {
@@ -38,6 +41,10 @@
override fun getConstantState(): ConstantState =
TestStubConstantState(this, changingConfigurations)
+ override fun equals(other: Any?): Boolean {
+ return (other as? TestStubDrawable ?: return false).name == name
+ }
+
private class TestStubConstantState(
private val drawable: Drawable,
private val changingConfigurations: Int,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiBaseFragmentTest.java b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiBaseFragmentTest.java
index e470406..a581993 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiBaseFragmentTest.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiBaseFragmentTest.java
@@ -19,6 +19,7 @@
import android.app.Fragment;
import android.app.Instrumentation;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.testing.BaseFragmentTest;
import android.testing.DexmakerShareClassLoaderRule;
@@ -31,6 +32,7 @@
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
+import org.junit.ClassRule;
import org.junit.Rule;
import org.mockito.Mockito;
@@ -43,6 +45,12 @@
@Rule
public final SysuiLeakCheck mLeakCheck = new SysuiLeakCheck();
+ @ClassRule
+ public static final SetFlagsRule.ClassRule mSetFlagsClassRule =
+ new SetFlagsRule.ClassRule(
+ com.android.systemui.Flags.class);
+ @Rule public final SetFlagsRule mSetFlagsRule = mSetFlagsClassRule.createSetFlagsRule();
+
@Rule
public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule =
new DexmakerShareClassLoaderRule();
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeDisplayStateRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeDisplayStateRepository.kt
index 9765d53..53285eb 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeDisplayStateRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeDisplayStateRepository.kt
@@ -23,7 +23,6 @@
import dagger.Binds
import dagger.Module
import javax.inject.Inject
-import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
@@ -40,7 +39,7 @@
override val currentDisplaySize: StateFlow<Size> = _currentDisplaySize.asStateFlow()
private val _isLargeScreen = MutableStateFlow<Boolean>(false)
- override val isLargeScreen: Flow<Boolean> = _isLargeScreen.asStateFlow()
+ override val isLargeScreen: StateFlow<Boolean> = _isLargeScreen.asStateFlow()
override val isReverseDefaultRotation = false
@@ -55,6 +54,10 @@
fun setCurrentDisplaySize(size: Size) {
_currentDisplaySize.value = size
}
+
+ fun setIsLargeScreen(isLargeScreen: Boolean) {
+ _isLargeScreen.value = isLargeScreen
+ }
}
@Module
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorKosmos.kt
index 7f9a71c..56297f0 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorKosmos.kt
@@ -25,6 +25,7 @@
val Kosmos.promptSelectorInteractor by Fixture {
PromptSelectorInteractorImpl(
fingerprintPropertyRepository = fingerprintPropertyRepository,
+ displayStateInteractor = displayStateInteractor,
promptRepository = promptRepository,
lockPatternUtils = lockPatternUtils
)
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 a6b40df..fb12897 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.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.keyguardSmartspaceSection: SmartspaceSection by
+ Kosmos.Fixture { mock<SmartspaceSection>() }
+
val Kosmos.defaultKeyguardBlueprint by
Kosmos.Fixture {
DefaultKeyguardBlueprint(
@@ -57,7 +62,7 @@
aodBurnInSection = mock(),
communalTutorialIndicatorSection = mock(),
clockSection = keyguardClockSection,
- smartspaceSection = mock(),
+ smartspaceSection = keyguardSmartspaceSection,
keyguardSliceViewSection = mock(),
udfpsAccessibilityOverlaySection = mock(),
accessibilityActionsSection = mock(),
@@ -80,7 +85,7 @@
aodBurnInSection = mock(),
communalTutorialIndicatorSection = mock(),
clockSection = keyguardClockSection,
- smartspaceSection = mock(),
+ smartspaceSection = keyguardSmartspaceSection,
mediaSection = mock(),
accessibilityActionsSection = mock(),
)
@@ -88,13 +93,15 @@
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 5256ce4..4328ca1 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 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 @@
clockInteractor = keyguardClockInteractor,
configurationInteractor = configurationInteractor,
fingerprintPropertyInteractor = fingerprintPropertyInteractor,
+ clockSection = keyguardClockSection,
+ smartspaceSection = keyguardSmartspaceSection,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinderKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinderKosmos.kt
deleted file mode 100644
index 24d2c2f..0000000
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinderKosmos.kt
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.keyguard.ui.binder
-
-import android.os.fakeExecutorHandler
-import com.android.systemui.kosmos.Kosmos
-
-val Kosmos.keyguardBlueprintViewBinder by
- Kosmos.Fixture { KeyguardBlueprintViewBinder(fakeExecutorHandler) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModelKosmos.kt
index 63b87c0..0c538ff 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModelKosmos.kt
@@ -16,8 +16,14 @@
package com.android.systemui.keyguard.ui.viewmodel
+import android.os.fakeExecutorHandler
import com.android.systemui.keyguard.domain.interactor.keyguardBlueprintInteractor
import com.android.systemui.kosmos.Kosmos
val Kosmos.keyguardBlueprintViewModel by
- Kosmos.Fixture { KeyguardBlueprintViewModel(keyguardBlueprintInteractor) }
+ Kosmos.Fixture {
+ KeyguardBlueprintViewModel(
+ fakeExecutorHandler,
+ keyguardBlueprintInteractor,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt
index f856d27..2567ffe 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt
@@ -32,7 +32,7 @@
val Kosmos.keyguardRootViewModel by Fixture {
KeyguardRootViewModel(
- scope = applicationCoroutineScope,
+ applicationScope = applicationCoroutineScope,
deviceEntryInteractor = deviceEntryInteractor,
dozeParameters = dozeParameters,
keyguardInteractor = keyguardInteractor,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/data/repository/FakeMediaProjectionRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/data/repository/FakeMediaProjectionRepository.kt
new file mode 100644
index 0000000..c4365c9
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/data/repository/FakeMediaProjectionRepository.kt
@@ -0,0 +1,28 @@
+/*
+ * 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.mediaprojection.data.repository
+
+import android.app.ActivityManager
+import com.android.systemui.mediaprojection.data.model.MediaProjectionState
+import kotlinx.coroutines.flow.MutableStateFlow
+
+class FakeMediaProjectionRepository : MediaProjectionRepository {
+ override suspend fun switchProjectedTask(task: ActivityManager.RunningTaskInfo) {}
+
+ override val mediaProjectionState: MutableStateFlow<MediaProjectionState> =
+ MutableStateFlow(MediaProjectionState.NotProjecting)
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionRepositoryKosmos.kt
new file mode 100644
index 0000000..f253e94
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionRepositoryKosmos.kt
@@ -0,0 +1,39 @@
+/*
+ * 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.mediaprojection.data.repository
+
+import android.os.Handler
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.mediaprojection.taskswitcher.activityTaskManagerTasksRepository
+import com.android.systemui.mediaprojection.taskswitcher.fakeMediaProjectionManager
+
+val Kosmos.fakeMediaProjectionRepository: FakeMediaProjectionRepository by
+ Kosmos.Fixture { FakeMediaProjectionRepository() }
+
+val Kosmos.realMediaProjectionRepository by
+ Kosmos.Fixture {
+ MediaProjectionManagerRepository(
+ mediaProjectionManager = fakeMediaProjectionManager.mediaProjectionManager,
+ handler = Handler.getMain(),
+ applicationScope = applicationCoroutineScope,
+ tasksRepository = activityTaskManagerTasksRepository,
+ backgroundDispatcher = testDispatcher,
+ mediaProjectionServiceHelper = fakeMediaProjectionManager.helper,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/taskswitcher/TaskSwitcherKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/taskswitcher/TaskSwitcherKosmos.kt
index 5b1f95a..5acadd7 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/taskswitcher/TaskSwitcherKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/taskswitcher/TaskSwitcherKosmos.kt
@@ -16,11 +16,10 @@
package com.android.systemui.mediaprojection.taskswitcher
-import android.os.Handler
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.kosmos.testDispatcher
-import com.android.systemui.mediaprojection.data.repository.MediaProjectionManagerRepository
+import com.android.systemui.mediaprojection.data.repository.realMediaProjectionRepository
import com.android.systemui.mediaprojection.taskswitcher.data.repository.ActivityTaskManagerTasksRepository
import com.android.systemui.mediaprojection.taskswitcher.domain.interactor.TaskSwitchInteractor
import com.android.systemui.mediaprojection.taskswitcher.ui.viewmodel.TaskSwitcherNotificationViewModel
@@ -40,21 +39,9 @@
)
}
-val Kosmos.mediaProjectionManagerRepository by
- Kosmos.Fixture {
- MediaProjectionManagerRepository(
- mediaProjectionManager = fakeMediaProjectionManager.mediaProjectionManager,
- handler = Handler.getMain(),
- applicationScope = applicationCoroutineScope,
- tasksRepository = activityTaskManagerTasksRepository,
- backgroundDispatcher = testDispatcher,
- mediaProjectionServiceHelper = fakeMediaProjectionManager.helper,
- )
- }
-
val Kosmos.taskSwitcherInteractor by
Kosmos.Fixture {
- TaskSwitchInteractor(mediaProjectionManagerRepository, activityTaskManagerTasksRepository)
+ TaskSwitchInteractor(realMediaProjectionRepository, activityTaskManagerTasksRepository)
}
val Kosmos.taskSwitcherViewModel by
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/data/repository/QSPreferencesRepositoryKosmos.kt
similarity index 70%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/IconLabelVisibilityRepositoryKosmos.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/QSPreferencesRepositoryKosmos.kt
index 277dbb7..39ae5eb 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/data/repository/QSPreferencesRepositoryKosmos.kt
@@ -17,5 +17,9 @@
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.iconLabelVisibilityRepository by Kosmos.Fixture { IconLabelVisibilityRepository() }
+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 7b9e4a1..954084b 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 @@
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
similarity index 72%
rename from packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/IconLabelVisibilityRepositoryKosmos.kt
rename to packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/QSPreferencesInteractorKosmos.kt
index 277dbb7..eb83e32 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/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelKosmos.kt
index 9e02df9..88bde2e 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelKosmos.kt
@@ -19,7 +19,9 @@
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.kosmos.testScope
+import com.android.systemui.mediaprojection.data.repository.fakeMediaProjectionRepository
import com.android.systemui.screenrecord.data.repository.screenRecordRepository
+import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.MediaProjectionChipInteractor
import com.android.systemui.statusbar.chips.screenrecord.domain.interactor.ScreenRecordChipInteractor
import com.android.systemui.util.time.fakeSystemClock
@@ -32,6 +34,15 @@
)
}
+val Kosmos.mediaProjectionChipInteractor: MediaProjectionChipInteractor by
+ Kosmos.Fixture {
+ MediaProjectionChipInteractor(
+ scope = applicationCoroutineScope,
+ mediaProjectionRepository = fakeMediaProjectionRepository,
+ systemClock = fakeSystemClock,
+ )
+ }
+
val Kosmos.callChipInteractor: FakeCallChipInteractor by Kosmos.Fixture { FakeCallChipInteractor() }
val Kosmos.ongoingActivityChipsViewModel: OngoingActivityChipsViewModel by
@@ -39,6 +50,7 @@
OngoingActivityChipsViewModel(
testScope.backgroundScope,
screenRecordChipInteractor = screenRecordChipInteractor,
+ mediaProjectionChipInteractor = mediaProjectionChipInteractor,
callChipInteractor = callChipInteractor,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/TestAudioDevicesFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/TestAudioDevicesFactory.kt
new file mode 100644
index 0000000..3ac7129
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/TestAudioDevicesFactory.kt
@@ -0,0 +1,58 @@
+/*
+ * 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.volume.data.repository
+
+import android.annotation.SuppressLint
+import android.media.AudioDeviceInfo
+import android.media.AudioDevicePort
+
+@SuppressLint("VisibleForTests")
+object TestAudioDevicesFactory {
+
+ fun builtInDevice(deviceName: String = "built_in"): AudioDeviceInfo {
+ return AudioDeviceInfo(
+ AudioDevicePort.createForTesting(
+ AudioDeviceInfo.TYPE_BUILTIN_SPEAKER,
+ deviceName,
+ "",
+ )
+ )
+ }
+
+ fun wiredDevice(deviceName: String = "wired"): AudioDeviceInfo {
+ return AudioDeviceInfo(
+ AudioDevicePort.createForTesting(
+ AudioDeviceInfo.TYPE_WIRED_HEADPHONES,
+ deviceName,
+ "",
+ )
+ )
+ }
+
+ fun bluetoothDevice(
+ deviceName: String = "bt",
+ deviceAddress: String = "test_address",
+ ): AudioDeviceInfo {
+ return AudioDeviceInfo(
+ AudioDevicePort.createForTesting(
+ AudioDeviceInfo.TYPE_BLE_HEADSET,
+ deviceName,
+ deviceAddress,
+ )
+ )
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/domain/interactor/AudioOutputInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/domain/interactor/AudioOutputInteractorKosmos.kt
index 63c3ee5..3f51a79 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/domain/interactor/AudioOutputInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/domain/interactor/AudioOutputInteractorKosmos.kt
@@ -22,7 +22,6 @@
import com.android.systemui.kosmos.testScope
import com.android.systemui.volume.data.repository.audioRepository
import com.android.systemui.volume.data.repository.audioSharingRepository
-import com.android.systemui.volume.localMediaRepositoryFactory
import com.android.systemui.volume.mediaOutputInteractor
val Kosmos.audioOutputInteractor by
@@ -36,7 +35,6 @@
bluetoothAdapter,
deviceIconInteractor,
mediaOutputInteractor,
- localMediaRepositoryFactory,
audioSharingRepository,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/captioning/CaptioningModuleKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/captioning/CaptioningModuleKosmos.kt
new file mode 100644
index 0000000..e7162d2
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/captioning/CaptioningModuleKosmos.kt
@@ -0,0 +1,41 @@
+/*
+ * 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.volume.panel.component.captioning
+
+import com.android.internal.logging.uiEventLogger
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.view.accessibility.data.repository.captioningInteractor
+import com.android.systemui.volume.panel.component.button.ui.composable.ToggleButtonComponent
+import com.android.systemui.volume.panel.component.captioning.domain.CaptioningAvailabilityCriteria
+import com.android.systemui.volume.panel.component.captioning.ui.viewmodel.captioningViewModel
+
+val Kosmos.captioningComponent by
+ Kosmos.Fixture {
+ ToggleButtonComponent(
+ captioningViewModel.buttonViewModel,
+ captioningViewModel::setIsSystemAudioCaptioningEnabled,
+ )
+ }
+val Kosmos.captioningAvailabilityCriteria by
+ Kosmos.Fixture {
+ CaptioningAvailabilityCriteria(
+ captioningInteractor,
+ testScope.backgroundScope,
+ uiEventLogger,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/captioning/ui/viewmodel/CaptioningViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/captioning/ui/viewmodel/CaptioningViewModelKosmos.kt
new file mode 100644
index 0000000..0edd9e0
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/captioning/ui/viewmodel/CaptioningViewModelKosmos.kt
@@ -0,0 +1,33 @@
+/*
+ * 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.volume.panel.component.captioning.ui.viewmodel
+
+import android.content.applicationContext
+import com.android.internal.logging.uiEventLogger
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.view.accessibility.data.repository.captioningInteractor
+
+val Kosmos.captioningViewModel by
+ Kosmos.Fixture {
+ CaptioningViewModel(
+ applicationContext,
+ captioningInteractor,
+ testScope.backgroundScope,
+ uiEventLogger,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/TestMediaDevicesFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/TestMediaDevicesFactory.kt
index 4029609..141f242 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/TestMediaDevicesFactory.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/TestMediaDevicesFactory.kt
@@ -18,6 +18,7 @@
import android.annotation.SuppressLint
import android.bluetooth.BluetoothDevice
+import android.graphics.drawable.Drawable
import android.graphics.drawable.TestStubDrawable
import com.android.settingslib.bluetooth.CachedBluetoothDevice
import com.android.settingslib.media.BluetoothMediaDevice
@@ -29,29 +30,44 @@
@SuppressLint("StaticFieldLeak") // These are mocks
object TestMediaDevicesFactory {
- fun builtInMediaDevice(): MediaDevice = mock {
- whenever(name).thenReturn("built_in_media")
- whenever(icon).thenReturn(TestStubDrawable())
+ fun builtInMediaDevice(
+ deviceName: String = "built_in_media",
+ deviceIcon: Drawable? = TestStubDrawable(),
+ ): MediaDevice = mock {
+ whenever(name).thenReturn(deviceName)
+ whenever(icon).thenReturn(deviceIcon)
}
- fun wiredMediaDevice(): MediaDevice =
+ fun wiredMediaDevice(
+ deviceName: String = "wired_media",
+ deviceIcon: Drawable? = TestStubDrawable(),
+ ): MediaDevice =
mock<PhoneMediaDevice> {
whenever(deviceType)
.thenReturn(MediaDevice.MediaDeviceType.TYPE_3POINT5_MM_AUDIO_DEVICE)
- whenever(name).thenReturn("wired_media")
- whenever(icon).thenReturn(TestStubDrawable())
+ whenever(name).thenReturn(deviceName)
+ whenever(icon).thenReturn(deviceIcon)
}
- fun bluetoothMediaDevice(): MediaDevice {
- val bluetoothDevice = mock<BluetoothDevice>()
+ fun bluetoothMediaDevice(
+ deviceName: String = "bt_media",
+ deviceIcon: Drawable? = TestStubDrawable(),
+ deviceAddress: String = "bt_media_device",
+ ): BluetoothMediaDevice {
+ val bluetoothDevice =
+ mock<BluetoothDevice> {
+ whenever(name).thenReturn(deviceName)
+ whenever(address).thenReturn(deviceAddress)
+ }
val cachedBluetoothDevice: CachedBluetoothDevice = mock {
whenever(isHearingAidDevice).thenReturn(true)
- whenever(address).thenReturn("bt_media_device")
+ whenever(address).thenReturn(deviceAddress)
whenever(device).thenReturn(bluetoothDevice)
+ whenever(name).thenReturn(deviceName)
}
return mock<BluetoothMediaDevice> {
- whenever(name).thenReturn("bt_media")
- whenever(icon).thenReturn(TestStubDrawable())
+ whenever(name).thenReturn(deviceName)
+ whenever(icon).thenReturn(deviceIcon)
whenever(cachedDevice).thenReturn(cachedBluetoothDevice)
}
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/spatial/SpatialAudioModuleKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/spatial/SpatialAudioModuleKosmos.kt
new file mode 100644
index 0000000..ea5d70d
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/spatial/SpatialAudioModuleKosmos.kt
@@ -0,0 +1,28 @@
+/*
+ * 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.volume.panel.component.spatial
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.volume.panel.component.button.ui.composable.ButtonComponent
+import com.android.systemui.volume.panel.component.spatial.domain.SpatialAudioAvailabilityCriteria
+import com.android.systemui.volume.panel.component.spatial.domain.interactor.spatialAudioComponentInteractor
+import com.android.systemui.volume.panel.component.spatial.ui.viewmodel.spatialAudioViewModel
+
+val Kosmos.spatialAudioComponent by
+ Kosmos.Fixture { ButtonComponent(spatialAudioViewModel.spatialAudioButton) { _, _ -> } }
+val Kosmos.spatialAudioAvailabilityCriteria by
+ Kosmos.Fixture { SpatialAudioAvailabilityCriteria(spatialAudioComponentInteractor) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractorKosmos.kt
new file mode 100644
index 0000000..95a7b9b
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractorKosmos.kt
@@ -0,0 +1,31 @@
+/*
+ * 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.volume.panel.component.spatial.domain.interactor
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.media.spatializerInteractor
+import com.android.systemui.volume.domain.interactor.audioOutputInteractor
+
+val Kosmos.spatialAudioComponentInteractor by
+ Kosmos.Fixture {
+ SpatialAudioComponentInteractor(
+ audioOutputInteractor,
+ spatializerInteractor,
+ testScope.backgroundScope,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/spatial/ui/viewmodel/SpatialAudioViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/spatial/ui/viewmodel/SpatialAudioViewModelKosmos.kt
new file mode 100644
index 0000000..1b8a3fc
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/spatial/ui/viewmodel/SpatialAudioViewModelKosmos.kt
@@ -0,0 +1,35 @@
+/*
+ * 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.volume.panel.component.spatial.ui.viewmodel
+
+import android.content.applicationContext
+import com.android.internal.logging.uiEventLogger
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.volume.panel.component.spatial.domain.interactor.spatialAudioComponentInteractor
+import com.android.systemui.volume.panel.component.spatial.spatialAudioAvailabilityCriteria
+
+val Kosmos.spatialAudioViewModel by
+ Kosmos.Fixture {
+ SpatialAudioViewModel(
+ applicationContext,
+ testScope.backgroundScope,
+ spatialAudioAvailabilityCriteria,
+ spatialAudioComponentInteractor,
+ uiEventLogger,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/domain/interactor/ComponentsInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/domain/interactor/ComponentsInteractorKosmos.kt
index 8862942..a18f498 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/domain/interactor/ComponentsInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/domain/interactor/ComponentsInteractorKosmos.kt
@@ -19,8 +19,10 @@
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.testScope
import com.android.systemui.volume.panel.component.bottombar.ui.bottomBarAvailabilityCriteria
+import com.android.systemui.volume.panel.component.captioning.captioningAvailabilityCriteria
import com.android.systemui.volume.panel.component.mediaoutput.mediaOutputAvailabilityCriteria
import com.android.systemui.volume.panel.component.shared.model.VolumePanelComponents
+import com.android.systemui.volume.panel.component.spatial.spatialAudioAvailabilityCriteria
import com.android.systemui.volume.panel.component.volume.volumeSlidersAvailabilityCriteria
import com.android.systemui.volume.panel.domain.ComponentAvailabilityCriteria
import com.android.systemui.volume.panel.domain.defaultCriteria
@@ -36,6 +38,8 @@
mapOf(
VolumePanelComponents.MEDIA_OUTPUT to Provider { mediaOutputAvailabilityCriteria },
VolumePanelComponents.VOLUME_SLIDERS to Provider { volumeSlidersAvailabilityCriteria },
+ VolumePanelComponents.CAPTIONING to Provider { captioningAvailabilityCriteria },
+ VolumePanelComponents.SPATIAL_AUDIO to Provider { spatialAudioAvailabilityCriteria },
VolumePanelComponents.BOTTOM_BAR to Provider { bottomBarAvailabilityCriteria },
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/ui/composable/ComponentsFactoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/ui/composable/ComponentsFactoryKosmos.kt
index bacf22c..6bea416 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/ui/composable/ComponentsFactoryKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/ui/composable/ComponentsFactoryKosmos.kt
@@ -18,8 +18,10 @@
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.volume.panel.component.bottombar.ui.bottomBarComponent
+import com.android.systemui.volume.panel.component.captioning.captioningComponent
import com.android.systemui.volume.panel.component.mediaoutput.mediaOutputComponent
import com.android.systemui.volume.panel.component.shared.model.VolumePanelComponents
+import com.android.systemui.volume.panel.component.spatial.spatialAudioComponent
import com.android.systemui.volume.panel.component.volume.volumeSlidersComponent
import com.android.systemui.volume.panel.shared.model.VolumePanelComponentKey
import com.android.systemui.volume.panel.shared.model.VolumePanelUiComponent
@@ -30,9 +32,11 @@
var Kosmos.prodComponentByKey: Map<VolumePanelComponentKey, Provider<VolumePanelUiComponent>> by
Kosmos.Fixture {
mapOf(
- VolumePanelComponents.BOTTOM_BAR to Provider { bottomBarComponent },
VolumePanelComponents.MEDIA_OUTPUT to Provider { mediaOutputComponent },
VolumePanelComponents.VOLUME_SLIDERS to Provider { volumeSlidersComponent },
+ VolumePanelComponents.CAPTIONING to Provider { captioningComponent },
+ VolumePanelComponents.SPATIAL_AUDIO to Provider { spatialAudioComponent },
+ VolumePanelComponents.BOTTOM_BAR to Provider { bottomBarComponent },
)
}
var Kosmos.enabledComponents: Collection<VolumePanelComponentKey> by
diff --git a/services/accessibility/accessibility.aconfig b/services/accessibility/accessibility.aconfig
index 1c57dd3..9353150 100644
--- a/services/accessibility/accessibility.aconfig
+++ b/services/accessibility/accessibility.aconfig
@@ -220,3 +220,13 @@
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 053a1a7..20b727c 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 @@
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 @@
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 dc1cfb9..ddccb37 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 @@
}
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 30e4a3e..0d0c21d 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.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 @@
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 d09d7e6..3fbd856 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 @@
* 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 29e8095..757abd9 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 @@
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 @@
/**
* 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 @@
"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 8c1116b..6f0baef 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 @@
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 026d29c..00e049c 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 boolean isPermissionTransferUserConsented(int associationId) {
mAssociationStore.getAssociationWithCallerChecks(associationId);
-
PermissionSyncRequest request = getPermissionSyncRequest(associationId);
if (request == null) {
return false;
@@ -147,12 +146,12 @@
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 @@
* 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 @@
* 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 @@
*/
@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 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/utils/PermissionsUtils.java b/services/companion/java/com/android/server/companion/utils/PermissionsUtils.java
index f397814..796d285 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 @@
}
/**
- * 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 @@
}
/**
- * 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 @@
}
}
- /**
- * 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/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java
index a619257..966478e 100644
--- a/services/core/java/com/android/server/PackageWatchdog.java
+++ b/services/core/java/com/android/server/PackageWatchdog.java
@@ -138,6 +138,12 @@
static final long DEFAULT_BOOT_LOOP_TRIGGER_WINDOW_MS = TimeUnit.MINUTES.toMillis(10);
+ // Time needed to apply mitigation
+ private static final String MITIGATION_WINDOW_MS =
+ "persist.device_config.configuration.mitigation_window_ms";
+ @VisibleForTesting
+ static final long DEFAULT_MITIGATION_WINDOW_MS = TimeUnit.SECONDS.toMillis(5);
+
// Threshold level at which or above user might experience significant disruption.
private static final String MAJOR_USER_IMPACT_LEVEL_THRESHOLD =
"persist.device_config.configuration.major_user_impact_level_threshold";
@@ -210,6 +216,9 @@
@GuardedBy("mLock")
private boolean mSyncRequired = false;
+ @GuardedBy("mLock")
+ private long mLastMitigation = -1000000;
+
@FunctionalInterface
@VisibleForTesting
interface SystemClock {
@@ -400,6 +409,16 @@
Slog.w(TAG, "Could not resolve a list of failing packages");
return;
}
+ synchronized (mLock) {
+ final long now = mSystemClock.uptimeMillis();
+ if (Flags.recoverabilityDetection()) {
+ if (now >= mLastMitigation
+ && (now - mLastMitigation) < getMitigationWindowMs()) {
+ Slog.i(TAG, "Skipping onPackageFailure mitigation");
+ return;
+ }
+ }
+ }
mLongTaskHandler.post(() -> {
synchronized (mLock) {
if (mAllObservers.isEmpty()) {
@@ -500,10 +519,17 @@
int currentObserverImpact,
int mitigationCount) {
if (currentObserverImpact < getUserImpactLevelLimit()) {
+ synchronized (mLock) {
+ mLastMitigation = mSystemClock.uptimeMillis();
+ }
currentObserverToNotify.execute(versionedPackage, failureReason, mitigationCount);
}
}
+ private long getMitigationWindowMs() {
+ return SystemProperties.getLong(MITIGATION_WINDOW_MS, DEFAULT_MITIGATION_WINDOW_MS);
+ }
+
/**
* Called when the system server boots. If the system server is detected to be in a boot loop,
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 4dd3a8f..b35959f 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -3980,7 +3980,7 @@
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 baa7f2f..cb0ad78 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -1013,7 +1013,7 @@
SystemServerAdapter.getDefaultAdapter(context),
SettingsAdapter.getDefaultAdapter(),
new AudioVolumeGroupHelper(),
- new DefaultAudioPolicyFacade(),
+ new DefaultAudioPolicyFacade(r -> r.run()),
null);
}
@@ -1901,7 +1901,6 @@
}
mSpatializerHelper.reset(/* featureEnabled */ mHasSpatializerEffect);
- mSoundDoseHelper.reset();
// Restore rotation information.
if (mMonitorRotation) {
@@ -1912,6 +1911,8 @@
// 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);
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index 07daecd..b1ea85c 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -94,14 +94,14 @@
private final Map<BluetoothDevice, AudioDeviceAttributes> mResolvedScoAudioDevices =
new HashMap<>();
- private @Nullable BluetoothHearingAid mHearingAid;
+ private @Nullable BluetoothHearingAid mHearingAid = null;
- private @Nullable BluetoothLeAudio mLeAudio;
+ private @Nullable BluetoothLeAudio mLeAudio = null;
private @Nullable BluetoothLeAudioCodecConfig mLeAudioCodecConfig;
// Reference to BluetoothA2dp to query for AbsoluteVolume.
- private @Nullable BluetoothA2dp mA2dp;
+ private @Nullable BluetoothA2dp mA2dp = null;
private @Nullable BluetoothCodecConfig mA2dpCodecConfig;
@@ -577,7 +577,11 @@
mHearingAid = null;
break;
case BluetoothProfile.LE_AUDIO:
+ if (mLeAudio != null && mLeAudioCallback != null) {
+ mLeAudio.unregisterCallback(mLeAudioCallback);
+ }
mLeAudio = null;
+ mLeAudioCallback = null;
mLeAudioCodecConfig = null;
break;
case BluetoothProfile.LE_AUDIO_BROADCAST:
@@ -596,8 +600,6 @@
// BluetoothLeAudio callback used to update the list of addresses in the same group as a
// connected LE Audio device
- MyLeAudioCallback mLeAudioCallback = null;
-
class MyLeAudioCallback implements BluetoothLeAudio.Callback {
@Override
public void onCodecConfigChanged(int groupId,
@@ -620,6 +622,8 @@
}
}
+ MyLeAudioCallback mLeAudioCallback = null;
+
// @GuardedBy("mDeviceBroker.mSetModeLock")
@GuardedBy("AudioDeviceBroker.this.mDeviceStateLock")
/*package*/ synchronized void onBtProfileConnected(int profile, BluetoothProfile proxy) {
@@ -635,18 +639,28 @@
onHeadsetProfileConnected((BluetoothHeadset) proxy);
return;
case BluetoothProfile.A2DP:
+ if (((BluetoothA2dp) proxy).equals(mA2dp)) {
+ return;
+ }
mA2dp = (BluetoothA2dp) proxy;
break;
case BluetoothProfile.HEARING_AID:
+ if (((BluetoothHearingAid) proxy).equals(mHearingAid)) {
+ return;
+ }
mHearingAid = (BluetoothHearingAid) proxy;
break;
case BluetoothProfile.LE_AUDIO:
- if (mLeAudio == null) {
- mLeAudioCallback = new MyLeAudioCallback();
- ((BluetoothLeAudio) proxy).registerCallback(
- mContext.getMainExecutor(), mLeAudioCallback);
+ if (((BluetoothLeAudio) proxy).equals(mLeAudio)) {
+ return;
+ }
+ if (mLeAudio != null && mLeAudioCallback != null) {
+ mLeAudio.unregisterCallback(mLeAudioCallback);
}
mLeAudio = (BluetoothLeAudio) proxy;
+ mLeAudioCallback = new MyLeAudioCallback();
+ mLeAudio.registerCallback(
+ mContext.getMainExecutor(), mLeAudioCallback);
break;
case BluetoothProfile.A2DP_SINK:
case BluetoothProfile.LE_AUDIO_BROADCAST:
diff --git a/services/core/java/com/android/server/audio/DefaultAudioPolicyFacade.java b/services/core/java/com/android/server/audio/DefaultAudioPolicyFacade.java
index 37b8126..75febbc 100644
--- a/services/core/java/com/android/server/audio/DefaultAudioPolicyFacade.java
+++ b/services/core/java/com/android/server/audio/DefaultAudioPolicyFacade.java
@@ -16,100 +16,43 @@
package com.android.server.audio;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.media.IAudioPolicyService;
-import android.media.permission.ClearCallingIdentityContext;
-import android.media.permission.SafeCloseable;
import android.os.IBinder;
import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.util.Log;
-import com.android.internal.annotations.GuardedBy;
+import java.util.concurrent.Executor;
+import java.util.function.Function;
/**
- * Default implementation of a facade to IAudioPolicyManager which fulfills AudioService
- * dependencies. This forwards calls as-is to IAudioPolicyManager.
- * Public methods throw IllegalStateException if AudioPolicy is not initialized/available
+ * Default implementation of a facade to IAudioPolicyService which fulfills AudioService
+ * dependencies. This forwards calls as-is to IAudioPolicyService.
*/
-public class DefaultAudioPolicyFacade implements AudioPolicyFacade, IBinder.DeathRecipient {
+public class DefaultAudioPolicyFacade implements AudioPolicyFacade {
- private static final String TAG = "DefaultAudioPolicyFacade";
private static final String AUDIO_POLICY_SERVICE_NAME = "media.audio_policy";
- private final Object mServiceLock = new Object();
- @GuardedBy("mServiceLock")
- private IAudioPolicyService mAudioPolicy;
+ private final ServiceHolder<IAudioPolicyService> mServiceHolder;
- public DefaultAudioPolicyFacade() {
- try {
- getAudioPolicyOrInit();
- } catch (IllegalStateException e) {
- // Log and suppress this exception, we may be able to connect later
- Log.e(TAG, "Failed to initialize APM connection", e);
- }
+ /**
+ * @param e - Executor for service start tasks
+ */
+ public DefaultAudioPolicyFacade(Executor e) {
+ mServiceHolder =
+ new ServiceHolder(
+ AUDIO_POLICY_SERVICE_NAME,
+ (Function<IBinder, IAudioPolicyService>)
+ IAudioPolicyService.Stub::asInterface,
+ e);
}
@Override
public boolean isHotwordStreamSupported(boolean lookbackAudio) {
- IAudioPolicyService ap = getAudioPolicyOrInit();
- try (SafeCloseable ignored = ClearCallingIdentityContext.create()) {
+ IAudioPolicyService ap = mServiceHolder.waitForService();
+ try {
return ap.isHotwordStreamSupported(lookbackAudio);
} catch (RemoteException e) {
- resetServiceConnection(ap.asBinder());
- throw new IllegalStateException(e);
- }
- }
-
- @Override
- public void binderDied() {
- Log.wtf(TAG, "Unexpected binderDied without IBinder object");
- }
-
- @Override
- public void binderDied(@NonNull IBinder who) {
- resetServiceConnection(who);
- }
-
- private void resetServiceConnection(@Nullable IBinder deadAudioPolicy) {
- synchronized (mServiceLock) {
- if (mAudioPolicy != null && mAudioPolicy.asBinder().equals(deadAudioPolicy)) {
- mAudioPolicy.asBinder().unlinkToDeath(this, 0);
- mAudioPolicy = null;
- }
- }
- }
-
- private @Nullable IAudioPolicyService getAudioPolicy() {
- synchronized (mServiceLock) {
- return mAudioPolicy;
- }
- }
-
- /*
- * Does not block.
- * @throws IllegalStateException for any failed connection
- */
- private @NonNull IAudioPolicyService getAudioPolicyOrInit() {
- synchronized (mServiceLock) {
- if (mAudioPolicy != null) {
- return mAudioPolicy;
- }
- // Do not block while attempting to connect to APM. Defer to caller.
- IAudioPolicyService ap = IAudioPolicyService.Stub.asInterface(
- ServiceManager.checkService(AUDIO_POLICY_SERVICE_NAME));
- if (ap == null) {
- throw new IllegalStateException(TAG + ": Unable to connect to AudioPolicy");
- }
- try {
- ap.asBinder().linkToDeath(this, 0);
- } catch (RemoteException e) {
- throw new IllegalStateException(
- TAG + ": Unable to link deathListener to AudioPolicy", e);
- }
- mAudioPolicy = ap;
- return mAudioPolicy;
+ mServiceHolder.attemptClear(ap.asBinder());
+ throw new IllegalStateException();
}
}
}
diff --git a/services/core/java/com/android/server/audio/ServiceHolder.java b/services/core/java/com/android/server/audio/ServiceHolder.java
new file mode 100644
index 0000000..e2588fb
--- /dev/null
+++ b/services/core/java/com/android/server/audio/ServiceHolder.java
@@ -0,0 +1,219 @@
+/*
+ * 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 com.android.server.audio;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.IBinder;
+import android.os.IInterface;
+import android.os.IServiceCallback;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+/**
+ * Manages a remote service which can start and stop. Allows clients to add tasks to run when the
+ * remote service starts or dies.
+ *
+ * <p>Example usage should look something like:
+ *
+ * <pre>
+ * var service = mServiceHolder.checkService();
+ * if (service == null) handleFailure();
+ * try {
+ * service.foo();
+ * } catch (RemoteException e) {
+ * mServiceHolder.attemptClear(service.asBinder());
+ * handleFailure();
+ * }
+ * </pre>
+ */
+public class ServiceHolder<I extends IInterface> implements IBinder.DeathRecipient {
+
+ private final String mTag;
+ private final String mServiceName;
+ private final Function<? super IBinder, ? extends I> mCastFunction;
+ private final Executor mExecutor;
+ private final ServiceProviderFacade mServiceProvider;
+
+ private final AtomicReference<I> mService = new AtomicReference();
+ private final Set<Consumer<I>> mOnStartTasks = ConcurrentHashMap.newKeySet();
+ private final Set<Consumer<I>> mOnDeathTasks = ConcurrentHashMap.newKeySet();
+
+ private final IServiceCallback mServiceListener =
+ new IServiceCallback.Stub() {
+ @Override
+ public void onRegistration(String name, IBinder binder) {
+ onServiceInited(binder);
+ }
+ };
+
+ // For test purposes
+ public static interface ServiceProviderFacade {
+ public void registerForNotifications(String name, IServiceCallback listener);
+
+ public IBinder checkService(String name);
+
+ public IBinder waitForService(String name);
+ }
+
+ public ServiceHolder(
+ @NonNull String serviceName,
+ @NonNull Function<? super IBinder, ? extends I> castFunction,
+ @NonNull Executor executor) {
+ this(
+ serviceName,
+ castFunction,
+ executor,
+ new ServiceProviderFacade() {
+ @Override
+ public void registerForNotifications(String name, IServiceCallback listener) {
+ try {
+ ServiceManager.registerForNotifications(name, listener);
+ } catch (RemoteException e) {
+ throw new IllegalStateException("ServiceManager died!!", e);
+ }
+ }
+
+ @Override
+ public IBinder checkService(String name) {
+ return ServiceManager.checkService(name);
+ }
+
+ @Override
+ public IBinder waitForService(String name) {
+ return ServiceManager.waitForService(name);
+ }
+ });
+ }
+
+ public ServiceHolder(
+ @NonNull String serviceName,
+ @NonNull Function<? super IBinder, ? extends I> castFunction,
+ @NonNull Executor executor,
+ @NonNull ServiceProviderFacade provider) {
+ mServiceName = Objects.requireNonNull(serviceName);
+ mCastFunction = Objects.requireNonNull(castFunction);
+ mExecutor = Objects.requireNonNull(executor);
+ mServiceProvider = Objects.requireNonNull(provider);
+ mTag = "ServiceHolder: " + serviceName;
+ mServiceProvider.registerForNotifications(mServiceName, mServiceListener);
+ }
+
+ /**
+ * Add tasks to run when service becomes available. Ran on the executor provided at
+ * construction. Note, for convenience, if the service is already connected, the task is
+ * immediately run.
+ */
+ public void registerOnStartTask(Consumer<I> task) {
+ mOnStartTasks.add(task);
+ I i;
+ if ((i = mService.get()) != null) {
+ mExecutor.execute(() -> task.accept(i));
+ }
+ }
+
+ public void unregisterOnStartTask(Consumer<I> task) {
+ mOnStartTasks.remove(task);
+ }
+
+ /**
+ * Add tasks to run when service goes down. Ran on the executor provided at construction. Should
+ * be called before getService to avoid dropping a death notification.
+ */
+ public void registerOnDeathTask(Consumer<I> task) {
+ mOnDeathTasks.add(task);
+ }
+
+ public void unregisterOnDeathTask(Consumer<I> task) {
+ mOnDeathTasks.remove(task);
+ }
+
+ @Override
+ public void binderDied(@NonNull IBinder who) {
+ attemptClear(who);
+ }
+
+ @Override
+ public void binderDied() {
+ throw new AssertionError("Wrong binderDied called, this should never happen");
+ }
+
+ /**
+ * Notify the holder that the service has gone done, usually in response to a RemoteException.
+ * Equivalent to receiving a binder death notification.
+ */
+ public void attemptClear(IBinder who) {
+ // Possibly prone to weird races, resulting in spurious dead/revive,
+ // but that should be fine.
+ var current = mService.get();
+ if (current != null
+ && Objects.equals(current.asBinder(), who)
+ && mService.compareAndSet(current, null)) {
+ who.unlinkToDeath(this, 0);
+ for (var r : mOnDeathTasks) {
+ mExecutor.execute(() -> r.accept(current));
+ }
+ }
+ }
+
+ /** Get the service, without blocking. Can trigger start tasks, on the provided executor. */
+ public @Nullable I checkService() {
+ var s = mService.get();
+ if (s != null) return s;
+ IBinder registered = mServiceProvider.checkService(mServiceName);
+ if (registered == null) return null;
+ return onServiceInited(registered);
+ }
+
+ /** Get the service, but block. Can trigger start tasks, on the provided executor. */
+ public @NonNull I waitForService() {
+ var s = mService.get();
+ return (s != null) ? s : onServiceInited(mServiceProvider.waitForService(mServiceName));
+ }
+
+ /*
+ * Called when the native service is initialized.
+ */
+ private @NonNull I onServiceInited(@NonNull IBinder who) {
+ var service = mCastFunction.apply(who);
+ Objects.requireNonNull(service);
+ if (!mService.compareAndSet(null, service)) {
+ return service;
+ }
+ // Even if the service has immediately died, we should perform these tasks for consistency
+ for (var r : mOnStartTasks) {
+ mExecutor.execute(() -> r.accept(service));
+ }
+ try {
+ who.linkToDeath(this, 0);
+ } catch (RemoteException e) {
+ Log.e(mTag, "Immediate service death. Service crash-looping");
+ attemptClear(who);
+ }
+ // This interface is non-null, but could represent a dead object
+ return service;
+ }
+}
diff --git a/services/core/java/com/android/server/audio/SoundDoseHelper.java b/services/core/java/com/android/server/audio/SoundDoseHelper.java
index 9610034ca..e28ae95 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 @@
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 @@
}
}
- reset();
+ reset(/*resetISoundDose=*/false);
}
private void onConfigureSafeMedia(boolean force, String caller) {
diff --git a/services/core/java/com/android/server/display/DisplayOffloadSessionImpl.java b/services/core/java/com/android/server/display/DisplayOffloadSessionImpl.java
index f77a360..0fef55d 100644
--- a/services/core/java/com/android/server/display/DisplayOffloadSessionImpl.java
+++ b/services/core/java/com/android/server/display/DisplayOffloadSessionImpl.java
@@ -21,13 +21,21 @@
import android.annotation.Nullable;
import android.hardware.display.DisplayManagerInternal;
import android.os.Trace;
+import android.util.Slog;
import android.view.Display;
+import com.android.server.display.utils.DebugUtils;
+
/**
* An implementation of the offload session that keeps track of whether the session is active.
* An offload session is used to control the display's brightness using the offload chip.
*/
public class DisplayOffloadSessionImpl implements DisplayManagerInternal.DisplayOffloadSession {
+ private static final String TAG = "DisplayOffloadSessionImpl";
+
+ // To enable these logs, run:
+ // 'adb shell setprop persist.log.tag.DisplayOffloadSessionImpl DEBUG && adb reboot'
+ private static final boolean DEBUG = DebugUtils.isDebuggable(TAG);
@Nullable
private final DisplayManagerInternal.DisplayOffloader mDisplayOffloader;
@@ -99,9 +107,14 @@
if (mDisplayOffloader == null || mIsActive) {
return false;
}
+
Trace.traceBegin(Trace.TRACE_TAG_POWER, "DisplayOffloader#startOffload");
try {
- return mIsActive = mDisplayOffloader.startOffload();
+ mIsActive = mDisplayOffloader.startOffload();
+ if (DEBUG) {
+ Slog.d(TAG, "startOffload = " + mIsActive);
+ }
+ return mIsActive;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
@@ -118,6 +131,9 @@
try {
mDisplayOffloader.stopOffload();
mIsActive = false;
+ if (DEBUG) {
+ Slog.i(TAG, "stopOffload");
+ }
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 7d482f7..b97053b 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -791,10 +791,11 @@
@Override
public void overrideDozeScreenState(int displayState, @Display.StateReason int reason) {
+ Slog.i(TAG, "New offload doze override: " + Display.stateToString(displayState));
mHandler.postAtTime(() -> {
if (mDisplayOffloadSession == null
|| !(DisplayOffloadSession.isSupportedOffloadState(displayState)
- || displayState == Display.STATE_UNKNOWN)) {
+ || displayState == Display.STATE_UNKNOWN)) {
return;
}
mDisplayStateController.overrideDozeScreenState(displayState, reason);
@@ -1279,7 +1280,7 @@
private void updatePowerStateInternal() {
// Update the power state request.
- final boolean mustNotify;
+ boolean mustNotify = false;
final int previousPolicy;
boolean mustInitialize = false;
mBrightnessReasonTemp.set(null);
@@ -1327,6 +1328,30 @@
initialize(readyToUpdateDisplayState() ? state : Display.STATE_UNKNOWN);
}
+ if (mFlags.isOffloadDozeOverrideHoldsWakelockEnabled()) {
+ // Sometimes, a display-state change can come without an associated PowerRequest,
+ // as with DisplayOffload. For those cases, we have to make sure to also mark the
+ // display as "not ready" so that we can inform power-manager when the state-change is
+ // complete.
+ if (mPowerState.getScreenState() != state) {
+ final boolean wasReady;
+ synchronized (mLock) {
+ wasReady = mDisplayReadyLocked;
+ mDisplayReadyLocked = false;
+ mustNotify = true;
+ }
+
+ if (wasReady) {
+ // If we went from ready to not-ready from the state-change (instead of a
+ // PowerRequest) there's a good chance that nothing is keeping PowerManager
+ // from suspending. Grab the unfinished business suspend blocker to keep the
+ // device awake until the display-state change goes into effect.
+ mWakelockController.acquireWakelock(
+ WakelockController.WAKE_LOCK_UNFINISHED_BUSINESS);
+ }
+ }
+ }
+
// Animate the screen state change unless already animating.
// The transition may be deferred, so after this point we will use the
// actual state instead of the desired one.
diff --git a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
index 8f775a5..f923cbc9 100644
--- a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
+++ b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
@@ -174,6 +174,11 @@
Flags::enableSynthetic60hzModes
);
+ private final FlagState mOffloadDozeOverrideHoldsWakelock = new FlagState(
+ Flags.FLAG_OFFLOAD_DOZE_OVERRIDE_HOLDS_WAKELOCK,
+ Flags::offloadDozeOverrideHoldsWakelock
+ );
+
/**
* @return {@code true} if 'port' is allowed in display layout configuration file.
*/
@@ -343,6 +348,10 @@
return mPeakRefreshRatePhysicalLimit.isEnabled();
}
+ public boolean isOffloadDozeOverrideHoldsWakelockEnabled() {
+ return mOffloadDozeOverrideHoldsWakelock.isEnabled();
+ }
+
/**
* @return Whether to ignore preferredRefreshRate app request or not
*/
@@ -389,6 +398,7 @@
pw.println(" " + mPeakRefreshRatePhysicalLimit);
pw.println(" " + mIgnoreAppPreferredRefreshRate);
pw.println(" " + mSynthetic60hzModes);
+ pw.println(" " + mOffloadDozeOverrideHoldsWakelock);
}
private static class FlagState {
diff --git a/services/core/java/com/android/server/display/feature/display_flags.aconfig b/services/core/java/com/android/server/display/feature/display_flags.aconfig
index 697218d..95d0ca3 100644
--- a/services/core/java/com/android/server/display/feature/display_flags.aconfig
+++ b/services/core/java/com/android/server/display/feature/display_flags.aconfig
@@ -289,3 +289,13 @@
}
}
+flag {
+ name: "offload_doze_override_holds_wakelock"
+ namespace: "display_manager"
+ description: "DisplayPowerController holds a suspend-blocker while changing the display state on behalf of offload doze override."
+ bug: "338403827"
+ is_fixed_read_only: true
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
index d876a38..3c3bdd5 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 @@
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 5646e1b..0688fbf 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 @@
*
* @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 54c8c00..58e146e 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 @@
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 @@
* @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 32e274e..5ab22e1 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 @@
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 e96963b9..f14cda1 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.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 @@
* @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 99148c4..08a9387 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 @@
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 @@
* @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 5c0c272..675aa31 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 @@
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 @@
* @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/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index b14702d..b3ab229 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -1243,23 +1243,24 @@
}
}
- private void enforceFrpResolved() {
+ private void enforceFrpNotActive() {
final int mainUserId = mInjector.getUserManagerInternal().getMainUserId();
if (mainUserId < 0) {
- Slog.d(TAG, "No Main user on device; skipping enforceFrpResolved");
+ Slog.d(TAG, "No Main user on device; skipping enforceFrpNotActive");
return;
}
- final ContentResolver cr = mContext.getContentResolver();
+ final ContentResolver cr = mContext.getContentResolver();
final boolean inSetupWizard = Settings.Secure.getIntForUser(cr,
Settings.Secure.USER_SETUP_COMPLETE, 0, mainUserId) == 0;
- final boolean secureFrp = android.security.Flags.frpEnforcement()
+ final boolean isFrpActive = android.security.Flags.frpEnforcement()
? mStorage.isFactoryResetProtectionActive()
- : (Settings.Global.getInt(cr, Settings.Global.SECURE_FRP_MODE, 0) == 1);
+ : (Settings.Global.getInt(cr, Settings.Global.SECURE_FRP_MODE, 0) == 1)
+ && inSetupWizard;
- if (inSetupWizard && secureFrp) {
- throw new SecurityException("Cannot change credential in SUW while factory reset"
- + " protection is not resolved yet");
+ if (isFrpActive) {
+ throw new SecurityException("Cannot change credential while factory reset protection"
+ + " is active");
}
}
@@ -1831,7 +1832,7 @@
final long identity = Binder.clearCallingIdentity();
try {
- enforceFrpResolved();
+ enforceFrpNotActive();
// When changing credential for profiles with unified challenge, some callers
// will pass in empty credential while others will pass in the credential of
// the parent user. setLockCredentialInternal() handles the formal case (empty
diff --git a/services/core/java/com/android/server/media/MediaRoute2Provider.java b/services/core/java/com/android/server/media/MediaRoute2Provider.java
index 1bc2a5e..363684f 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.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 @@
@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 6ce3ab4..76930a0 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 @@
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 @@
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 @@
if (Flags.enableBuiltInSpeakerRouteSuitabilityStatuses()) {
synchronized (mTransferLock) {
mPendingTransferRequest =
- new SessionCreationRequest(
+ new SessionCreationOrTransferRequest(
requestId,
routeId,
transferReason,
@@ -438,7 +443,7 @@
boolean isTransferringToTheSelectedRoute =
mPendingTransferRequest.isTargetRoute(selectedRoute);
boolean canBePotentiallyTransferred =
- mPendingTransferRequest.isInsideOfRoutesList(transferableRoutes);
+ mPendingTransferRequest.isTargetRouteIdInList(transferableRoutes);
if (isTransferringToTheSelectedRoute) {
transferReason = mPendingTransferRequest.mTransferReason;
@@ -492,20 +497,20 @@
@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 @@
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 @@
// 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 @@
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/notification/NotificationShellCmd.java b/services/core/java/com/android/server/notification/NotificationShellCmd.java
index 9f3104c..10169d5 100644
--- a/services/core/java/com/android/server/notification/NotificationShellCmd.java
+++ b/services/core/java/com/android/server/notification/NotificationShellCmd.java
@@ -66,7 +66,7 @@
+ " disallow_listener COMPONENT [user_id (current user if not specified)]\n"
+ " allow_assistant COMPONENT [user_id (current user if not specified)]\n"
+ " remove_assistant COMPONENT [user_id (current user if not specified)]\n"
- + " set_dnd [on|none (same as on)|priority|alarms|all|off (same as all)]"
+ + " set_dnd [on|none (same as on)|priority|alarms|all|off (same as all)]\n"
+ " allow_dnd PACKAGE [user_id (current user if not specified)]\n"
+ " disallow_dnd PACKAGE [user_id (current user if not specified)]\n"
+ " reset_assistant_user_set [user_id (current user if not specified)]\n"
diff --git a/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java b/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java
index dd76037..f540f1d 100644
--- a/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java
+++ b/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java
@@ -925,10 +925,11 @@
}
}
- @RequiresPermission(Manifest.permission.USE_ON_DEVICE_INTELLIGENCE)
+ /**
+ * Reset the temporary services set in CTS tests, this method is primarily used to only revert
+ * the changes caused by CTS tests.
+ */
public void resetTemporaryServices() {
- mContext.enforceCallingPermission(
- Manifest.permission.USE_ON_DEVICE_INTELLIGENCE, TAG);
synchronized (mLock) {
if (mTemporaryHandler != null) {
mTemporaryHandler.removeMessages(MSG_RESET_TEMPORARY_SERVICE);
diff --git a/services/core/java/com/android/server/pm/InstantAppResolver.java b/services/core/java/com/android/server/pm/InstantAppResolver.java
index 92d6a82..42efd6e 100644
--- a/services/core/java/com/android/server/pm/InstantAppResolver.java
+++ b/services/core/java/com/android/server/pm/InstantAppResolver.java
@@ -28,6 +28,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
+import android.app.ActivityOptions;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
@@ -296,6 +297,9 @@
if (needsPhaseTwo) {
intent.setAction(Intent.ACTION_RESOLVE_INSTANT_APP_PACKAGE);
} else {
+ ActivityOptions options = ActivityOptions.makeBasic()
+ .setPendingIntentCreatorBackgroundActivityStartMode(
+ ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
// We have all of the data we need; just start the installer without a second phase
if (failureIntent != null || installFailureActivity != null) {
// Intent that is launched if the package couldn't be installed for any reason.
@@ -322,7 +326,7 @@
PendingIntent.FLAG_CANCEL_CURRENT
| PendingIntent.FLAG_ONE_SHOT
| PendingIntent.FLAG_IMMUTABLE,
- null /*bOptions*/, userId);
+ options.toBundle(), userId);
IntentSender failureSender = new IntentSender(failureIntentTarget);
// TODO(b/72700831): remove populating old extra
intent.putExtra(Intent.EXTRA_INSTANT_APP_FAILURE, failureSender);
@@ -342,7 +346,7 @@
new String[] { resolvedType },
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT
| PendingIntent.FLAG_IMMUTABLE,
- null /*bOptions*/, userId);
+ options.toBundle(), userId);
IntentSender successSender = new IntentSender(successIntentTarget);
intent.putExtra(Intent.EXTRA_INSTANT_APP_SUCCESS, successSender);
} catch (RemoteException ignore) { /* ignore; same process */ }
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 57f6d27..a904738 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 @@
}
// Okay to proceed
synchronized (mLock) {
+ assertCallerIsOwnerOrRoot();
+ assertPreparedAndNotSealedLocked("setPreVerifiedDomains");
mPreVerifiedDomains = preVerifiedDomains;
}
}
diff --git a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
index 1b6af71..efaa7a8 100644
--- a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
+++ b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
@@ -3698,7 +3698,7 @@
}
return mTotalTimeUs + (mNesting > 0
? (curBatteryRealtimeUs - mUpdateTimeUs)
- / (mTimerPool != null ? mTimerPool.size() : 1)
+ / (mTimerPool != null && mTimerPool.size() > 0 ? mTimerPool.size() : 1)
: 0);
}
diff --git a/services/core/java/com/android/server/search/SearchManagerService.java b/services/core/java/com/android/server/search/SearchManagerService.java
index ecfc040..9b39fa1 100644
--- a/services/core/java/com/android/server/search/SearchManagerService.java
+++ b/services/core/java/com/android/server/search/SearchManagerService.java
@@ -61,6 +61,8 @@
private static final String TAG = "SearchManagerService";
final Handler mHandler;
+ private final MyPackageMonitor mMyPackageMonitor;
+
public static class Lifecycle extends SystemService {
private SearchManagerService mService;
@@ -95,7 +97,8 @@
*/
public SearchManagerService(Context context) {
mContext = context;
- new MyPackageMonitor().register(context, null, UserHandle.ALL, true);
+ mMyPackageMonitor = new MyPackageMonitor();
+ mMyPackageMonitor.register(context, null, UserHandle.ALL, true);
new GlobalSearchProviderObserver(context.getContentResolver());
mHandler = BackgroundThread.getHandler();
}
@@ -230,7 +233,6 @@
if (!shouldRebuildSearchableList(changingUserId)) {
return;
}
-
synchronized (mSearchables) {
// Invalidate the searchable list.
Searchables searchables = mSearchables.get(changingUserId);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 434e92f..8611599 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -3964,7 +3964,7 @@
}
if (isCurrentVisible) {
- if (isNextNotYetVisible || delayRemoval) {
+ if (isNextNotYetVisible || delayRemoval || isInTransition()) {
// Add this activity to the list of stopping activities. It will be processed and
// destroyed when the next activity reports idle.
addToStopping(false /* scheduleIdle */, false /* idleDelayed */,
@@ -8551,7 +8551,7 @@
// If activity in fullscreen mode is letterboxed because of fixed orientation then bounds
// are already calculated in resolveFixedOrientationConfiguration.
// Don't apply aspect ratio if app is overridden to fullscreen by device user/manufacturer.
- if (!isLetterboxedForFixedOrientationAndAspectRatio()
+ if (Flags.immersiveAppRepositioning() && !isLetterboxedForFixedOrientationAndAspectRatio()
&& !mLetterboxUiController.hasFullscreenOverride()) {
resolveAspectRatioRestriction(newParentConfiguration);
}
@@ -8568,6 +8568,14 @@
computeConfigByResolveHint(resolvedConfig, newParentConfiguration);
}
}
+ // If activity in fullscreen mode is letterboxed because of fixed orientation then bounds
+ // are already calculated in resolveFixedOrientationConfiguration, or if in size compat
+ // mode, it should already be calculated in resolveSizeCompatModeConfiguration.
+ // Don't apply aspect ratio if app is overridden to fullscreen by device user/manufacturer.
+ if (!Flags.immersiveAppRepositioning() && !isLetterboxedForFixedOrientationAndAspectRatio()
+ && !mInSizeCompatModeForBounds && !mLetterboxUiController.hasFullscreenOverride()) {
+ resolveAspectRatioRestriction(newParentConfiguration);
+ }
if (isFixedOrientationLetterboxAllowed || compatDisplayInsets != null
// In fullscreen, can be letterboxed for aspect ratio.
@@ -8903,7 +8911,11 @@
}
boolean isImmersiveMode(@NonNull Rect parentBounds) {
- if (!mResolveConfigHint.mUseOverrideInsetsForConfig) {
+ if (!Flags.immersiveAppRepositioning()) {
+ return false;
+ }
+ if (!mResolveConfigHint.mUseOverrideInsetsForConfig
+ && mWmService.mFlags.mInsetsDecoupledConfiguration) {
return false;
}
final Insets navBarInsets = mDisplayContent.getInsetsStateController()
@@ -9252,10 +9264,12 @@
// orientation bounds (stored in resolved bounds) instead of parent bounds since the
// activity will be displayed within them even if it is in size compat mode. They should be
// saved here before resolved bounds are overridden below.
- final Rect containerBounds = isAspectRatioApplied()
+ final boolean useResolvedBounds = Flags.immersiveAppRepositioning()
+ ? isAspectRatioApplied() : isLetterboxedForFixedOrientationAndAspectRatio();
+ final Rect containerBounds = useResolvedBounds
? new Rect(resolvedBounds)
: newParentConfiguration.windowConfiguration.getBounds();
- final Rect containerAppBounds = isAspectRatioApplied()
+ final Rect containerAppBounds = useResolvedBounds
? new Rect(resolvedConfig.windowConfiguration.getAppBounds())
: newParentConfiguration.windowConfiguration.getAppBounds();
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index 108c7fb..f91ef1d 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 @@
}
void finishPresentAnimations() {
- if (!mComposed) {
- return;
- }
-
if (mCloseAdaptor != null) {
mCloseAdaptor.mTarget.cancelAnimation();
mCloseAdaptor = null;
@@ -1131,8 +1127,10 @@
}
void clearBackAnimateTarget() {
- finishPresentAnimations();
- mComposed = false;
+ if (mComposed) {
+ mComposed = false;
+ finishPresentAnimations();
+ }
mWaitTransition = false;
mStartingSurfaceTargetMatch = false;
mSwitchType = UNKNOWN;
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index 72f592b..e07b72a 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -33,6 +33,7 @@
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.os.Process.SYSTEM_UID;
import static android.view.MotionEvent.CLASSIFICATION_MULTI_FINGER_SWIPE;
+import static android.view.WindowInsets.Type.mandatorySystemGestures;
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
@@ -60,6 +61,8 @@
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.graphics.Bitmap;
+import android.graphics.Insets;
+import android.graphics.Rect;
import android.os.Environment;
import android.os.IBinder;
import android.os.RemoteException;
@@ -71,7 +74,9 @@
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
+import android.view.InsetsState;
import android.view.MotionEvent;
+import android.view.WindowInsets;
import android.view.WindowManagerPolicyConstants.PointerEventListener;
import com.android.internal.annotations.VisibleForTesting;
@@ -208,6 +213,7 @@
private final HashMap<ComponentName, ActivityInfo> mTmpAvailActCache = new HashMap<>();
private final HashMap<String, ApplicationInfo> mTmpAvailAppCache = new HashMap<>();
private final SparseBooleanArray mTmpQuietProfileUserIds = new SparseBooleanArray();
+ private final Rect mTmpRect = new Rect();
// TODO(b/127498985): This is currently a rough heuristic for interaction inside an app
private final PointerEventListener mListener = new PointerEventListener() {
@@ -229,12 +235,27 @@
if (win == null) {
return;
}
+
+ // Verify the touch is within the mandatory system gesture inset bounds of the
+ // window, use the raw insets state to ignore window z-order
+ final InsetsState insetsState = dc.getInsetsStateController()
+ .getRawInsetsState();
+ mTmpRect.set(win.getFrame());
+ mTmpRect.inset(insetsState.calculateInsets(win.getFrame(),
+ mandatorySystemGestures(), false /* ignoreVisibility */));
+ if (!mTmpRect.contains(x, y)) {
+ return;
+ }
+
// Unfreeze the task list once we touch down in a task
final boolean isAppWindowTouch = FIRST_APPLICATION_WINDOW <= win.mAttrs.type
&& win.mAttrs.type <= LAST_APPLICATION_WINDOW;
if (isAppWindowTouch) {
final Task stack = mService.getTopDisplayFocusedRootTask();
final Task topTask = stack != null ? stack.getTopMostTask() : null;
+ ProtoLog.i(WM_DEBUG_TASKS, "Resetting frozen recents task list"
+ + " reason=app touch win=%s x=%d y=%d insetFrame=%s", win, x, y,
+ mTmpRect);
resetFreezeTaskListReordering(topTask);
}
}
@@ -301,6 +322,8 @@
mFreezeTaskListReordering = true;
}
+ ProtoLog.i(WM_DEBUG_TASKS, "Setting frozen recents task list");
+
// Always update the reordering time when this is called to ensure that the timeout
// is reset
mService.mH.removeCallbacks(mResetFreezeTaskListOnTimeoutRunnable);
@@ -344,6 +367,7 @@
final Task focusedStack = mService.getTopDisplayFocusedRootTask();
final Task topTask = focusedStack != null ? focusedStack.getTopMostTask() : null;
final Task reorderToEndTask = topTask != null && topTask.hasChild() ? topTask : null;
+ ProtoLog.i(WM_DEBUG_TASKS, "Resetting frozen recents task list reason=timeout");
resetFreezeTaskListReordering(reorderToEndTask);
}
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index cd22591..9dc9ad4 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -6880,7 +6880,7 @@
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 28369fa..c972eee 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 @@
@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 @@
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 @@
// 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 @@
}
/**
+ * 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
@@ -3758,7 +3787,7 @@
if (changeInfo.mRotation != wc.mDisplayContent.getRotation()) {
// This isn't cheap, so only do it for rotation change.
changeInfo.mSnapshotLuma = TransitionAnimation.getBorderLuma(
- buffer, screenshotBuffer.getColorSpace());
+ buffer, screenshotBuffer.getColorSpace(), wc.mSurfaceControl);
}
SurfaceControl.Transaction t = wc.mWmService.mTransactionFactory.get();
TransitionAnimation.configureScreenshotLayer(t, snapshotSurface, screenshotBuffer);
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 5e932d4..6221d96 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 @@
}
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 @@
// 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/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
index e763c9e..669a999 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
@@ -1588,7 +1588,7 @@
private Set<EnforcingAdmin> getEnforcingAdminsOnUser(int userId) {
synchronized (mLock) {
return mEnforcingAdmins.contains(userId)
- ? mEnforcingAdmins.get(userId) : Collections.emptySet();
+ ? new HashSet<>(mEnforcingAdmins.get(userId)) : Collections.emptySet();
}
}
diff --git a/services/midi/java/com/android/server/midi/MidiService.java b/services/midi/java/com/android/server/midi/MidiService.java
index c16c612..cc340c0 100644
--- a/services/midi/java/com/android/server/midi/MidiService.java
+++ b/services/midi/java/com/android/server/midi/MidiService.java
@@ -287,6 +287,7 @@
}
public void deviceAdded(Device device) {
+ Log.d(TAG, "deviceAdded() " + device.getUserId() + " userId:" + getUserId());
// ignore devices that our client cannot access
if (!device.isUidAllowed(mUid) || !device.isUserIdAllowed(getUserId())) return;
@@ -301,6 +302,7 @@
}
public void deviceRemoved(Device device) {
+ Log.d(TAG, "deviceRemoved() " + device.getUserId() + " userId:" + getUserId());
// ignore devices that our client cannot access
if (!device.isUidAllowed(mUid) || !device.isUserIdAllowed(getUserId())) return;
@@ -315,6 +317,7 @@
}
public void deviceStatusChanged(Device device, MidiDeviceStatus status) {
+ Log.d(TAG, "deviceStatusChanged() " + device.getUserId() + " userId:" + getUserId());
// ignore devices that our client cannot access
if (!device.isUidAllowed(mUid) || !device.isUserIdAllowed(getUserId())) return;
@@ -1303,7 +1306,7 @@
String[] inputPortNames, String[] outputPortNames, Bundle properties,
IMidiDeviceServer server, ServiceInfo serviceInfo,
boolean isPrivate, int uid, int defaultProtocol, int userId) {
- Log.d(TAG, "addDeviceLocked()" + uid + " type:" + type);
+ Log.d(TAG, "addDeviceLocked() " + uid + " type:" + type + " userId:" + userId);
// Limit the number of devices per app.
int deviceCountForApp = 0;
diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
index 488fe57..9f97648 100644
--- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
+++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
@@ -370,18 +370,18 @@
}
private static void createAndUploadReport(ProfcollectForwardingService pfs) {
- String reportName;
- try {
- reportName = pfs.mIProfcollect.report(pfs.mUsageSetting) + ".zip";
- } catch (RemoteException e) {
- Log.e(LOG_TAG, "Failed to create report: " + e.getMessage());
- return;
- }
- if (!pfs.mUploadEnabled) {
- Log.i(LOG_TAG, "Upload is not enabled.");
- return;
- }
BackgroundThread.get().getThreadHandler().post(() -> {
+ String reportName;
+ try {
+ reportName = pfs.mIProfcollect.report(pfs.mUsageSetting) + ".zip";
+ } catch (RemoteException e) {
+ Log.e(LOG_TAG, "Failed to create report: " + e.getMessage());
+ return;
+ }
+ if (!pfs.mUploadEnabled) {
+ Log.i(LOG_TAG, "Upload is not enabled.");
+ return;
+ }
Intent intent = new Intent()
.setPackage("com.android.shell")
.setAction("com.android.shell.action.PROFCOLLECT_UPLOAD")
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
index 98f572d..8fd1e6b 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
@@ -1538,6 +1538,8 @@
@Test
public void testDozeScreenStateOverride_toSupportedOffloadStateFromDoze_DisplayStateChanges() {
+ when(mDisplayManagerFlagsMock.isOffloadDozeOverrideHoldsWakelockEnabled()).thenReturn(true);
+
// set up.
int initState = Display.STATE_DOZE;
int supportedTargetState = Display.STATE_DOZE_SUSPEND;
@@ -1556,10 +1558,15 @@
mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
advanceTime(1); // Run updatePowerState
+ reset(mHolder.wakelockController);
mHolder.dpc.overrideDozeScreenState(
supportedTargetState, Display.STATE_REASON_DEFAULT_POLICY);
advanceTime(1); // Run updatePowerState
+ // Should get a wakelock to notify powermanager
+ verify(mHolder.wakelockController, atLeastOnce()).acquireWakelock(
+ eq(WakelockController.WAKE_LOCK_UNFINISHED_BUSINESS));
+
verify(mHolder.displayPowerState)
.setScreenState(supportedTargetState, Display.STATE_REASON_DEFAULT_POLICY);
}
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 ad68de8..9d8d520 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.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 @@
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 @@
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 f971f0e..4e8c755 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 @@
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/audio/ServiceHolderTest.java b/services/tests/servicestests/src/com/android/server/audio/ServiceHolderTest.java
new file mode 100644
index 0000000..39f19ae
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/audio/ServiceHolderTest.java
@@ -0,0 +1,284 @@
+/*
+ * 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 com.android.server.audio;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.media.IAudioPolicyService;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.IServiceCallback;
+import android.os.RemoteException;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.ArgumentMatchers;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+@RunWith(AndroidJUnit4.class)
+@Presubmit
+public class ServiceHolderTest {
+
+ private static final String AUDIO_POLICY_SERVICE_NAME = "media.audio_policy";
+
+ @Rule
+ public final MockitoRule mockito = MockitoJUnit.rule();
+
+ // the actual class under test
+ private ServiceHolder<IAudioPolicyService> mServiceHolder;
+
+ @Mock private ServiceHolder.ServiceProviderFacade mServiceProviderFacade;
+
+ @Mock private IAudioPolicyService mAudioPolicyService;
+
+ @Mock private IBinder mBinder;
+
+ @Mock private Consumer<IAudioPolicyService> mTaskOne;
+ @Mock private Consumer<IAudioPolicyService> mTaskTwo;
+
+ @Before
+ public void setUp() throws Exception {
+ mServiceHolder =
+ new ServiceHolder(
+ AUDIO_POLICY_SERVICE_NAME,
+ (Function<IBinder, IAudioPolicyService>)
+ binder -> {
+ if (binder == mBinder) {
+ return mAudioPolicyService;
+ } else {
+ return mock(IAudioPolicyService.class);
+ }
+ },
+ r -> r.run(),
+ mServiceProviderFacade);
+ when(mAudioPolicyService.asBinder()).thenReturn(mBinder);
+ }
+
+ @Test
+ public void testListenerRegistered_whenConstructed() {
+ verify(mServiceProviderFacade)
+ .registerForNotifications(eq(AUDIO_POLICY_SERVICE_NAME), ArgumentMatchers.any());
+ }
+
+ @Test
+ public void testServiceSuccessfullyPopulated_whenCallback() throws RemoteException {
+ initializeViaCallback();
+ verify(mBinder).linkToDeath(any(), anyInt());
+ assertThat(mServiceHolder.checkService()).isEqualTo(mAudioPolicyService);
+ }
+
+ @Test
+ public void testCheckServiceCalled_whenUncached() {
+ when(mServiceProviderFacade.checkService(eq(AUDIO_POLICY_SERVICE_NAME)))
+ .thenReturn(mBinder);
+ assertThat(mServiceHolder.checkService()).isEqualTo(mAudioPolicyService);
+ }
+
+ @Test
+ public void testCheckServiceTransmitsNull() {
+ assertThat(mServiceHolder.checkService()).isEqualTo(null);
+ }
+
+ @Test
+ public void testWaitForServiceCalled_whenUncached() {
+ when(mServiceProviderFacade.waitForService(eq(AUDIO_POLICY_SERVICE_NAME)))
+ .thenReturn(mBinder);
+ assertThat(mServiceHolder.waitForService()).isEqualTo(mAudioPolicyService);
+ }
+
+ @Test
+ public void testCheckServiceNotCalled_whenCached() {
+ initializeViaCallback();
+ mServiceHolder.checkService();
+ verify(mServiceProviderFacade, never()).checkService(any());
+ }
+
+ @Test
+ public void testWaitForServiceNotCalled_whenCached() {
+ initializeViaCallback();
+ mServiceHolder.waitForService();
+ verify(mServiceProviderFacade, never()).waitForService(any());
+ }
+
+ @Test
+ public void testStartTaskCalled_onStart() {
+ mServiceHolder.registerOnStartTask(mTaskOne);
+ mServiceHolder.registerOnStartTask(mTaskTwo);
+ mServiceHolder.unregisterOnStartTask(mTaskOne);
+ when(mServiceProviderFacade.checkService(eq(AUDIO_POLICY_SERVICE_NAME)))
+ .thenReturn(mBinder);
+
+ assertThat(mServiceHolder.checkService()).isEqualTo(mAudioPolicyService);
+
+ verify(mTaskTwo).accept(eq(mAudioPolicyService));
+ verify(mTaskOne, never()).accept(any());
+ }
+
+ @Test
+ public void testStartTaskCalled_onStartFromCallback() {
+ mServiceHolder.registerOnStartTask(mTaskOne);
+ mServiceHolder.registerOnStartTask(mTaskTwo);
+ mServiceHolder.unregisterOnStartTask(mTaskOne);
+
+ initializeViaCallback();
+
+ assertThat(mServiceHolder.checkService()).isEqualTo(mAudioPolicyService);
+ verify(mTaskTwo).accept(eq(mAudioPolicyService));
+ verify(mTaskOne, never()).accept(any());
+ }
+
+ @Test
+ public void testStartTaskCalled_onRegisterAfterStarted() {
+ initializeViaCallback();
+ mServiceHolder.registerOnStartTask(mTaskOne);
+ verify(mTaskOne).accept(eq(mAudioPolicyService));
+ }
+
+ @Test
+ public void testBinderDied_clearsServiceAndUnlinks() {
+ initializeViaCallback();
+ assertThat(mServiceHolder.checkService()).isEqualTo(mAudioPolicyService);
+
+ mServiceHolder.binderDied(mBinder);
+
+ verify(mBinder).unlinkToDeath(any(), anyInt());
+ assertThat(mServiceHolder.checkService()).isEqualTo(null);
+ verify(mServiceProviderFacade).checkService(eq(AUDIO_POLICY_SERVICE_NAME));
+ }
+
+ @Test
+ public void testBinderDied_callsDeathTasks() {
+ mServiceHolder.registerOnDeathTask(mTaskOne);
+ mServiceHolder.registerOnDeathTask(mTaskTwo);
+ initializeViaCallback();
+ assertThat(mServiceHolder.checkService()).isEqualTo(mAudioPolicyService);
+ mServiceHolder.unregisterOnDeathTask(mTaskOne);
+
+ mServiceHolder.binderDied(mBinder);
+
+ verify(mTaskTwo).accept(eq(mAudioPolicyService));
+ verify(mTaskOne, never()).accept(any());
+ }
+
+ @Test
+ public void testAttemptClear_clearsServiceAndUnlinks() {
+ initializeViaCallback();
+ assertThat(mServiceHolder.checkService()).isEqualTo(mAudioPolicyService);
+
+ mServiceHolder.attemptClear(mBinder);
+
+ verify(mBinder).unlinkToDeath(any(), anyInt());
+ assertThat(mServiceHolder.checkService()).isEqualTo(null);
+ verify(mServiceProviderFacade).checkService(eq(AUDIO_POLICY_SERVICE_NAME));
+ }
+
+ @Test
+ public void testAttemptClear_callsDeathTasks() {
+ mServiceHolder.registerOnDeathTask(mTaskOne);
+ mServiceHolder.registerOnDeathTask(mTaskTwo);
+ initializeViaCallback();
+ assertThat(mServiceHolder.checkService()).isEqualTo(mAudioPolicyService);
+ mServiceHolder.unregisterOnDeathTask(mTaskOne);
+
+ mServiceHolder.attemptClear(mBinder);
+
+ verify(mTaskTwo).accept(eq(mAudioPolicyService));
+ verify(mTaskOne, never()).accept(any());
+ }
+
+ @Test
+ public void testSet_whenServiceSet_isIgnored() {
+ mServiceHolder.registerOnStartTask(mTaskOne);
+ when(mServiceProviderFacade.checkService(eq(AUDIO_POLICY_SERVICE_NAME)))
+ .thenReturn(mBinder);
+ assertThat(mServiceHolder.checkService()).isEqualTo(mAudioPolicyService);
+
+ verify(mTaskOne).accept(eq(mAudioPolicyService));
+
+ // get the callback
+ ArgumentCaptor<IServiceCallback> cb = ArgumentCaptor.forClass(IServiceCallback.class);
+ verify(mServiceProviderFacade)
+ .registerForNotifications(eq(AUDIO_POLICY_SERVICE_NAME), cb.capture());
+
+ // Simulate a service callback with a different instance
+ try {
+ cb.getValue().onRegistration(AUDIO_POLICY_SERVICE_NAME, new Binder());
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+
+ // No additional start task call (i.e. only the first verify)
+ verify(mTaskOne).accept(any());
+ // Same instance
+ assertThat(mServiceHolder.checkService()).isEqualTo(mAudioPolicyService);
+
+ }
+
+ @Test
+ public void testClear_whenServiceCleared_isIgnored() {
+ mServiceHolder.registerOnDeathTask(mTaskOne);
+ mServiceHolder.attemptClear(mBinder);
+ verify(mTaskOne, never()).accept(any());
+ }
+
+ @Test
+ public void testClear_withDifferentCookie_isIgnored() {
+ mServiceHolder.registerOnDeathTask(mTaskOne);
+ initializeViaCallback();
+ assertThat(mServiceHolder.checkService()).isEqualTo(mAudioPolicyService);
+
+ // Notif for stale cookie
+ mServiceHolder.attemptClear(new Binder());
+
+ // Service shouldn't be cleared
+ assertThat(mServiceHolder.checkService()).isEqualTo(mAudioPolicyService);
+ // No death tasks should fire
+ verify(mTaskOne, never()).accept(any());
+ }
+
+ private void initializeViaCallback() {
+ ArgumentCaptor<IServiceCallback> cb = ArgumentCaptor.forClass(IServiceCallback.class);
+ verify(mServiceProviderFacade)
+ .registerForNotifications(eq(AUDIO_POLICY_SERVICE_NAME), cb.capture());
+
+ try {
+ cb.getValue().onRegistration(AUDIO_POLICY_SERVICE_NAME, mBinder);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
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 98e119c..473d1dc 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 @@
@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 c89c32a..74583dd 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 @@
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/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
index 4b22652..601a016 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
@@ -43,6 +43,8 @@
import android.content.Intent;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;
import android.platform.test.flag.junit.SetFlagsRule;
import android.service.gatekeeper.GateKeeperResponse;
@@ -483,18 +485,31 @@
setSecureFrpMode(true);
try {
mService.setLockCredential(newPassword("1234"), nonePassword(), PRIMARY_USER_ID);
- fail("Password shouldn't be changeable before FRP unlock");
+ fail("Password shouldn't be changeable while FRP is active");
} catch (SecurityException e) { }
}
@Test
- public void testSetCredentialPossibleInSecureFrpModeAfterSuw() throws RemoteException {
+ @DisableFlags(android.security.Flags.FLAG_FRP_ENFORCEMENT)
+ public void testSetCredentialPossibleInSecureFrpModeAfterSuw_FlagOff() throws RemoteException {
setUserSetupComplete(true);
setSecureFrpMode(true);
setCredential(PRIMARY_USER_ID, newPassword("1234"));
}
@Test
+ @EnableFlags(android.security.Flags.FLAG_FRP_ENFORCEMENT)
+ public void testSetCredentialNotPossibleInSecureFrpModeAfterSuw_FlagOn()
+ throws RemoteException {
+ setUserSetupComplete(true);
+ setSecureFrpMode(true);
+ try {
+ mService.setLockCredential(newPassword("1234"), nonePassword(), PRIMARY_USER_ID);
+ fail("Password shouldn't be changeable after SUW while FRP is active");
+ } catch (SecurityException e) { }
+ }
+
+ @Test
public void testPasswordHistoryDisabledByDefault() throws Exception {
final int userId = PRIMARY_USER_ID;
checkPasswordHistoryLength(userId, 0);
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 96ddfe8..7ced9d5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -107,6 +107,7 @@
import android.os.Binder;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;
import android.platform.test.annotations.RequiresFlagsDisabled;
import android.provider.DeviceConfig;
@@ -401,6 +402,7 @@
// TODO(b/333663877): Enable test after fix
@Test
@RequiresFlagsDisabled({Flags.FLAG_INSETS_DECOUPLED_CONFIGURATION})
+ @EnableFlags(Flags.FLAG_IMMERSIVE_APP_REPOSITIONING)
public void testRepositionLandscapeImmersiveAppWithDisplayCutout() {
final int dw = 2100;
final int dh = 2000;
@@ -4059,6 +4061,7 @@
}
@Test
+ @EnableFlags(Flags.FLAG_IMMERSIVE_APP_REPOSITIONING)
public void testImmersiveLetterboxAlignedToBottom_OverlappingNavbar() {
assertLandscapeActivityAlignedToBottomWithNavbar(true /* immersive */);
}
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 698afaa..69f2d68 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 @@
}
@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<>();
diff --git a/tests/FlickerTests/ActivityEmbedding/Android.bp b/tests/FlickerTests/ActivityEmbedding/Android.bp
index 2cdf542..e09fbf6 100644
--- a/tests/FlickerTests/ActivityEmbedding/Android.bp
+++ b/tests/FlickerTests/ActivityEmbedding/Android.bp
@@ -20,17 +20,65 @@
// all of the 'license_kinds' from "frameworks_base_license"
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
+ default_team: "trendy_team_windowing_sdk",
default_applicable_licenses: ["frameworks_base_license"],
}
-android_test {
- name: "FlickerTestsOther",
+filegroup {
+ name: "FlickerTestsOtherCommon-src",
+ srcs: ["src/**/ActivityEmbeddingTestBase.kt"],
+}
+
+filegroup {
+ name: "FlickerTestsOtherOpen-src",
+ srcs: ["src/**/open/*"],
+}
+
+filegroup {
+ name: "FlickerTestsOtherRotation-src",
+ srcs: ["src/**/rotation/*"],
+}
+
+java_library {
+ name: "FlickerTestsOtherCommon",
+ defaults: ["FlickerTestsDefault"],
+ srcs: [":FlickerTestsOtherCommon-src"],
+ static_libs: ["FlickerTestsBase"],
+}
+
+java_defaults {
+ name: "FlickerTestsOtherDefaults",
defaults: ["FlickerTestsDefault"],
manifest: "AndroidManifest.xml",
package_name: "com.android.server.wm.flicker",
instrumentation_target_package: "com.android.server.wm.flicker",
test_config_template: "AndroidTestTemplate.xml",
- srcs: ["src/**/*"],
- static_libs: ["FlickerTestsBase"],
+ static_libs: [
+ "FlickerTestsBase",
+ "FlickerTestsOtherCommon",
+ ],
data: ["trace_config/*"],
}
+
+android_test {
+ name: "FlickerTestsOtherOpen",
+ defaults: ["FlickerTestsOtherDefaults"],
+ srcs: [":FlickerTestsOtherOpen-src"],
+}
+
+android_test {
+ name: "FlickerTestsOtherRotation",
+ defaults: ["FlickerTestsOtherDefaults"],
+ srcs: [":FlickerTestsOtherRotation-src"],
+}
+
+android_test {
+ name: "FlickerTestsOther",
+ defaults: ["FlickerTestsOtherDefaults"],
+ srcs: ["src/**/*"],
+ exclude_srcs: [
+ ":FlickerTestsOtherOpen-src",
+ ":FlickerTestsOtherRotation-src",
+ ":FlickerTestsOtherCommon-src",
+ ],
+}
diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
index 093923f..a8b383c 100644
--- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
+++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
@@ -101,8 +101,8 @@
private static final String OBSERVER_NAME_2 = "observer2";
private static final String OBSERVER_NAME_3 = "observer3";
private static final String OBSERVER_NAME_4 = "observer4";
- private static final long SHORT_DURATION = TimeUnit.SECONDS.toMillis(1);
- private static final long LONG_DURATION = TimeUnit.SECONDS.toMillis(5);
+ private static final long SHORT_DURATION = TimeUnit.SECONDS.toMillis(10);
+ private static final long LONG_DURATION = TimeUnit.SECONDS.toMillis(50);
@Rule
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
@@ -1453,7 +1453,8 @@
raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_A,
VERSION_CODE)), PackageWatchdog.FAILURE_REASON_UNKNOWN);
- moveTimeForwardAndDispatch(PackageWatchdog.DEFAULT_DEESCALATION_WINDOW_MS);
+ moveTimeForwardAndDispatch(PackageWatchdog.DEFAULT_DEESCALATION_WINDOW_MS
+ - TimeUnit.MINUTES.toMillis(1));
// The first failure will be outside the threshold.
raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_A,
@@ -1712,6 +1713,9 @@
watchdog.onPackageFailure(packages, failureReason);
}
mTestLooper.dispatchAll();
+ if (Flags.recoverabilityDetection()) {
+ moveTimeForwardAndDispatch(watchdog.DEFAULT_MITIGATION_WINDOW_MS);
+ }
}
private PackageWatchdog createWatchdog() {