Merge "Update SelectorWithWidgetPreference layout" into main
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 719e438..1b71e73 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -25,6 +25,9 @@
import static android.app.admin.DevicePolicyResources.UNDEFINED;
import static android.graphics.drawable.Icon.TYPE_URI;
import static android.graphics.drawable.Icon.TYPE_URI_ADAPTIVE_BITMAP;
+import static android.util.TypedValue.COMPLEX_UNIT_PX;
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static java.util.Objects.requireNonNull;
@@ -6001,6 +6004,8 @@
contentView.setViewVisibility(p.mTextViewId, View.GONE);
contentView.setTextViewText(p.mTextViewId, null);
}
+
+ updateExpanderAlignment(contentView, p, hasSecondLine);
setHeaderlessVerticalMargins(contentView, p, hasSecondLine);
// Update margins to leave space for the top line (but not for headerless views like
@@ -6010,12 +6015,29 @@
int margin = getContentMarginTop(mContext,
R.dimen.notification_2025_content_margin_top);
contentView.setViewLayoutMargin(R.id.notification_main_column,
- RemoteViews.MARGIN_TOP, margin, TypedValue.COMPLEX_UNIT_PX);
+ RemoteViews.MARGIN_TOP, margin, COMPLEX_UNIT_PX);
}
return contentView;
}
+ private static void updateExpanderAlignment(RemoteViews contentView,
+ StandardTemplateParams p, boolean hasSecondLine) {
+ if (notificationsRedesignTemplates() && p.mHeaderless) {
+ if (!hasSecondLine) {
+ // If there's no text, let's center the expand button vertically to align things
+ // more nicely. This is handled separately for notifications that use a
+ // NotificationHeaderView, see NotificationHeaderView#centerTopLine.
+ contentView.setViewLayoutHeight(R.id.expand_button, MATCH_PARENT,
+ COMPLEX_UNIT_PX);
+ } else {
+ // Otherwise, just use the default height for the button to keep it top-aligned.
+ contentView.setViewLayoutHeight(R.id.expand_button, WRAP_CONTENT,
+ COMPLEX_UNIT_PX);
+ }
+ }
+ }
+
private static void setHeaderlessVerticalMargins(RemoteViews contentView,
StandardTemplateParams p, boolean hasSecondLine) {
if (Flags.notificationsRedesignTemplates() || !p.mHeaderless) {
@@ -9560,7 +9582,7 @@
int marginStart = res.getDimensionPixelSize(
R.dimen.notification_2025_content_margin_start);
contentView.setViewLayoutMargin(R.id.title,
- RemoteViews.MARGIN_START, marginStart, TypedValue.COMPLEX_UNIT_PX);
+ RemoteViews.MARGIN_START, marginStart, COMPLEX_UNIT_PX);
}
if (isLegacyHeaderless) {
// Collapsed legacy messaging style has a 1-line limit.
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index f58baff..4fc894c 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -789,6 +789,12 @@
in @nullable ImeTracker.Token statsToken);
/**
+ * Updates the currently animating insets types of a remote process.
+ */
+ @EnforcePermission("MANAGE_APP_TOKENS")
+ void updateDisplayWindowAnimatingTypes(int displayId, int animatingTypes);
+
+ /**
* Called to get the expected window insets.
*
* @return {@code true} if system bars are always consumed.
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 1f8f0820..7d6d5a2 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -272,6 +272,15 @@
in @nullable ImeTracker.Token imeStatsToken);
/**
+ * Notifies WindowState what insets types are currently running within the Window.
+ * see {@link com.android.server.wm.WindowState#mInsetsAnimationRunning).
+ *
+ * @param window The window that is insets animaiton is running.
+ * @param animatingTypes Indicates the currently animating insets types.
+ */
+ oneway void updateAnimatingTypes(IWindow window, int animatingTypes);
+
+ /**
* Called when the system gesture exclusion has changed.
*/
oneway void reportSystemGestureExclusionChanged(IWindow window, in List<Rect> exclusionRects);
@@ -372,14 +381,4 @@
*/
oneway void notifyImeWindowVisibilityChangedFromClient(IWindow window, boolean visible,
in ImeTracker.Token statsToken);
-
- /**
- * Notifies WindowState whether inset animations are currently running within the Window.
- * This value is used by the server to vote for refresh rate.
- * see {@link com.android.server.wm.WindowState#mInsetsAnimationRunning).
- *
- * @param window The window that is insets animaiton is running.
- * @param running Indicates the insets animation state.
- */
- oneway void notifyInsetsAnimationRunningStateChanged(IWindow window, boolean running);
}
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 0d82acd..462c5c6 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -211,12 +211,12 @@
}
/**
- * Notifies when the state of running animation is changed. The state is either "running" or
- * "idle".
+ * Notifies when the insets types of running animation have changed. The animatingTypes
+ * contain all types, which have an ongoing animation.
*
- * @param running {@code true} if there is any animation running; {@code false} otherwise.
+ * @param animatingTypes the {@link InsetsType}s that are currently animating
*/
- default void notifyAnimationRunningStateChanged(boolean running) {}
+ default void updateAnimatingTypes(@InsetsType int animatingTypes) {}
/** @see ViewRootImpl#isHandlingPointerEvent */
default boolean isHandlingPointerEvent() {
@@ -665,6 +665,9 @@
/** Set of inset types which are requested visible which are reported to the host */
private @InsetsType int mReportedRequestedVisibleTypes = WindowInsets.Type.defaultVisible();
+ /** Set of insets types which are currently animating */
+ private @InsetsType int mAnimatingTypes = 0;
+
/** Set of inset types that we have controls of */
private @InsetsType int mControllableTypes;
@@ -745,9 +748,10 @@
mFrame, mFromState, mToState, RESIZE_INTERPOLATOR,
ANIMATION_DURATION_RESIZE, mTypes, InsetsController.this);
if (mRunningAnimations.isEmpty()) {
- mHost.notifyAnimationRunningStateChanged(true);
+ mHost.updateAnimatingTypes(runner.getTypes());
}
mRunningAnimations.add(new RunningAnimation(runner, runner.getAnimationType()));
+ mAnimatingTypes |= runner.getTypes();
}
};
@@ -1564,9 +1568,8 @@
}
}
ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_CLIENT_ANIMATION_RUNNING);
- if (mRunningAnimations.isEmpty()) {
- mHost.notifyAnimationRunningStateChanged(true);
- }
+ mAnimatingTypes |= runner.getTypes();
+ mHost.updateAnimatingTypes(mAnimatingTypes);
mRunningAnimations.add(new RunningAnimation(runner, animationType));
if (DEBUG) Log.d(TAG, "Animation added to runner. useInsetsAnimationThread: "
+ useInsetsAnimationThread);
@@ -1827,7 +1830,7 @@
dispatchAnimationEnd(runningAnimation.runner.getAnimation());
} else {
if (Flags.refactorInsetsController()) {
- if (removedTypes == ime()
+ if ((removedTypes & ime()) != 0
&& control.getAnimationType() == ANIMATION_TYPE_HIDE) {
if (mHost != null) {
// if the (hide) animation is cancelled, the
@@ -1842,9 +1845,11 @@
break;
}
}
- if (mRunningAnimations.isEmpty()) {
- mHost.notifyAnimationRunningStateChanged(false);
+ if (removedTypes > 0) {
+ mAnimatingTypes &= ~removedTypes;
+ mHost.updateAnimatingTypes(mAnimatingTypes);
}
+
onAnimationStateChanged(removedTypes, false /* running */);
}
@@ -1969,14 +1974,6 @@
return animatingTypes;
}
- private @InsetsType int computeAnimatingTypes() {
- int animatingTypes = 0;
- for (int i = 0; i < mRunningAnimations.size(); i++) {
- animatingTypes |= mRunningAnimations.get(i).runner.getTypes();
- }
- return animatingTypes;
- }
-
/**
* Called when finishing setting requested visible types or finishing setting controls.
*
@@ -1989,7 +1986,7 @@
// report its requested visibility at the end of the animation, otherwise we would
// lose the leash, and it would disappear during the animation
// TODO(b/326377046) revisit this part and see if we can make it more general
- typesToReport = mRequestedVisibleTypes | (computeAnimatingTypes() & ime());
+ typesToReport = mRequestedVisibleTypes | (mAnimatingTypes & ime());
} else {
typesToReport = mRequestedVisibleTypes;
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 9498407..7fd7be8 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -2540,11 +2540,12 @@
}
/**
- * Notify the when the running state of a insets animation changed.
+ * Notify the when the animating insets types have changed.
*/
@VisibleForTesting
- public void notifyInsetsAnimationRunningStateChanged(boolean running) {
+ public void updateAnimatingTypes(@InsetsType int animatingTypes) {
if (sToolkitSetFrameRateReadOnlyFlagValue) {
+ boolean running = animatingTypes != 0;
if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
Trace.instant(Trace.TRACE_TAG_VIEW,
TextUtils.formatSimple("notifyInsetsAnimationRunningStateChanged(%s)",
@@ -2552,7 +2553,7 @@
}
mInsetsAnimationRunning = running;
try {
- mWindowSession.notifyInsetsAnimationRunningStateChanged(mWindow, running);
+ mWindowSession.updateAnimatingTypes(mWindow, animatingTypes);
} catch (RemoteException e) {
}
}
diff --git a/core/java/android/view/ViewRootInsetsControllerHost.java b/core/java/android/view/ViewRootInsetsControllerHost.java
index 889acca4..8954df6 100644
--- a/core/java/android/view/ViewRootInsetsControllerHost.java
+++ b/core/java/android/view/ViewRootInsetsControllerHost.java
@@ -171,6 +171,13 @@
}
@Override
+ public void updateAnimatingTypes(@WindowInsets.Type.InsetsType int animatingTypes) {
+ if (mViewRoot != null) {
+ mViewRoot.updateAnimatingTypes(animatingTypes);
+ }
+ }
+
+ @Override
public boolean hasAnimationCallbacks() {
if (mViewRoot.mView == null) {
return false;
@@ -275,13 +282,6 @@
}
@Override
- public void notifyAnimationRunningStateChanged(boolean running) {
- if (mViewRoot != null) {
- mViewRoot.notifyInsetsAnimationRunningStateChanged(running);
- }
- }
-
- @Override
public boolean isHandlingPointerEvent() {
return mViewRoot != null && mViewRoot.isHandlingPointerEvent();
}
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index 72a595d..0a86ff8 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -597,6 +597,11 @@
}
@Override
+ public void updateAnimatingTypes(IWindow window, @InsetsType int animatingTypes) {
+ // NO-OP
+ }
+
+ @Override
public void reportSystemGestureExclusionChanged(android.view.IWindow window,
List<Rect> exclusionRects) {
}
@@ -679,11 +684,6 @@
@NonNull ImeTracker.Token statsToken) {
}
- @Override
- public void notifyInsetsAnimationRunningStateChanged(IWindow window, boolean running) {
- // NO-OP
- }
-
void setParentInterface(@Nullable ISurfaceControlViewHostParent parentInterface) {
IBinder oldInterface = mParentInterface == null ? null : mParentInterface.asBinder();
IBinder newInterface = parentInterface == null ? null : parentInterface.asBinder();
diff --git a/core/java/android/view/inputmethod/flags.aconfig b/core/java/android/view/inputmethod/flags.aconfig
index 16f4114..c81c2bb 100644
--- a/core/java/android/view/inputmethod/flags.aconfig
+++ b/core/java/android/view/inputmethod/flags.aconfig
@@ -196,3 +196,10 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "report_animating_insets_types"
+ namespace: "input_method"
+ description: "Adding animating insets types and report IME visibility at the beginning of hiding"
+ bug: "393049691"
+}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 99fe0cb..5e828ba 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -5211,7 +5211,11 @@
*/
@Nullable
public String getFontVariationSettings() {
- return mTextPaint.getFontVariationSettings();
+ if (Flags.typefaceRedesignReadonly()) {
+ return mTextPaint.getFontVariationOverride();
+ } else {
+ return mTextPaint.getFontVariationSettings();
+ }
}
/**
@@ -5567,10 +5571,10 @@
Math.clamp(400 + mFontWeightAdjustment,
FontStyle.FONT_WEIGHT_MIN, FontStyle.FONT_WEIGHT_MAX)));
}
- mTextPaint.setFontVariationSettings(
+ mTextPaint.setFontVariationOverride(
FontVariationAxis.toFontVariationSettings(axes));
} else {
- mTextPaint.setFontVariationSettings(fontVariationSettings);
+ mTextPaint.setFontVariationOverride(fontVariationSettings);
}
effective = true;
} else {
diff --git a/core/java/com/android/internal/os/BatteryStatsHistory.java b/core/java/com/android/internal/os/BatteryStatsHistory.java
index 85794d4..056a0e8 100644
--- a/core/java/com/android/internal/os/BatteryStatsHistory.java
+++ b/core/java/com/android/internal/os/BatteryStatsHistory.java
@@ -181,6 +181,11 @@
*/
public interface BatteryHistoryStore {
/**
+ * Returns the maximum amount of storage that can be occupied by the battery history story.
+ */
+ int getMaxHistorySize();
+
+ /**
* Returns the table of contents, in the chronological order.
*/
List<BatteryHistoryFragment> getFragments();
@@ -516,6 +521,22 @@
}
/**
+ * Returns a high estimate of how many items are currently included in the battery history.
+ */
+ public int getEstimatedItemCount() {
+ int estimatedBytes = mHistoryBuffer.dataSize();
+ if (mStore != null) {
+ estimatedBytes += mStore.getMaxHistorySize() * 10; // account for the compression ratio
+ }
+ if (mHistoryParcels != null) {
+ for (int i = mHistoryParcels.size() - 1; i >= 0; i--) {
+ estimatedBytes += mHistoryParcels.get(i).dataSize();
+ }
+ }
+ return estimatedBytes / 4; // Minimum size of a history item is 4 bytes
+ }
+
+ /**
* Creates a read-only copy of the battery history. Does not copy the files stored
* in the system directory, so it is not safe while actively writing history.
*/
diff --git a/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java b/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java
index 0d5d876..38398b4 100644
--- a/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java
+++ b/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java
@@ -47,6 +47,8 @@
private boolean mClosed;
private long mBaseMonotonicTime;
private long mBaseTimeUtc;
+ private int mItemIndex = 0;
+ private int mMaxHistoryItems;
public BatteryStatsHistoryIterator(@NonNull BatteryStatsHistory history, long startTimeMs,
long endTimeMs) {
@@ -54,6 +56,7 @@
mStartTimeMs = startTimeMs;
mEndTimeMs = (endTimeMs != MonotonicClock.UNDEFINED) ? endTimeMs : Long.MAX_VALUE;
mHistoryItem.clear();
+ mMaxHistoryItems = history.getEstimatedItemCount();
}
@Override
@@ -80,6 +83,11 @@
private void advance() {
while (true) {
+ if (mItemIndex > mMaxHistoryItems) {
+ Slog.wtfStack(TAG, "Number of battery history items is too large: " + mItemIndex);
+ break;
+ }
+
Parcel p = mBatteryStatsHistory.getNextParcel(mStartTimeMs, mEndTimeMs);
if (p == null) {
break;
@@ -109,6 +117,7 @@
break;
}
if (mHistoryItem.time >= mStartTimeMs) {
+ mItemIndex++;
mNextItemReady = true;
return;
}
diff --git a/core/java/com/android/internal/widget/NotificationProgressBar.java b/core/java/com/android/internal/widget/NotificationProgressBar.java
index c0fe0d1..3472d68 100644
--- a/core/java/com/android/internal/widget/NotificationProgressBar.java
+++ b/core/java/com/android/internal/widget/NotificationProgressBar.java
@@ -555,6 +555,18 @@
mNotificationProgressDrawable.setParts(p.first);
mAdjustedProgressFraction =
(p.second - mTrackerDrawWidth / 2F) / (width - mTrackerDrawWidth);
+
+ mNotificationProgressDrawable.updateEndDotColor(getEndDotColor(fallbackSegments));
+ }
+
+ private int getEndDotColor(List<ProgressStyle.Segment> fallbackSegments) {
+ if (!mProgressModel.isStyledByProgress()) return Color.TRANSPARENT;
+ if (mProgressModel.getProgress() == mProgressModel.getProgressMax()) {
+ return Color.TRANSPARENT;
+ }
+
+ return fallbackSegments == null ? mProgressModel.getSegments().getLast().getColor()
+ : fallbackSegments.getLast().getColor();
}
private void updateTrackerAndBarPos(int w, int h) {
diff --git a/core/java/com/android/internal/widget/NotificationProgressDrawable.java b/core/java/com/android/internal/widget/NotificationProgressDrawable.java
index 30dcc67..b109610 100644
--- a/core/java/com/android/internal/widget/NotificationProgressDrawable.java
+++ b/core/java/com/android/internal/widget/NotificationProgressDrawable.java
@@ -21,6 +21,7 @@
import android.content.res.Resources.Theme;
import android.content.res.TypedArray;
import android.graphics.Canvas;
+import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
@@ -74,6 +75,8 @@
mFillPaint.setStyle(Paint.Style.FILL);
}
+ private @ColorInt int mEndDotColor = Color.TRANSPARENT;
+
private int mAlpha;
public NotificationProgressDrawable() {
@@ -125,6 +128,16 @@
setParts(Arrays.asList(parts));
}
+ /**
+ * Update the color of the end dot. If TRANSPARENT, the dot is not drawn.
+ */
+ public void updateEndDotColor(@ColorInt int endDotColor) {
+ if (mEndDotColor != endDotColor) {
+ mEndDotColor = endDotColor;
+ invalidateSelf();
+ }
+ }
+
@Override
public void draw(@NonNull Canvas canvas) {
final float pointRadius = mState.mPointRadius;
@@ -164,6 +177,18 @@
canvas.drawRoundRect(mPointRectF, cornerRadius, cornerRadius, mFillPaint);
}
}
+
+ if (mEndDotColor != Color.TRANSPARENT) {
+ final float right = (float) getBounds().right;
+ final float dotRadius = mState.mFadedSegmentHeight / 2F;
+ mFillPaint.setColor(mEndDotColor);
+ // Use drawRoundRect instead of drawCircle to ensure alignment with the segment below.
+ mSegRectF.set(
+ Math.round(right - mState.mFadedSegmentHeight), Math.round(centerY - dotRadius),
+ Math.round(right), Math.round(centerY + dotRadius));
+ canvas.drawRoundRect(mSegRectF, mState.mSegmentCornerRadius,
+ mState.mSegmentCornerRadius, mFillPaint);
+ }
}
@Override
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 9acb242..a1961ae 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -268,6 +268,9 @@
72dp (content margin) - 12dp (action padding) - 4dp (button inset) -->
<dimen name="notification_2025_actions_margin_start">56dp</dimen>
+ <!-- Notification action button text size -->
+ <dimen name="notification_2025_action_text_size">16sp</dimen>
+
<!-- The margin on the end of most content views (ignores the expander) -->
<dimen name="notification_content_margin_end">16dp</dimen>
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index 4516e9c..af87af0 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -1195,6 +1195,23 @@
});
}
+ @Test
+ public void testAnimatingTypes() throws Exception {
+ prepareControls();
+
+ final int types = navigationBars() | statusBars();
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ clearInvocations(mTestHost);
+ mController.hide(types);
+ // quickly jump to final state by cancelling it.
+ mController.cancelExistingAnimations();
+ });
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+ verify(mTestHost, times(1)).updateAnimatingTypes(eq(types));
+ verify(mTestHost, times(1)).updateAnimatingTypes(eq(0) /* animatingTypes */);
+ }
+
private void waitUntilNextFrame() throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
Choreographer.getMainThreadInstance().postCallback(Choreographer.CALLBACK_COMMIT,
diff --git a/core/tests/coretests/src/android/view/ViewRootImplTest.java b/core/tests/coretests/src/android/view/ViewRootImplTest.java
index c40137f..f5d1e7a 100644
--- a/core/tests/coretests/src/android/view/ViewRootImplTest.java
+++ b/core/tests/coretests/src/android/view/ViewRootImplTest.java
@@ -1054,7 +1054,7 @@
ViewRootImpl viewRootImpl = mView.getViewRootImpl();
sInstrumentation.runOnMainSync(() -> {
mView.invalidate();
- viewRootImpl.notifyInsetsAnimationRunningStateChanged(true);
+ viewRootImpl.updateAnimatingTypes(Type.systemBars());
mView.invalidate();
});
sInstrumentation.waitForIdleSync();
diff --git a/libs/WindowManager/Shell/res/values/colors.xml b/libs/WindowManager/Shell/res/values/colors.xml
index d754243..8d18f95 100644
--- a/libs/WindowManager/Shell/res/values/colors.xml
+++ b/libs/WindowManager/Shell/res/values/colors.xml
@@ -68,4 +68,8 @@
<color name="desktop_mode_caption_button_on_hover_light">#11000000</color>
<color name="desktop_mode_caption_button_on_hover_dark">#11FFFFFF</color>
<color name="desktop_mode_caption_button">#00000000</color>
+ <color name="tiling_divider_background_light">#C9C7B6</color>
+ <color name="tiling_divider_background_dark">#4A4739</color>
+ <color name="tiling_handle_background_light">#000000</color>
+ <color name="tiling_handle_background_dark">#FFFFFF</color>
</resources>
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java
index 7acad50..2e33253 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java
@@ -22,6 +22,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.TaskInfo;
import android.content.Context;
import android.hardware.display.DisplayManager;
import android.os.SystemProperties;
@@ -287,6 +288,16 @@
}
/**
+ * @return If {@code true} we set opaque background for all freeform tasks to prevent freeform
+ * tasks below from being visible if freeform task window above is translucent.
+ * Otherwise if fluid resize is enabled, add a background to freeform tasks.
+ */
+ public static boolean shouldSetBackground(@NonNull TaskInfo taskInfo) {
+ return taskInfo.isFreeform() && (!DesktopModeStatus.isVeiledResizeEnabled()
+ || DesktopModeFlags.ENABLE_OPAQUE_BACKGROUND_FOR_TRANSPARENT_WINDOWS.isTrue());
+ }
+
+ /**
* @return {@code true} if the app handle should be shown because desktop mode is enabled or
* the device has a large screen
*/
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
index df82091..dd2050a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
@@ -461,6 +461,14 @@
}
}
+ private void setAnimating(boolean imeAnimationOngoing) {
+ int animatingTypes = imeAnimationOngoing ? WindowInsets.Type.ime() : 0;
+ try {
+ mWmService.updateDisplayWindowAnimatingTypes(mDisplayId, animatingTypes);
+ } catch (RemoteException e) {
+ }
+ }
+
private int imeTop(float surfaceOffset, float surfacePositionY) {
// surfaceOffset is already offset by the surface's top inset, so we need to subtract
// the top inset so that the return value is in screen coordinates.
@@ -619,6 +627,9 @@
+ imeTop(hiddenY, defaultY) + "->" + imeTop(shownY, defaultY)
+ " showing:" + (mAnimationDirection == DIRECTION_SHOW));
}
+ if (android.view.inputmethod.Flags.reportAnimatingInsetsTypes()) {
+ setAnimating(true);
+ }
int flags = dispatchStartPositioning(mDisplayId, imeTop(hiddenY, defaultY),
imeTop(shownY, defaultY), mAnimationDirection == DIRECTION_SHOW,
isFloating, t);
@@ -666,6 +677,8 @@
}
if (!android.view.inputmethod.Flags.refactorInsetsController()) {
dispatchEndPositioning(mDisplayId, mCancelled, t);
+ } else if (android.view.inputmethod.Flags.reportAnimatingInsetsTypes()) {
+ setAnimating(false);
}
if (mAnimationDirection == DIRECTION_HIDE && !mCancelled) {
ImeTracker.forLogging().onProgress(mStatsToken,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerHandleView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerHandleView.java
index 6c04e2a..d304e20 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerHandleView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerHandleView.java
@@ -80,7 +80,19 @@
private int mHoveringWidth;
private int mHoveringHeight;
private boolean mIsLeftRightSplit;
+ private boolean mIsSplitScreen;
+ /**
+ * Notifies the divider of ui mode change.
+ *
+ * @param isDarkMode Whether the mode is ui dark mode.
+ */
+ public void onUiModeChange(boolean isDarkMode) {
+ if (!mIsSplitScreen) {
+ mPaint.setColor(getTilingHandleColor(isDarkMode));
+ invalidate();
+ }
+ }
public DividerHandleView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
mPaint.setColor(getResources().getColor(R.color.docked_divider_handle, null));
@@ -103,6 +115,27 @@
mHoveringHeight = mHeight > mWidth ? ((int) (mHeight * 1.5f)) : mHeight;
}
+ /**
+ * Used by tiling infrastructure to specify display light/dark mode and
+ * whether handle colors should be overridden on display mode change in case
+ * of non split screen.
+ * @param isSplitScreen Whether the divider is used by split screen or tiling.
+ * @param isDarkMode Whether the mode is ui dark mode.
+ */
+ public void setup(boolean isSplitScreen, boolean isDarkMode) {
+ mIsSplitScreen = isSplitScreen;
+ if (!mIsSplitScreen) {
+ mPaint.setColor(getTilingHandleColor(isDarkMode));
+ setAlpha(.9f);
+ }
+ }
+
+ private int getTilingHandleColor(Boolean isDarkMode) {
+ return isDarkMode ? getResources().getColor(
+ R.color.tiling_handle_background_dark, null /* theme */) : getResources().getColor(
+ R.color.tiling_handle_background_light, null /* theme */);
+ }
+
/** sets whether it's a left/right or top/bottom split */
public void setIsLeftRightSplit(boolean isLeftRightSplit) {
mIsLeftRightSplit = isLeftRightSplit;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerRoundedCorner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerRoundedCorner.java
index d5aaf75..cf0ecae 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerRoundedCorner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerRoundedCorner.java
@@ -47,15 +47,17 @@
private InvertedRoundedCornerDrawInfo mBottomLeftCorner;
private InvertedRoundedCornerDrawInfo mBottomRightCorner;
private boolean mIsLeftRightSplit;
+ private boolean mIsSplitScreen;
public DividerRoundedCorner(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
mDividerWidth = getResources().getDimensionPixelSize(R.dimen.split_divider_bar_width);
mDividerBarBackground = new Paint();
mDividerBarBackground.setColor(
- getResources().getColor(R.color.split_divider_background, null));
+ getResources().getColor(R.color.split_divider_background, null /* theme */));
mDividerBarBackground.setFlags(Paint.ANTI_ALIAS_FLAG);
mDividerBarBackground.setStyle(Paint.Style.FILL);
+ mIsSplitScreen = false;
}
@Override
@@ -99,7 +101,41 @@
}
/**
+ * Used by tiling infrastructure to specify display light/dark mode and
+ * whether handle colors should be overridden on display mode change in case
+ * of non split screen.
+ *
+ * @param isSplitScreen Whether the divider is used by split screen or tiling.
+ * @param isDarkMode Whether the mode is ui dark mode.
+ */
+ public void setup(boolean isSplitScreen, boolean isDarkMode) {
+ mIsSplitScreen = isSplitScreen;
+ if (!isSplitScreen) {
+ mDividerBarBackground.setColor(getTilingHandleColor(isDarkMode));
+ }
+ }
+
+ /**
+ * Notifies the divider of ui mode change.
+ *
+ * @param isDarkMode Whether the mode is ui dark mode.
+ */
+ public void onUiModeChange(boolean isDarkMode) {
+ if (!mIsSplitScreen) {
+ mDividerBarBackground.setColor(getTilingHandleColor(isDarkMode));
+ invalidate();
+ }
+ }
+
+ private int getTilingHandleColor(boolean isDarkMode) {
+ return isDarkMode ? getResources().getColor(
+ R.color.tiling_divider_background_dark, null /* theme */) : getResources().getColor(
+ R.color.tiling_divider_background_light, null /* theme */);
+ }
+
+ /**
* Set whether the rounded corner is for a left/right split.
+ *
* @param isLeftRightSplit whether it's a left/right split or top/bottom split.
*/
public void setIsLeftRightSplit(boolean isLeftRightSplit) {
@@ -123,7 +159,16 @@
mCornerPosition = cornerPosition;
final RoundedCorner roundedCorner = getDisplay().getRoundedCorner(cornerPosition);
- mRadius = roundedCorner == null ? 0 : roundedCorner.getRadius();
+ if (mIsSplitScreen) {
+ mRadius = roundedCorner == null ? 0 : roundedCorner.getRadius();
+ } else {
+ mRadius = mContext
+ .getResources()
+ .getDimensionPixelSize(
+ com.android.wm.shell.shared.R.dimen
+ .desktop_windowing_freeform_rounded_corner_radius);
+ }
+
// Starts with a filled square, and then subtracting out a circle from the appropriate
// corner.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
index 49510c8..5e8c1fe 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
@@ -61,6 +61,7 @@
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.shared.annotations.ShellBackgroundThread;
import com.android.wm.shell.shared.annotations.ShellMainThread;
+import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHost;
import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHostSupplier;
import com.android.wm.shell.windowdecor.extension.TaskInfoKt;
@@ -247,6 +248,10 @@
relayoutParams.mOccludingCaptionElements.add(controlsElement);
relayoutParams.mCaptionTopPadding = getTopPadding(relayoutParams,
taskInfo.getConfiguration().windowConfiguration.getBounds(), displayInsetsState);
+ // Set opaque background for all freeform tasks to prevent freeform tasks below
+ // from being visible if freeform task window above is translucent.
+ // Otherwise if fluid resize is enabled, add a background to freeform tasks.
+ relayoutParams.mShouldSetBackground = DesktopModeStatus.shouldSetBackground(taskInfo);
}
@SuppressLint("MissingPermission")
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 0d773ec..7ef1a93 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
@@ -558,6 +558,7 @@
} else {
decoration.relayout(taskInfo, taskInfo.isFocused, decoration.mExclusionRegion);
}
+ mDesktopTilingDecorViewModel.onTaskInfoChange(taskInfo);
mActivityOrientationChangeHandler.ifPresent(handler ->
handler.handleActivityOrientationChange(oldTaskInfo, taskInfo));
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
index 6165dbf..30e5c2a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
@@ -1064,6 +1064,10 @@
relayoutParams.mCornerRadius = shouldIgnoreCornerRadius ? INVALID_CORNER_RADIUS :
getCornerRadius(context, relayoutParams.mLayoutResId);
}
+ // Set opaque background for all freeform tasks to prevent freeform tasks below
+ // from being visible if freeform task window above is translucent.
+ // Otherwise if fluid resize is enabled, add a background to freeform tasks.
+ relayoutParams.mShouldSetBackground = DesktopModeStatus.shouldSetBackground(taskInfo);
}
private static int getCornerRadius(@NonNull Context context, int layoutResId) {
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 4002dc5..7baef2b 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
@@ -16,7 +16,6 @@
package com.android.wm.shell.windowdecor;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.content.res.Configuration.DENSITY_DPI_UNDEFINED;
import static android.view.WindowInsets.Type.captionBar;
import static android.view.WindowInsets.Type.mandatorySystemGestures;
@@ -57,7 +56,6 @@
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.desktopmode.DesktopModeEventLogger;
-import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
import com.android.wm.shell.windowdecor.WindowDecoration.RelayoutParams.OccludingCaptionElement;
import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewHostViewContainer;
import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHost;
@@ -504,15 +502,14 @@
startT.show(mTaskSurface);
}
- if (mTaskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM
- && !DesktopModeStatus.isVeiledResizeEnabled()) {
- // When fluid resize is enabled, add a background to freeform tasks
- int backgroundColorInt = mTaskInfo.taskDescription.getBackgroundColor();
+ if (params.mShouldSetBackground) {
+ final int backgroundColorInt = mTaskInfo.taskDescription != null
+ ? mTaskInfo.taskDescription.getBackgroundColor() : Color.BLACK;
mTmpColor[0] = (float) Color.red(backgroundColorInt) / 255.f;
mTmpColor[1] = (float) Color.green(backgroundColorInt) / 255.f;
mTmpColor[2] = (float) Color.blue(backgroundColorInt) / 255.f;
startT.setColor(mTaskSurface, mTmpColor);
- } else if (!DesktopModeStatus.isVeiledResizeEnabled()) {
+ } else {
startT.unsetColor(mTaskSurface);
}
@@ -833,6 +830,7 @@
boolean mSetTaskVisibilityPositionAndCrop;
boolean mHasGlobalFocus;
boolean mShouldSetAppBounds;
+ boolean mShouldSetBackground;
void reset() {
mLayoutResId = Resources.ID_NULL;
@@ -857,6 +855,7 @@
mAsyncViewHost = false;
mHasGlobalFocus = false;
mShouldSetAppBounds = false;
+ mShouldSetBackground = false;
}
boolean hasInputFeatureSpy() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDecorViewModel.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDecorViewModel.kt
index ee5d0e8..e9426d2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDecorViewModel.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDecorViewModel.kt
@@ -137,6 +137,10 @@
}
}
+ fun onTaskInfoChange(taskInfo: RunningTaskInfo) {
+ tilingTransitionHandlerByDisplayId.get(taskInfo.displayId)?.onTaskInfoChange(taskInfo)
+ }
+
override fun onDisplayChange(
displayId: Int,
fromRotation: Int,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManager.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManager.kt
index fbbf1a5..cb45c17 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManager.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManager.kt
@@ -57,6 +57,7 @@
private val transactionSupplier: Supplier<SurfaceControl.Transaction>,
private var dividerBounds: Rect,
private val displayContext: Context,
+ private val isDarkMode: Boolean,
) : WindowlessWindowManager(config, leash, null), DividerMoveCallback, View.OnLayoutChangeListener {
private lateinit var viewHost: SurfaceControlViewHost
private var tilingDividerView: TilingDividerView? = null
@@ -153,7 +154,7 @@
surfaceControlViewHost.setView(dividerView, lp)
val tmpDividerBounds = Rect()
getDividerBounds(tmpDividerBounds)
- dividerView.setup(this, tmpDividerBounds, handleRegionSize)
+ dividerView.setup(this, tmpDividerBounds, handleRegionSize, isDarkMode)
t.setRelativeLayer(leash, relativeLeash, 1)
.setPosition(
leash,
@@ -172,6 +173,11 @@
updateTouchRegion()
}
+ /** Changes divider colour if dark/light mode is toggled. */
+ fun onUiModeChange(isDarkMode: Boolean) {
+ tilingDividerView?.onUiModeChange(isDarkMode)
+ }
+
/** Hides the divider bar. */
fun hideDividerBar() {
if (!dividerShown) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecoration.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecoration.kt
index 9833325..a45df04 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecoration.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecoration.kt
@@ -103,6 +103,7 @@
@VisibleForTesting
var desktopTilingDividerWindowManager: DesktopTilingDividerWindowManager? = null
private lateinit var dividerBounds: Rect
+ private var isDarkMode = false
private var isResizing = false
private var isTilingFocused = false
@@ -129,6 +130,7 @@
val isTiled = destinationBounds != taskInfo.configuration.windowConfiguration.bounds
initTilingApps(resizeMetadata, position, taskInfo)
+ isDarkMode = isTaskInDarkMode(taskInfo)
// Observe drag resizing to break tiling if a task is drag resized.
desktopModeWindowDecoration.addDragResizeListener(this)
@@ -232,6 +234,7 @@
transactionSupplier,
dividerBounds,
displayContext,
+ isDarkMode,
)
}
// a leash to present the divider on top of, without re-parenting.
@@ -356,6 +359,17 @@
transitions.startTransition(TRANSIT_CHANGE, wct, this)
}
+ fun onTaskInfoChange(taskInfo: RunningTaskInfo) {
+ val isCurrentTaskInDarkMode = isTaskInDarkMode(taskInfo)
+ if (isCurrentTaskInDarkMode == isDarkMode || !isTilingManagerInitialised) return
+ isDarkMode = isCurrentTaskInDarkMode
+ desktopTilingDividerWindowManager?.onUiModeChange(isDarkMode)
+ }
+
+ fun isTaskInDarkMode(taskInfo: RunningTaskInfo): Boolean =
+ (taskInfo.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) ==
+ Configuration.UI_MODE_NIGHT_YES
+
override fun startAnimation(
transition: IBinder,
info: TransitionInfo,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/TilingDividerView.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/TilingDividerView.kt
index b8e3b0f..54dcd2d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/TilingDividerView.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/TilingDividerView.kt
@@ -16,6 +16,7 @@
package com.android.wm.shell.windowdecor.tiling
import android.content.Context
+import android.content.res.Configuration
import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.Rect
@@ -85,11 +86,14 @@
dividerMoveCallback: DividerMoveCallback,
dividerBounds: Rect,
handleRegionSize: Size,
+ isDarkMode: Boolean,
) {
callback = dividerMoveCallback
this.dividerBounds.set(dividerBounds)
handle.setIsLeftRightSplit(true)
+ handle.setup(/* isSplitScreen= */ false, isDarkMode)
corners.setIsLeftRightSplit(true)
+ corners.setup(/* isSplitScreen= */ false, isDarkMode)
handleRegionHeight = handleRegionSize.height
handleRegionWidth = handleRegionSize.width
cornersRadius =
@@ -103,6 +107,18 @@
)
}
+ fun onUiModeChange(isDarkMode: Boolean) {
+ handle.onUiModeChange(isDarkMode)
+ corners.onUiModeChange(isDarkMode)
+ paint.color =
+ if (isDarkMode) {
+ resources.getColor(R.color.tiling_divider_background_dark, null /* theme */)
+ } else {
+ resources.getColor(R.color.tiling_divider_background_light, null /* theme */)
+ }
+ invalidate()
+ }
+
override fun onFinishInflate() {
super.onFinishInflate()
dividerBar = requireViewById(R.id.divider_bar)
@@ -112,7 +128,15 @@
resources.getDimensionPixelSize(R.dimen.docked_stack_divider_lift_elevation)
setOnTouchListener(this)
setWillNotDraw(false)
- paint.color = resources.getColor(R.color.split_divider_background, null)
+ paint.color =
+ if (
+ context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK ==
+ Configuration.UI_MODE_NIGHT_YES
+ ) {
+ resources.getColor(R.color.tiling_divider_background_dark, /* theme= */null)
+ } else {
+ resources.getColor(R.color.tiling_divider_background_light, /* theme= */ null)
+ }
paint.isAntiAlias = true
paint.style = Paint.Style.FILL
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatusTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatusTest.kt
index 4082ffd..fb62ba7 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatusTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatusTest.kt
@@ -16,6 +16,7 @@
package com.android.wm.shell.shared.desktopmode
+import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
import android.content.Context
import android.content.res.Resources
import android.platform.test.annotations.DisableFlags
@@ -27,6 +28,7 @@
import com.android.internal.R
import com.android.window.flags.Flags
import com.android.wm.shell.ShellTestCase
+import com.android.wm.shell.util.createTaskInfo
import com.google.common.truth.Truth.assertThat
import org.junit.After
import org.junit.Before
@@ -152,6 +154,70 @@
assertThat(DesktopModeStatus.canEnterDesktopMode(mockContext)).isTrue()
}
+ @EnableFlags(
+ Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE,
+ Flags.FLAG_ENABLE_OPAQUE_BACKGROUND_FOR_TRANSPARENT_WINDOWS,
+ )
+ @Test
+ fun shouldSetBackground_BTWFlagEnabled_freeformTask_returnsTrue() {
+ val freeFormTaskInfo = createTaskInfo(deviceWindowingMode = WINDOWING_MODE_FREEFORM)
+ assertThat(DesktopModeStatus.shouldSetBackground(freeFormTaskInfo)).isTrue()
+ }
+
+ @EnableFlags(
+ Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE,
+ Flags.FLAG_ENABLE_OPAQUE_BACKGROUND_FOR_TRANSPARENT_WINDOWS,
+ )
+ @Test
+ fun shouldSetBackground_BTWFlagEnabled_notFreeformTask_returnsFalse() {
+ val notFreeFormTaskInfo = createTaskInfo()
+ assertThat(DesktopModeStatus.shouldSetBackground(notFreeFormTaskInfo)).isFalse()
+ }
+
+ @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
+ @DisableFlags(Flags.FLAG_ENABLE_OPAQUE_BACKGROUND_FOR_TRANSPARENT_WINDOWS)
+ @Test
+ fun shouldSetBackground_BTWFlagDisabled_freeformTaskAndFluid_returnsTrue() {
+ val freeFormTaskInfo = createTaskInfo(deviceWindowingMode = WINDOWING_MODE_FREEFORM)
+
+ setIsVeiledResizeEnabled(false)
+ assertThat(DesktopModeStatus.shouldSetBackground(freeFormTaskInfo)).isTrue()
+ }
+
+ @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
+ @DisableFlags(Flags.FLAG_ENABLE_OPAQUE_BACKGROUND_FOR_TRANSPARENT_WINDOWS)
+ @Test
+ fun shouldSetBackground_BTWFlagDisabled_freeformTaskAndVeiled_returnsFalse() {
+ val freeFormTaskInfo = createTaskInfo(deviceWindowingMode = WINDOWING_MODE_FREEFORM)
+
+ setIsVeiledResizeEnabled(true)
+ assertThat(DesktopModeStatus.shouldSetBackground(freeFormTaskInfo)).isFalse()
+ }
+
+ @EnableFlags(
+ Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE,
+ Flags.FLAG_ENABLE_OPAQUE_BACKGROUND_FOR_TRANSPARENT_WINDOWS,
+ )
+ @Test
+ fun shouldSetBackground_BTWFlagEnabled_freeformTaskAndFluid_returnsTrue() {
+ val freeFormTaskInfo = createTaskInfo(deviceWindowingMode = WINDOWING_MODE_FREEFORM)
+
+ setIsVeiledResizeEnabled(false)
+ assertThat(DesktopModeStatus.shouldSetBackground(freeFormTaskInfo)).isTrue()
+ }
+
+ @EnableFlags(
+ Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE,
+ Flags.FLAG_ENABLE_OPAQUE_BACKGROUND_FOR_TRANSPARENT_WINDOWS,
+ )
+ @Test
+ fun shouldSetBackground_BTWFlagEnabled_windowModesTask_freeformTaskAndVeiled_returnsTrue() {
+ val freeFormTaskInfo = createTaskInfo(deviceWindowingMode = WINDOWING_MODE_FREEFORM)
+
+ setIsVeiledResizeEnabled(true)
+ assertThat(DesktopModeStatus.shouldSetBackground(freeFormTaskInfo)).isTrue()
+ }
+
@Test
fun isDeviceEligibleForDesktopMode_configDEModeOnAndIntDispHostsDesktop_returnsTrue() {
doReturn(true).whenever(mockResources).getBoolean(eq(R.bool.config_isDesktopModeSupported))
@@ -254,4 +320,11 @@
deviceRestrictions.isAccessible = true
deviceRestrictions.setBoolean(/* obj= */ null, /* z= */ !eligible)
}
+
+ private fun setIsVeiledResizeEnabled(enabled: Boolean) {
+ val deviceRestrictions =
+ DesktopModeStatus::class.java.getDeclaredField("IS_VEILED_RESIZE_ENABLED")
+ deviceRestrictions.isAccessible = true
+ deviceRestrictions.setBoolean(/* obj= */ null, /* z= */ enabled)
+ }
}
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 16c7935..e89a122 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
@@ -321,6 +321,19 @@
}
@Test
+ fun testOnTaskInfoChanged_tilingNotified() {
+ val task = createTask(
+ windowingMode = WINDOWING_MODE_FREEFORM
+ )
+ setUpMockDecorationsForTasks(task)
+
+ onTaskOpening(task)
+ desktopModeWindowDecorViewModel.onTaskInfoChanged(task)
+
+ verify(mockTilingWindowDecoration).onTaskInfoChange(task)
+ }
+
+ @Test
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_IMMERSIVE_HANDLE_HIDING)
fun testInsetsStateChanged_notifiesAllDecorsInDisplay() {
val task1 = createTask(windowingMode = WINDOWING_MODE_FREEFORM, displayId = 1)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
index af01623..a2927fa 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
@@ -24,7 +24,6 @@
import static android.view.WindowInsets.Type.mandatorySystemGestures;
import static android.view.WindowInsets.Type.statusBars;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.android.wm.shell.MockSurfaceControlHelper.createMockSurfaceControlBuilder;
import static com.android.wm.shell.MockSurfaceControlHelper.createMockSurfaceControlTransaction;
@@ -51,7 +50,6 @@
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import static org.mockito.quality.Strictness.LENIENT;
import android.annotation.NonNull;
import android.app.ActivityManager;
@@ -79,13 +77,11 @@
import androidx.test.filters.SmallTest;
-import com.android.dx.mockito.inline.extended.StaticMockitoSession;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.TestRunningTaskInfoBuilder;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.desktopmode.DesktopModeEventLogger;
-import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
import com.android.wm.shell.tests.R;
import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewContainer;
import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHost;
@@ -564,12 +560,7 @@
}
@Test
- public void testRelayout_fluidResizeEnabled_freeformTask_setTaskSurfaceColor() {
- StaticMockitoSession mockitoSession = mockitoSession().mockStatic(
- DesktopModeStatus.class).strictness(
- LENIENT).startMocking();
- when(DesktopModeStatus.isVeiledResizeEnabled()).thenReturn(false);
-
+ public void testRelayout_shouldSetBackground_freeformTask_setTaskSurfaceColor() {
final Display defaultDisplay = mock(Display.class);
doReturn(defaultDisplay).when(mMockDisplayController)
.getDisplay(Display.DEFAULT_DISPLAY);
@@ -595,11 +586,10 @@
.build();
final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo);
+ mRelayoutParams.mShouldSetBackground = true;
windowDecor.relayout(taskInfo, true /* hasGlobalFocus */);
verify(mMockSurfaceControlStartT).setColor(mMockTaskSurface, new float[]{1.f, 1.f, 0.f});
-
- mockitoSession.finishMocking();
}
@Test
@@ -627,11 +617,7 @@
}
@Test
- public void testRelayout_fluidResizeEnabled_fullscreenTask_clearTaskSurfaceColor() {
- StaticMockitoSession mockitoSession = mockitoSession().mockStatic(
- DesktopModeStatus.class).strictness(LENIENT).startMocking();
- when(DesktopModeStatus.isVeiledResizeEnabled()).thenReturn(false);
-
+ public void testRelayout_shouldNotSetBackground_fullscreenTask_clearTaskSurfaceColor() {
final Display defaultDisplay = mock(Display.class);
doReturn(defaultDisplay).when(mMockDisplayController)
.getDisplay(Display.DEFAULT_DISPLAY);
@@ -655,12 +641,11 @@
.setWindowingMode(WINDOWING_MODE_FULLSCREEN)
.build();
final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo);
+ mRelayoutParams.mIsCaptionVisible = false;
windowDecor.relayout(taskInfo, true /* hasGlobalFocus */);
verify(mMockSurfaceControlStartT).unsetColor(mMockTaskSurface);
-
- mockitoSession.finishMocking();
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManagerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManagerTest.kt
index 121e0e9..8442056 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManagerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManagerTest.kt
@@ -81,6 +81,7 @@
transactionSupplierMock,
BOUNDS,
context,
+ /* isDarkMode= */ true
)
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/TilingDividerViewTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/TilingDividerViewTest.kt
index 9a9d05a..9a3d5d8 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/TilingDividerViewTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/TilingDividerViewTest.kt
@@ -60,7 +60,7 @@
tilingDividerView =
LayoutInflater.from(mContext).inflate(R.layout.tiling_split_divider, /* root= */ null)
as TilingDividerView
- tilingDividerView.setup(dividerMoveCallbackMock, DIVIDER_BOUNDS, HANDLE_SIZE)
+ tilingDividerView.setup(dividerMoveCallbackMock, DIVIDER_BOUNDS, HANDLE_SIZE, true)
tilingDividerView.handleY = 0..1500
}
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 38ac8ab..a892e88 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -141,6 +141,7 @@
"libsync",
"libui",
"aconfig_text_flags_c_lib",
+ "aconfig_view_accessibility_flags_c_lib",
"server_configurable_flags",
"libaconfig_storage_read_api_cc",
"libgraphicsenv",
diff --git a/libs/hwui/FeatureFlags.h b/libs/hwui/FeatureFlags.h
index 5f84f47..5ceb97c 100644
--- a/libs/hwui/FeatureFlags.h
+++ b/libs/hwui/FeatureFlags.h
@@ -18,6 +18,7 @@
#define ANDROID_HWUI_FEATURE_FLAGS_H
#ifdef __ANDROID__
+#include <android_view_accessibility.h>
#include <com_android_text_flags.h>
#endif // __ANDROID__
@@ -44,6 +45,19 @@
} // namespace text_feature
+namespace view_accessibility_flags {
+
+inline bool force_invert_color() {
+#ifdef __ANDROID__
+ static bool flag = android::view::accessibility::force_invert_color();
+ return flag;
+#else
+ return true;
+#endif // __ANDROID__
+}
+
+} // namespace view_accessibility_flags
+
} // namespace android
#endif // ANDROID_HWUI_FEATURE_FLAGS_H
diff --git a/media/java/android/media/flags/projection.aconfig b/media/java/android/media/flags/projection.aconfig
index 6d4f0b4..846448b 100644
--- a/media/java/android/media/flags/projection.aconfig
+++ b/media/java/android/media/flags/projection.aconfig
@@ -39,3 +39,12 @@
}
is_exported: true
}
+
+flag {
+ namespace: "media_projection"
+ name: "app_content_sharing"
+ description: "Enable apps to share some sub-surface"
+ bug: "379989921"
+ is_exported: true
+}
+
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/theme/AndroidColorScheme.kt b/packages/SystemUI/compose/core/src/com/android/compose/theme/AndroidColorScheme.kt
index ed144bd..375dade 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/theme/AndroidColorScheme.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/theme/AndroidColorScheme.kt
@@ -78,6 +78,10 @@
val underSurface: Color,
val weatherTemp: Color,
val widgetBackground: Color,
+ val surfaceEffect0: Color,
+ val surfaceEffect1: Color,
+ val surfaceEffect2: Color,
+ val surfaceEffect3: Color,
) {
companion object {
internal fun color(context: Context, @ColorRes id: Int): Color {
@@ -123,6 +127,10 @@
underSurface = color(context, R.color.customColorUnderSurface),
weatherTemp = color(context, R.color.customColorWeatherTemp),
widgetBackground = color(context, R.color.customColorWidgetBackground),
+ surfaceEffect0 = color(context, R.color.surface_effect_0),
+ surfaceEffect1 = color(context, R.color.surface_effect_1),
+ surfaceEffect2 = color(context, R.color.surface_effect_2),
+ surfaceEffect3 = color(context, R.color.surface_effect_3),
)
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/common/data/repository/PackageInstallerMonitorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/common/data/repository/PackageInstallerMonitorTest.kt
index 781e416..ede29d8 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/common/data/repository/PackageInstallerMonitorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/common/data/repository/PackageInstallerMonitorTest.kt
@@ -26,6 +26,9 @@
import com.android.systemui.common.shared.model.PackageInstallSession
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.kosmos.backgroundScope
+import com.android.systemui.kosmos.collectLastValue
+import com.android.systemui.kosmos.runTest
import com.android.systemui.kosmos.testScope
import com.android.systemui.log.logcatLogBuffer
import com.android.systemui.testKosmos
@@ -173,6 +176,58 @@
}
@Test
+ fun onCreateUpdatedSession_ignoreNullPackageNameSessions() =
+ kosmos.runTest {
+ val nullPackageSession =
+ SessionInfo().apply {
+ sessionId = 1
+ appPackageName = null
+ appIcon = icon1
+ }
+
+ val wellFormedSession =
+ SessionInfo().apply {
+ sessionId = 2
+ appPackageName = "pkg_name"
+ appIcon = icon2
+ }
+
+ defaultSessions = listOf(wellFormedSession)
+
+ whenever(packageInstaller.allSessions).thenReturn(defaultSessions)
+ whenever(packageInstaller.getSessionInfo(1)).thenReturn(nullPackageSession)
+ whenever(packageInstaller.getSessionInfo(2)).thenReturn(wellFormedSession)
+
+ val packageInstallerMonitor =
+ PackageInstallerMonitor(
+ handler,
+ backgroundScope,
+ logcatLogBuffer("PackageInstallerRepositoryImplTest"),
+ packageInstaller,
+ )
+
+ val sessions by collectLastValue(packageInstallerMonitor.installSessionsForPrimaryUser)
+
+ // Verify flow updated with the new session
+ assertThat(sessions)
+ .comparingElementsUsing(represents)
+ .containsExactlyElementsIn(defaultSessions)
+
+ val callback =
+ withArgCaptor<PackageInstaller.SessionCallback> {
+ verify(packageInstaller).registerSessionCallback(capture(), eq(handler))
+ }
+
+ // New session added
+ callback.onCreated(nullPackageSession.sessionId)
+
+ // Verify flow updated with the new session
+ assertThat(sessions)
+ .comparingElementsUsing(represents)
+ .containsExactlyElementsIn(defaultSessions)
+ }
+
+ @Test
fun installSessions_newSessionsAreAdded() =
testScope.runTest {
val installSessions by collectLastValue(underTest.installSessionsForPrimaryUser)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
index 1899b7d..0e5e333 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
@@ -423,5 +423,15 @@
@Override
public void destroy() {}
+
+ @Override
+ public boolean isDestroyed() {
+ return false;
+ }
+
+ @Override
+ public int getCurrentTileUser() {
+ return 0;
+ }
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/TilesAvailabilityInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/TilesAvailabilityInteractorTest.kt
index 5a58597..67fb100 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/TilesAvailabilityInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/TilesAvailabilityInteractorTest.kt
@@ -56,166 +56,178 @@
private val createdTiles = mutableListOf<FakeQSTile>()
- private val kosmos = testKosmos().apply {
- tileAvailabilityInteractorsMap = buildMap {
- put(AIRPLANE_MODE_TILE_SPEC, QSTileAvailabilityInteractor.AlwaysAvailableInteractor)
- put(WORK_MODE_TILE_SPEC, FakeTileAvailabilityInteractor(
- mapOf(
- fakeUserRepository.getSelectedUserInfo().id to flowOf(true),
- ).withDefault { flowOf(false) }
- ))
- put(HOTSPOT_TILE_SPEC, FakeTileAvailabilityInteractor(
- emptyMap<Int, Flow<Boolean>>().withDefault { flowOf(false) }
- ))
- }
+ private val kosmos =
+ testKosmos().apply {
+ tileAvailabilityInteractorsMap = buildMap {
+ put(AIRPLANE_MODE_TILE_SPEC, QSTileAvailabilityInteractor.AlwaysAvailableInteractor)
+ put(
+ WORK_MODE_TILE_SPEC,
+ FakeTileAvailabilityInteractor(
+ mapOf(fakeUserRepository.getSelectedUserInfo().id to flowOf(true))
+ .withDefault { flowOf(false) }
+ ),
+ )
+ put(
+ HOTSPOT_TILE_SPEC,
+ FakeTileAvailabilityInteractor(
+ emptyMap<Int, Flow<Boolean>>().withDefault { flowOf(false) }
+ ),
+ )
+ }
- qsTileFactory = constantFactory(
- tilesForCreator(
+ qsTileFactory =
+ constantFactory(
+ tilesForCreator(
userRepository.getSelectedUserInfo().id,
mapOf(
- AIRPLANE_MODE_TILE_SPEC to false,
- WORK_MODE_TILE_SPEC to false,
- HOTSPOT_TILE_SPEC to true,
- INTERNET_TILE_SPEC to true,
- FLASHLIGHT_TILE_SPEC to false,
- )
+ AIRPLANE_MODE_TILE_SPEC to false,
+ WORK_MODE_TILE_SPEC to false,
+ HOTSPOT_TILE_SPEC to true,
+ INTERNET_TILE_SPEC to true,
+ FLASHLIGHT_TILE_SPEC to false,
+ ),
+ )
)
- )
- }
+ }
private val underTest by lazy { kosmos.tilesAvailabilityInteractor }
@Test
@DisableFlags(FLAG_QS_NEW_TILES)
- fun flagOff_usesAvailabilityFromFactoryTiles() = with(kosmos) {
- testScope.runTest {
- val unavailableTiles = underTest.getUnavailableTiles(
- setOf(
- AIRPLANE_MODE_TILE_SPEC,
- WORK_MODE_TILE_SPEC,
- HOTSPOT_TILE_SPEC,
- INTERNET_TILE_SPEC,
- FLASHLIGHT_TILE_SPEC,
- ).map(TileSpec::create)
- )
- assertThat(unavailableTiles).isEqualTo(setOf(
- AIRPLANE_MODE_TILE_SPEC,
- WORK_MODE_TILE_SPEC,
- FLASHLIGHT_TILE_SPEC,
- ).mapTo(mutableSetOf(), TileSpec::create))
- }
- }
-
- @Test
- fun tileCannotBeCreated_isUnavailable() = with(kosmos) {
- testScope.runTest {
- val badSpec = TileSpec.create("unknown")
- val unavailableTiles = underTest.getUnavailableTiles(
- setOf(
- badSpec
+ fun flagOff_usesAvailabilityFromFactoryTiles() =
+ with(kosmos) {
+ testScope.runTest {
+ val unavailableTiles =
+ underTest.getUnavailableTiles(
+ setOf(
+ AIRPLANE_MODE_TILE_SPEC,
+ WORK_MODE_TILE_SPEC,
+ HOTSPOT_TILE_SPEC,
+ INTERNET_TILE_SPEC,
+ FLASHLIGHT_TILE_SPEC,
+ )
+ .map(TileSpec::create)
)
- )
- assertThat(unavailableTiles).contains(badSpec)
+ assertThat(unavailableTiles)
+ .isEqualTo(
+ setOf(AIRPLANE_MODE_TILE_SPEC, WORK_MODE_TILE_SPEC, FLASHLIGHT_TILE_SPEC)
+ .mapTo(mutableSetOf(), TileSpec::create)
+ )
+ }
}
- }
+
+ @Test
+ fun tileCannotBeCreated_isUnavailable() =
+ with(kosmos) {
+ testScope.runTest {
+ val badSpec = TileSpec.create("unknown")
+ val unavailableTiles = underTest.getUnavailableTiles(setOf(badSpec))
+ assertThat(unavailableTiles).contains(badSpec)
+ }
+ }
@Test
@EnableFlags(FLAG_QS_NEW_TILES)
- fun flagOn_defaultsToInteractorTiles_usesFactoryForOthers() = with(kosmos) {
- testScope.runTest {
- val unavailableTiles = underTest.getUnavailableTiles(
+ fun flagOn_defaultsToInteractorTiles_usesFactoryForOthers() =
+ with(kosmos) {
+ testScope.runTest {
+ val unavailableTiles =
+ underTest.getUnavailableTiles(
+ setOf(
+ AIRPLANE_MODE_TILE_SPEC,
+ WORK_MODE_TILE_SPEC,
+ HOTSPOT_TILE_SPEC,
+ INTERNET_TILE_SPEC,
+ FLASHLIGHT_TILE_SPEC,
+ )
+ .map(TileSpec::create)
+ )
+ assertThat(unavailableTiles)
+ .isEqualTo(
+ setOf(HOTSPOT_TILE_SPEC, FLASHLIGHT_TILE_SPEC)
+ .mapTo(mutableSetOf(), TileSpec::create)
+ )
+ }
+ }
+
+ @Test
+ @EnableFlags(FLAG_QS_NEW_TILES)
+ fun flagOn_defaultsToInteractorTiles_usesFactoryForOthers_userChange() =
+ with(kosmos) {
+ testScope.runTest {
+ fakeUserRepository.asMainUser()
+ val unavailableTiles =
+ underTest.getUnavailableTiles(
+ setOf(
+ AIRPLANE_MODE_TILE_SPEC,
+ WORK_MODE_TILE_SPEC,
+ HOTSPOT_TILE_SPEC,
+ INTERNET_TILE_SPEC,
+ FLASHLIGHT_TILE_SPEC,
+ )
+ .map(TileSpec::create)
+ )
+ assertThat(unavailableTiles)
+ .isEqualTo(
+ setOf(WORK_MODE_TILE_SPEC, HOTSPOT_TILE_SPEC, FLASHLIGHT_TILE_SPEC)
+ .mapTo(mutableSetOf(), TileSpec::create)
+ )
+ }
+ }
+
+ @Test
+ @EnableFlags(FLAG_QS_NEW_TILES)
+ fun flagOn_onlyNeededTilesAreCreated_andThenDestroyed() =
+ with(kosmos) {
+ testScope.runTest {
+ underTest.getUnavailableTiles(
setOf(
AIRPLANE_MODE_TILE_SPEC,
WORK_MODE_TILE_SPEC,
HOTSPOT_TILE_SPEC,
INTERNET_TILE_SPEC,
FLASHLIGHT_TILE_SPEC,
- ).map(TileSpec::create)
- )
- assertThat(unavailableTiles).isEqualTo(setOf(
- HOTSPOT_TILE_SPEC,
- FLASHLIGHT_TILE_SPEC,
- ).mapTo(mutableSetOf(), TileSpec::create))
- }
- }
-
- @Test
- @EnableFlags(FLAG_QS_NEW_TILES)
- fun flagOn_defaultsToInteractorTiles_usesFactoryForOthers_userChange() = with(kosmos) {
- testScope.runTest {
- fakeUserRepository.asMainUser()
- val unavailableTiles = underTest.getUnavailableTiles(
- setOf(
- AIRPLANE_MODE_TILE_SPEC,
- WORK_MODE_TILE_SPEC,
- HOTSPOT_TILE_SPEC,
- INTERNET_TILE_SPEC,
- FLASHLIGHT_TILE_SPEC,
- ).map(TileSpec::create)
- )
- assertThat(unavailableTiles).isEqualTo(setOf(
- WORK_MODE_TILE_SPEC,
- HOTSPOT_TILE_SPEC,
- FLASHLIGHT_TILE_SPEC,
- ).mapTo(mutableSetOf(), TileSpec::create))
- }
- }
-
- @Test
- @EnableFlags(FLAG_QS_NEW_TILES)
- fun flagOn_onlyNeededTilesAreCreated_andThenDestroyed() = with(kosmos) {
- testScope.runTest {
- underTest.getUnavailableTiles(
- setOf(
- AIRPLANE_MODE_TILE_SPEC,
- WORK_MODE_TILE_SPEC,
- HOTSPOT_TILE_SPEC,
- INTERNET_TILE_SPEC,
- FLASHLIGHT_TILE_SPEC,
- ).map(TileSpec::create)
- )
- assertThat(createdTiles.map { it.tileSpec })
+ )
+ .map(TileSpec::create)
+ )
+ assertThat(createdTiles.map { it.tileSpec })
.containsExactly(INTERNET_TILE_SPEC, FLASHLIGHT_TILE_SPEC)
- assertThat(createdTiles.all { it.destroyed }).isTrue()
+ assertThat(createdTiles.all { it.isDestroyed }).isTrue()
+ }
}
- }
@Test
@DisableFlags(FLAG_QS_NEW_TILES)
- fun flagOn_TilesAreCreatedAndThenDestroyed() = with(kosmos) {
- testScope.runTest {
- val allTiles = setOf(
- AIRPLANE_MODE_TILE_SPEC,
- WORK_MODE_TILE_SPEC,
- HOTSPOT_TILE_SPEC,
- INTERNET_TILE_SPEC,
- FLASHLIGHT_TILE_SPEC,
- )
- underTest.getUnavailableTiles(allTiles.map(TileSpec::create))
- assertThat(createdTiles.map { it.tileSpec })
- .containsExactlyElementsIn(allTiles)
- assertThat(createdTiles.all { it.destroyed }).isTrue()
+ fun flagOn_TilesAreCreatedAndThenDestroyed() =
+ with(kosmos) {
+ testScope.runTest {
+ val allTiles =
+ setOf(
+ AIRPLANE_MODE_TILE_SPEC,
+ WORK_MODE_TILE_SPEC,
+ HOTSPOT_TILE_SPEC,
+ INTERNET_TILE_SPEC,
+ FLASHLIGHT_TILE_SPEC,
+ )
+ underTest.getUnavailableTiles(allTiles.map(TileSpec::create))
+ assertThat(createdTiles.map { it.tileSpec }).containsExactlyElementsIn(allTiles)
+ assertThat(createdTiles.all { it.isDestroyed }).isTrue()
+ }
}
- }
-
private fun constantFactory(creatorTiles: Set<FakeQSTile>): QSFactory {
return FakeQSFactory { spec ->
- creatorTiles.firstOrNull { it.tileSpec == spec }?.also {
- createdTiles.add(it)
- }
+ creatorTiles.firstOrNull { it.tileSpec == spec }?.also { createdTiles.add(it) }
}
}
companion object {
private fun tilesForCreator(
- user: Int,
- specAvailabilities: Map<String, Boolean>
+ user: Int,
+ specAvailabilities: Map<String, Boolean>,
): Set<FakeQSTile> {
return specAvailabilities.mapTo(mutableSetOf()) {
- FakeQSTile(user, it.value).apply {
- tileSpec = it.key
- }
+ FakeQSTile(user, it.value).apply { tileSpec = it.key }
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt
index 9b50f1b..c308976 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt
@@ -17,10 +17,10 @@
package com.android.systemui.qs.pipeline.domain.interactor
import android.content.ComponentName
-import android.content.Context
import android.content.Intent
import android.content.pm.UserInfo
import android.os.UserHandle
+import android.platform.test.annotations.EnableFlags
import android.service.quicksettings.Tile
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -28,653 +28,702 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.dump.nano.SystemUIProtoDump
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.runTest
+import com.android.systemui.kosmos.testScope
import com.android.systemui.plugins.qs.QSTile
import com.android.systemui.plugins.qs.QSTile.BooleanState
import com.android.systemui.plugins.qs.TileDetailsViewModel
import com.android.systemui.qs.FakeQSFactory
import com.android.systemui.qs.FakeQSTile
import com.android.systemui.qs.external.CustomTile
-import com.android.systemui.qs.external.CustomTileStatePersister
import com.android.systemui.qs.external.TileLifecycleManager
import com.android.systemui.qs.external.TileServiceKey
-import com.android.systemui.qs.pipeline.data.repository.CustomTileAddedRepository
-import com.android.systemui.qs.pipeline.data.repository.FakeCustomTileAddedRepository
-import com.android.systemui.qs.pipeline.data.repository.FakeInstalledTilesComponentRepository
-import com.android.systemui.qs.pipeline.data.repository.FakeTileSpecRepository
-import com.android.systemui.qs.pipeline.data.repository.MinimumTilesFixedRepository
-import com.android.systemui.qs.pipeline.data.repository.TileSpecRepository
+import com.android.systemui.qs.external.customTileStatePersister
+import com.android.systemui.qs.external.tileLifecycleManagerFactory
+import com.android.systemui.qs.pipeline.data.repository.customTileAddedRepository
+import com.android.systemui.qs.pipeline.data.repository.fakeInstalledTilesRepository
+import com.android.systemui.qs.pipeline.data.repository.tileSpecRepository
import com.android.systemui.qs.pipeline.domain.model.TileModel
-import com.android.systemui.qs.pipeline.shared.QSPipelineFlagsRepository
import com.android.systemui.qs.pipeline.shared.TileSpec
import com.android.systemui.qs.pipeline.shared.logging.QSPipelineLogger
-import com.android.systemui.qs.tiles.di.NewQSTileFactory
+import com.android.systemui.qs.pipeline.shared.logging.qsLogger
+import com.android.systemui.qs.qsTileFactory
+import com.android.systemui.qs.tiles.di.newQSTileFactory
import com.android.systemui.qs.toProto
-import com.android.systemui.retail.data.repository.FakeRetailModeRepository
-import com.android.systemui.settings.UserTracker
-import com.android.systemui.user.data.repository.FakeUserRepository
+import com.android.systemui.settings.fakeUserTracker
+import com.android.systemui.testKosmos
+import com.android.systemui.user.data.repository.fakeUserRepository
+import com.android.systemui.user.data.repository.userRepository
import com.android.systemui.util.mockito.any
-import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import com.google.protobuf.nano.MessageNano
-import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
-import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.anyString
-import org.mockito.Mock
import org.mockito.Mockito.inOrder
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.mock
+@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(AndroidJUnit4::class)
+@EnableFlags(FLAG_QS_NEW_TILES)
class CurrentTilesInteractorImplTest : SysuiTestCase() {
- private val tileSpecRepository: TileSpecRepository = FakeTileSpecRepository()
- private val userRepository = FakeUserRepository()
- private val installedTilesPackageRepository = FakeInstalledTilesComponentRepository()
- private val tileFactory = FakeQSFactory(::tileCreator)
- private val customTileAddedRepository: CustomTileAddedRepository =
- FakeCustomTileAddedRepository()
- private val pipelineFlags = QSPipelineFlagsRepository()
- private val tileLifecycleManagerFactory = TLMFactory()
- private val minimumTilesRepository = MinimumTilesFixedRepository()
- private val retailModeRepository = FakeRetailModeRepository()
-
- @Mock private lateinit var customTileStatePersister: CustomTileStatePersister
-
- @Mock private lateinit var userTracker: UserTracker
-
- @Mock private lateinit var logger: QSPipelineLogger
-
- @Mock private lateinit var newQSTileFactory: NewQSTileFactory
-
- private val testDispatcher = StandardTestDispatcher()
- private val testScope = TestScope(testDispatcher)
+ private val kosmos =
+ testKosmos().apply {
+ qsTileFactory = FakeQSFactory { tileCreator(it) }
+ fakeUserTracker.set(listOf(USER_INFO_0), 0)
+ fakeUserRepository.setUserInfos(listOf(USER_INFO_0, USER_INFO_1))
+ tileLifecycleManagerFactory = TLMFactory()
+ newQSTileFactory = mock()
+ qsLogger = mock()
+ }
private val unavailableTiles = mutableSetOf("e")
- private lateinit var underTest: CurrentTilesInteractorImpl
-
- @Before
- fun setup() {
- MockitoAnnotations.initMocks(this)
-
- mSetFlagsRule.enableFlags(FLAG_QS_NEW_TILES)
-
- userRepository.setUserInfos(listOf(USER_INFO_0, USER_INFO_1))
-
- setUserTracker(0)
-
- underTest =
- CurrentTilesInteractorImpl(
- tileSpecRepository = tileSpecRepository,
- installedTilesComponentRepository = installedTilesPackageRepository,
- userRepository = userRepository,
- minimumTilesRepository = minimumTilesRepository,
- retailModeRepository = retailModeRepository,
- customTileStatePersister = customTileStatePersister,
- tileFactory = tileFactory,
- newQSTileFactory = { newQSTileFactory },
- customTileAddedRepository = customTileAddedRepository,
- tileLifecycleManagerFactory = tileLifecycleManagerFactory,
- userTracker = userTracker,
- mainDispatcher = testDispatcher,
- backgroundDispatcher = testDispatcher,
- scope = testScope.backgroundScope,
- logger = logger,
- featureFlags = pipelineFlags,
- )
- }
+ private val underTest = kosmos.currentTilesInteractor
@Test
fun initialState() =
- testScope.runTest(USER_INFO_0) {
- assertThat(underTest.currentTiles.value).isEmpty()
- assertThat(underTest.currentQSTiles).isEmpty()
- assertThat(underTest.currentTilesSpecs).isEmpty()
- assertThat(underTest.userId.value).isEqualTo(0)
- assertThat(underTest.userContext.value.userId).isEqualTo(0)
+ with(kosmos) {
+ testScope.runTest(USER_INFO_0) {
+ assertThat(underTest.currentTiles.value).isEmpty()
+ assertThat(underTest.currentQSTiles).isEmpty()
+ assertThat(underTest.currentTilesSpecs).isEmpty()
+ assertThat(underTest.userId.value).isEqualTo(0)
+ assertThat(underTest.userContext.value.userId).isEqualTo(0)
+ }
}
@Test
fun correctTiles() =
- testScope.runTest(USER_INFO_0) {
- val tiles by collectLastValue(underTest.currentTiles)
+ with(kosmos) {
+ testScope.runTest(USER_INFO_0) {
+ val tiles by collectLastValue(underTest.currentTiles)
- val specs =
- listOf(
- TileSpec.create("a"),
- TileSpec.create("e"),
- CUSTOM_TILE_SPEC,
- TileSpec.create("d"),
- TileSpec.create("non_existent"),
- )
- tileSpecRepository.setTiles(USER_INFO_0.id, specs)
+ val specs =
+ listOf(
+ TileSpec.create("a"),
+ TileSpec.create("e"),
+ CUSTOM_TILE_SPEC,
+ TileSpec.create("d"),
+ TileSpec.create("non_existent"),
+ )
+ tileSpecRepository.setTiles(USER_INFO_0.id, specs)
- // check each tile
+ // check each tile
- // Tile a
- val tile0 = tiles!![0]
- assertThat(tile0.spec).isEqualTo(specs[0])
- assertThat(tile0.tile.tileSpec).isEqualTo(specs[0].spec)
- assertThat(tile0.tile).isInstanceOf(FakeQSTile::class.java)
- assertThat(tile0.tile.isAvailable).isTrue()
+ // Tile a
+ val tile0 = tiles!![0]
+ assertThat(tile0.spec).isEqualTo(specs[0])
+ assertThat(tile0.tile.tileSpec).isEqualTo(specs[0].spec)
+ assertThat(tile0.tile).isInstanceOf(FakeQSTile::class.java)
+ assertThat(tile0.tile.isAvailable).isTrue()
- // Tile e is not available and is not in the list
+ // Tile e is not available and is not in the list
- // Custom Tile
- val tile1 = tiles!![1]
- assertThat(tile1.spec).isEqualTo(specs[2])
- assertThat(tile1.tile.tileSpec).isEqualTo(specs[2].spec)
- assertThat(tile1.tile).isInstanceOf(CustomTile::class.java)
- assertThat(tile1.tile.isAvailable).isTrue()
+ // Custom Tile
+ val tile1 = tiles!![1]
+ assertThat(tile1.spec).isEqualTo(specs[2])
+ assertThat(tile1.tile.tileSpec).isEqualTo(specs[2].spec)
+ assertThat(tile1.tile).isInstanceOf(CustomTile::class.java)
+ assertThat(tile1.tile.isAvailable).isTrue()
- // Tile d
- val tile2 = tiles!![2]
- assertThat(tile2.spec).isEqualTo(specs[3])
- assertThat(tile2.tile.tileSpec).isEqualTo(specs[3].spec)
- assertThat(tile2.tile).isInstanceOf(FakeQSTile::class.java)
- assertThat(tile2.tile.isAvailable).isTrue()
+ // Tile d
+ val tile2 = tiles!![2]
+ assertThat(tile2.spec).isEqualTo(specs[3])
+ assertThat(tile2.tile.tileSpec).isEqualTo(specs[3].spec)
+ assertThat(tile2.tile).isInstanceOf(FakeQSTile::class.java)
+ assertThat(tile2.tile.isAvailable).isTrue()
- // Tile non-existent shouldn't be created. Therefore, only 3 tiles total
- assertThat(tiles?.size).isEqualTo(3)
+ // Tile non-existent shouldn't be created. Therefore, only 3 tiles total
+ assertThat(tiles?.size).isEqualTo(3)
+ }
}
@Test
fun logTileCreated() =
- testScope.runTest(USER_INFO_0) {
- val specs = listOf(TileSpec.create("a"), CUSTOM_TILE_SPEC)
- tileSpecRepository.setTiles(USER_INFO_0.id, specs)
- runCurrent()
+ with(kosmos) {
+ testScope.runTest(USER_INFO_0) {
+ val specs = listOf(TileSpec.create("a"), CUSTOM_TILE_SPEC)
+ tileSpecRepository.setTiles(USER_INFO_0.id, specs)
+ runCurrent()
- specs.forEach { verify(logger).logTileCreated(it) }
+ specs.forEach { verify(qsLogger).logTileCreated(it) }
+ }
}
@Test
fun logTileNotFoundInFactory() =
- testScope.runTest(USER_INFO_0) {
- val specs = listOf(TileSpec.create("non_existing"))
- tileSpecRepository.setTiles(USER_INFO_0.id, specs)
- runCurrent()
+ with(kosmos) {
+ testScope.runTest(USER_INFO_0) {
+ val specs = listOf(TileSpec.create("non_existing"))
+ tileSpecRepository.setTiles(USER_INFO_0.id, specs)
+ runCurrent()
- verify(logger, never()).logTileCreated(any())
- verify(logger).logTileNotFoundInFactory(specs[0])
+ verify(qsLogger, never()).logTileCreated(any())
+ verify(qsLogger).logTileNotFoundInFactory(specs[0])
+ }
}
@Test
fun tileNotAvailableDestroyed_logged() =
- testScope.runTest(USER_INFO_0) {
- val specs = listOf(TileSpec.create("e"))
- tileSpecRepository.setTiles(USER_INFO_0.id, specs)
- runCurrent()
+ with(kosmos) {
+ testScope.runTest(USER_INFO_0) {
+ val specs = listOf(TileSpec.create("e"))
+ tileSpecRepository.setTiles(USER_INFO_0.id, specs)
+ runCurrent()
- verify(logger, never()).logTileCreated(any())
- verify(logger)
- .logTileDestroyed(
- specs[0],
- QSPipelineLogger.TileDestroyedReason.NEW_TILE_NOT_AVAILABLE,
- )
+ verify(qsLogger, never()).logTileCreated(any())
+ verify(qsLogger)
+ .logTileDestroyed(
+ specs[0],
+ QSPipelineLogger.TileDestroyedReason.NEW_TILE_NOT_AVAILABLE,
+ )
+ }
}
@Test
fun someTilesNotValid_repositorySetToDefinitiveList() =
- testScope.runTest(USER_INFO_0) {
- val tiles by collectLastValue(tileSpecRepository.tilesSpecs(USER_INFO_0.id))
+ with(kosmos) {
+ testScope.runTest(USER_INFO_0) {
+ val tiles by collectLastValue(tileSpecRepository.tilesSpecs(USER_INFO_0.id))
- val specs = listOf(TileSpec.create("a"), TileSpec.create("e"))
- tileSpecRepository.setTiles(USER_INFO_0.id, specs)
+ val specs = listOf(TileSpec.create("a"), TileSpec.create("e"))
+ tileSpecRepository.setTiles(USER_INFO_0.id, specs)
- assertThat(tiles).isEqualTo(listOf(TileSpec.create("a")))
+ assertThat(tiles).isEqualTo(listOf(TileSpec.create("a")))
+ }
}
@Test
fun deduplicatedTiles() =
- testScope.runTest(USER_INFO_0) {
- val tiles by collectLastValue(underTest.currentTiles)
+ with(kosmos) {
+ testScope.runTest(USER_INFO_0) {
+ val tiles by collectLastValue(underTest.currentTiles)
- val specs = listOf(TileSpec.create("a"), TileSpec.create("a"))
+ val specs = listOf(TileSpec.create("a"), TileSpec.create("a"))
- tileSpecRepository.setTiles(USER_INFO_0.id, specs)
+ tileSpecRepository.setTiles(USER_INFO_0.id, specs)
- assertThat(tiles?.size).isEqualTo(1)
- assertThat(tiles!![0].spec).isEqualTo(specs[0])
+ assertThat(tiles?.size).isEqualTo(1)
+ assertThat(tiles!![0].spec).isEqualTo(specs[0])
+ }
}
@Test
fun tilesChange_platformTileNotRecreated() =
- testScope.runTest(USER_INFO_0) {
- val tiles by collectLastValue(underTest.currentTiles)
+ with(kosmos) {
+ testScope.runTest(USER_INFO_0) {
+ val tiles by collectLastValue(underTest.currentTiles)
- val specs = listOf(TileSpec.create("a"))
+ val specs = listOf(TileSpec.create("a"))
- tileSpecRepository.setTiles(USER_INFO_0.id, specs)
- val originalTileA = tiles!![0].tile
+ tileSpecRepository.setTiles(USER_INFO_0.id, specs)
+ val originalTileA = tiles!![0].tile
- tileSpecRepository.addTile(USER_INFO_0.id, TileSpec.create("b"))
+ tileSpecRepository.addTile(USER_INFO_0.id, TileSpec.create("b"))
- assertThat(tiles?.size).isEqualTo(2)
- assertThat(tiles!![0].tile).isSameInstanceAs(originalTileA)
+ assertThat(tiles?.size).isEqualTo(2)
+ assertThat(tiles!![0].tile).isSameInstanceAs(originalTileA)
+ }
}
@Test
fun tileRemovedIsDestroyed() =
- testScope.runTest(USER_INFO_0) {
- val tiles by collectLastValue(underTest.currentTiles)
+ with(kosmos) {
+ testScope.runTest(USER_INFO_0) {
+ val tiles by collectLastValue(underTest.currentTiles)
- val specs = listOf(TileSpec.create("a"), TileSpec.create("c"))
+ val specs = listOf(TileSpec.create("a"), TileSpec.create("c"))
- tileSpecRepository.setTiles(USER_INFO_0.id, specs)
- val originalTileC = tiles!![1].tile
+ tileSpecRepository.setTiles(USER_INFO_0.id, specs)
+ val originalTileC = tiles!![1].tile
- tileSpecRepository.removeTiles(USER_INFO_0.id, listOf(TileSpec.create("c")))
+ tileSpecRepository.removeTiles(USER_INFO_0.id, listOf(TileSpec.create("c")))
- assertThat(tiles?.size).isEqualTo(1)
- assertThat(tiles!![0].spec).isEqualTo(TileSpec.create("a"))
+ assertThat(tiles?.size).isEqualTo(1)
+ assertThat(tiles!![0].spec).isEqualTo(TileSpec.create("a"))
- assertThat((originalTileC as FakeQSTile).destroyed).isTrue()
- verify(logger)
- .logTileDestroyed(
- TileSpec.create("c"),
- QSPipelineLogger.TileDestroyedReason.TILE_REMOVED,
- )
+ assertThat(originalTileC.isDestroyed).isTrue()
+ verify(qsLogger)
+ .logTileDestroyed(
+ TileSpec.create("c"),
+ QSPipelineLogger.TileDestroyedReason.TILE_REMOVED,
+ )
+ }
}
@Test
fun tileBecomesNotAvailable_destroyed() =
- testScope.runTest(USER_INFO_0) {
- val tiles by collectLastValue(underTest.currentTiles)
- val repoTiles by collectLastValue(tileSpecRepository.tilesSpecs(USER_INFO_0.id))
+ with(kosmos) {
+ testScope.runTest(USER_INFO_0) {
+ val tiles by collectLastValue(underTest.currentTiles)
+ val repoTiles by collectLastValue(tileSpecRepository.tilesSpecs(USER_INFO_0.id))
- val specs = listOf(TileSpec.create("a"))
+ val specs = listOf(TileSpec.create("a"))
- tileSpecRepository.setTiles(USER_INFO_0.id, specs)
- val originalTileA = tiles!![0].tile
+ tileSpecRepository.setTiles(USER_INFO_0.id, specs)
+ val originalTileA = tiles!![0].tile
- // Tile becomes unavailable
- (originalTileA as FakeQSTile).available = false
- unavailableTiles.add("a")
- // and there is some change in the specs
- tileSpecRepository.addTile(USER_INFO_0.id, TileSpec.create("b"))
- runCurrent()
+ // Tile becomes unavailable
+ (originalTileA as FakeQSTile).available = false
+ unavailableTiles.add("a")
+ // and there is some change in the specs
+ tileSpecRepository.addTile(USER_INFO_0.id, TileSpec.create("b"))
+ runCurrent()
- assertThat(originalTileA.destroyed).isTrue()
- verify(logger)
- .logTileDestroyed(
- TileSpec.create("a"),
- QSPipelineLogger.TileDestroyedReason.EXISTING_TILE_NOT_AVAILABLE,
- )
+ assertThat(originalTileA.isDestroyed).isTrue()
+ verify(qsLogger)
+ .logTileDestroyed(
+ TileSpec.create("a"),
+ QSPipelineLogger.TileDestroyedReason.EXISTING_TILE_NOT_AVAILABLE,
+ )
- assertThat(tiles?.size).isEqualTo(1)
- assertThat(tiles!![0].spec).isEqualTo(TileSpec.create("b"))
- assertThat(tiles!![0].tile).isNotSameInstanceAs(originalTileA)
+ assertThat(tiles?.size).isEqualTo(1)
+ assertThat(tiles!![0].spec).isEqualTo(TileSpec.create("b"))
+ assertThat(tiles!![0].tile).isNotSameInstanceAs(originalTileA)
- assertThat(repoTiles).isEqualTo(tiles!!.map(TileModel::spec))
+ assertThat(repoTiles).isEqualTo(tiles!!.map(TileModel::spec))
+ }
}
@Test
fun userChange_tilesChange() =
- testScope.runTest(USER_INFO_0) {
- val tiles by collectLastValue(underTest.currentTiles)
+ with(kosmos) {
+ testScope.runTest(USER_INFO_0) {
+ val tiles by collectLastValue(underTest.currentTiles)
- val specs0 = listOf(TileSpec.create("a"))
- val specs1 = listOf(TileSpec.create("b"))
- tileSpecRepository.setTiles(USER_INFO_0.id, specs0)
- tileSpecRepository.setTiles(USER_INFO_1.id, specs1)
+ val specs0 = listOf(TileSpec.create("a"))
+ val specs1 = listOf(TileSpec.create("b"))
+ tileSpecRepository.setTiles(USER_INFO_0.id, specs0)
+ tileSpecRepository.setTiles(USER_INFO_1.id, specs1)
- switchUser(USER_INFO_1)
+ switchUser(USER_INFO_1)
- assertThat(tiles!![0].spec).isEqualTo(specs1[0])
- assertThat(tiles!![0].tile.tileSpec).isEqualTo(specs1[0].spec)
+ assertThat(tiles!![0].spec).isEqualTo(specs1[0])
+ assertThat(tiles!![0].tile.tileSpec).isEqualTo(specs1[0].spec)
+ }
}
@Test
fun tileNotPresentInSecondaryUser_destroyedInUserChange() =
- testScope.runTest(USER_INFO_0) {
- val tiles by collectLastValue(underTest.currentTiles)
+ with(kosmos) {
+ testScope.runTest(USER_INFO_0) {
+ val tiles by collectLastValue(underTest.currentTiles)
- val specs0 = listOf(TileSpec.create("a"))
- val specs1 = listOf(TileSpec.create("b"))
- tileSpecRepository.setTiles(USER_INFO_0.id, specs0)
- tileSpecRepository.setTiles(USER_INFO_1.id, specs1)
+ val specs0 = listOf(TileSpec.create("a"))
+ val specs1 = listOf(TileSpec.create("b"))
+ tileSpecRepository.setTiles(USER_INFO_0.id, specs0)
+ tileSpecRepository.setTiles(USER_INFO_1.id, specs1)
- val originalTileA = tiles!![0].tile
+ val originalTileA = tiles!![0].tile
- switchUser(USER_INFO_1)
- runCurrent()
+ switchUser(USER_INFO_1)
+ runCurrent()
- assertThat((originalTileA as FakeQSTile).destroyed).isTrue()
- verify(logger)
- .logTileDestroyed(
- specs0[0],
- QSPipelineLogger.TileDestroyedReason.TILE_NOT_PRESENT_IN_NEW_USER,
- )
+ assertThat(originalTileA.isDestroyed).isTrue()
+ verify(qsLogger)
+ .logTileDestroyed(
+ specs0[0],
+ QSPipelineLogger.TileDestroyedReason.TILE_NOT_PRESENT_IN_NEW_USER,
+ )
+ }
}
@Test
- fun userChange_customTileDestroyed_lifecycleNotTerminated() {
- testScope.runTest(USER_INFO_0) {
- val tiles by collectLastValue(underTest.currentTiles)
+ fun userChange_customTileDestroyed_lifecycleNotTerminated() =
+ with(kosmos) {
+ testScope.runTest(USER_INFO_0) {
+ val tiles by collectLastValue(underTest.currentTiles)
- val specs = listOf(CUSTOM_TILE_SPEC)
- tileSpecRepository.setTiles(USER_INFO_0.id, specs)
- tileSpecRepository.setTiles(USER_INFO_1.id, specs)
+ val specs = listOf(CUSTOM_TILE_SPEC)
+ tileSpecRepository.setTiles(USER_INFO_0.id, specs)
+ tileSpecRepository.setTiles(USER_INFO_1.id, specs)
- val originalCustomTile = tiles!![0].tile
+ val originalCustomTile = tiles!![0].tile
- switchUser(USER_INFO_1)
- runCurrent()
+ switchUser(USER_INFO_1)
+ runCurrent()
- verify(originalCustomTile).destroy()
- assertThat(tileLifecycleManagerFactory.created).isEmpty()
+ verify(originalCustomTile).destroy()
+ assertThat((tileLifecycleManagerFactory as TLMFactory).created).isEmpty()
+ }
}
- }
@Test
fun userChange_sameTileUserChanged() =
- testScope.runTest(USER_INFO_0) {
- val tiles by collectLastValue(underTest.currentTiles)
+ with(kosmos) {
+ testScope.runTest(USER_INFO_0) {
+ val tiles by collectLastValue(underTest.currentTiles)
- val specs = listOf(TileSpec.create("a"))
- tileSpecRepository.setTiles(USER_INFO_0.id, specs)
- tileSpecRepository.setTiles(USER_INFO_1.id, specs)
+ val specs = listOf(TileSpec.create("a"))
+ tileSpecRepository.setTiles(USER_INFO_0.id, specs)
+ tileSpecRepository.setTiles(USER_INFO_1.id, specs)
- val originalTileA = tiles!![0].tile as FakeQSTile
- assertThat(originalTileA.user).isEqualTo(USER_INFO_0.id)
+ val originalTileA = tiles!![0].tile as FakeQSTile
+ assertThat(originalTileA.user).isEqualTo(USER_INFO_0.id)
- switchUser(USER_INFO_1)
- runCurrent()
+ switchUser(USER_INFO_1)
+ runCurrent()
- assertThat(tiles!![0].tile).isSameInstanceAs(originalTileA)
- assertThat(originalTileA.user).isEqualTo(USER_INFO_1.id)
- verify(logger).logTileUserChanged(specs[0], USER_INFO_1.id)
+ assertThat(tiles!![0].tile).isSameInstanceAs(originalTileA)
+ assertThat(originalTileA.user).isEqualTo(USER_INFO_1.id)
+ verify(qsLogger).logTileUserChanged(specs[0], USER_INFO_1.id)
+ }
}
@Test
fun addTile() =
- testScope.runTest(USER_INFO_0) {
- val tiles by collectLastValue(tileSpecRepository.tilesSpecs(USER_INFO_0.id))
- val spec = TileSpec.create("a")
- val currentSpecs = listOf(TileSpec.create("b"), TileSpec.create("c"))
- tileSpecRepository.setTiles(USER_INFO_0.id, currentSpecs)
+ with(kosmos) {
+ testScope.runTest(USER_INFO_0) {
+ val tiles by collectLastValue(tileSpecRepository.tilesSpecs(USER_INFO_0.id))
+ val spec = TileSpec.create("a")
+ val currentSpecs = listOf(TileSpec.create("b"), TileSpec.create("c"))
+ tileSpecRepository.setTiles(USER_INFO_0.id, currentSpecs)
- underTest.addTile(spec, position = 1)
+ underTest.addTile(spec, position = 1)
- val expectedSpecs = listOf(TileSpec.create("b"), spec, TileSpec.create("c"))
- assertThat(tiles).isEqualTo(expectedSpecs)
+ val expectedSpecs = listOf(TileSpec.create("b"), spec, TileSpec.create("c"))
+ assertThat(tiles).isEqualTo(expectedSpecs)
+ }
}
@Test
fun addTile_currentUser() =
- testScope.runTest(USER_INFO_1) {
- val tiles0 by collectLastValue(tileSpecRepository.tilesSpecs(USER_INFO_0.id))
- val tiles1 by collectLastValue(tileSpecRepository.tilesSpecs(USER_INFO_1.id))
- val spec = TileSpec.create("a")
- val currentSpecs = listOf(TileSpec.create("b"), TileSpec.create("c"))
- tileSpecRepository.setTiles(USER_INFO_0.id, currentSpecs)
- tileSpecRepository.setTiles(USER_INFO_1.id, currentSpecs)
+ with(kosmos) {
+ testScope.runTest(USER_INFO_1) {
+ val tiles0 by collectLastValue(tileSpecRepository.tilesSpecs(USER_INFO_0.id))
+ val tiles1 by collectLastValue(tileSpecRepository.tilesSpecs(USER_INFO_1.id))
+ val spec = TileSpec.create("a")
+ val currentSpecs = listOf(TileSpec.create("b"), TileSpec.create("c"))
+ tileSpecRepository.setTiles(USER_INFO_0.id, currentSpecs)
+ tileSpecRepository.setTiles(USER_INFO_1.id, currentSpecs)
- switchUser(USER_INFO_1)
- underTest.addTile(spec, position = 1)
+ switchUser(USER_INFO_1)
+ underTest.addTile(spec, position = 1)
- assertThat(tiles0).isEqualTo(currentSpecs)
+ assertThat(tiles0).isEqualTo(currentSpecs)
- val expectedSpecs = listOf(TileSpec.create("b"), spec, TileSpec.create("c"))
- assertThat(tiles1).isEqualTo(expectedSpecs)
+ val expectedSpecs = listOf(TileSpec.create("b"), spec, TileSpec.create("c"))
+ assertThat(tiles1).isEqualTo(expectedSpecs)
+ }
}
@Test
fun removeTile_platform() =
- testScope.runTest(USER_INFO_0) {
- val tiles by collectLastValue(tileSpecRepository.tilesSpecs(USER_INFO_0.id))
+ with(kosmos) {
+ testScope.runTest(USER_INFO_0) {
+ val tiles by collectLastValue(tileSpecRepository.tilesSpecs(USER_INFO_0.id))
- val specs = listOf(TileSpec.create("a"), TileSpec.create("b"))
- tileSpecRepository.setTiles(USER_INFO_0.id, specs)
- runCurrent()
+ val specs = listOf(TileSpec.create("a"), TileSpec.create("b"))
+ tileSpecRepository.setTiles(USER_INFO_0.id, specs)
+ runCurrent()
- underTest.removeTiles(specs.subList(0, 1))
+ underTest.removeTiles(specs.subList(0, 1))
- assertThat(tiles).isEqualTo(specs.subList(1, 2))
+ assertThat(tiles).isEqualTo(specs.subList(1, 2))
+ }
}
@Test
- fun removeTile_customTile_lifecycleEnded() {
- testScope.runTest(USER_INFO_0) {
- val tiles by collectLastValue(tileSpecRepository.tilesSpecs(USER_INFO_0.id))
+ fun removeTile_customTile_lifecycleEnded() =
+ with(kosmos) {
+ testScope.runTest(USER_INFO_0) {
+ val tiles by collectLastValue(tileSpecRepository.tilesSpecs(USER_INFO_0.id))
- val specs = listOf(TileSpec.create("a"), CUSTOM_TILE_SPEC)
- tileSpecRepository.setTiles(USER_INFO_0.id, specs)
- runCurrent()
- assertThat(customTileAddedRepository.isTileAdded(TEST_COMPONENT, USER_INFO_0.id))
- .isTrue()
+ val specs = listOf(TileSpec.create("a"), CUSTOM_TILE_SPEC)
+ tileSpecRepository.setTiles(USER_INFO_0.id, specs)
+ runCurrent()
+ assertThat(customTileAddedRepository.isTileAdded(TEST_COMPONENT, USER_INFO_0.id))
+ .isTrue()
- underTest.removeTiles(listOf(CUSTOM_TILE_SPEC))
+ underTest.removeTiles(listOf(CUSTOM_TILE_SPEC))
- assertThat(tiles).isEqualTo(specs.subList(0, 1))
+ assertThat(tiles).isEqualTo(specs.subList(0, 1))
- val tileLifecycleManager =
- tileLifecycleManagerFactory.created[USER_INFO_0.id to TEST_COMPONENT]
- assertThat(tileLifecycleManager).isNotNull()
+ val tileLifecycleManager =
+ (tileLifecycleManagerFactory as TLMFactory)
+ .created[USER_INFO_0.id to TEST_COMPONENT]
+ assertThat(tileLifecycleManager).isNotNull()
- with(inOrder(tileLifecycleManager!!)) {
- verify(tileLifecycleManager).onStopListening()
- verify(tileLifecycleManager).onTileRemoved()
- verify(tileLifecycleManager).flushMessagesAndUnbind()
+ with(inOrder(tileLifecycleManager!!)) {
+ verify(tileLifecycleManager).onStopListening()
+ verify(tileLifecycleManager).onTileRemoved()
+ verify(tileLifecycleManager).flushMessagesAndUnbind()
+ }
+ assertThat(customTileAddedRepository.isTileAdded(TEST_COMPONENT, USER_INFO_0.id))
+ .isFalse()
+ assertThat(
+ customTileStatePersister.readState(
+ TileServiceKey(TEST_COMPONENT, USER_INFO_0.id)
+ )
+ )
+ .isNull()
}
- assertThat(customTileAddedRepository.isTileAdded(TEST_COMPONENT, USER_INFO_0.id))
- .isFalse()
- verify(customTileStatePersister)
- .removeState(TileServiceKey(TEST_COMPONENT, USER_INFO_0.id))
}
- }
@Test
fun removeTiles_currentUser() =
- testScope.runTest {
- val tiles0 by collectLastValue(tileSpecRepository.tilesSpecs(USER_INFO_0.id))
- val tiles1 by collectLastValue(tileSpecRepository.tilesSpecs(USER_INFO_1.id))
- val currentSpecs =
- listOf(TileSpec.create("a"), TileSpec.create("b"), TileSpec.create("c"))
- tileSpecRepository.setTiles(USER_INFO_0.id, currentSpecs)
- tileSpecRepository.setTiles(USER_INFO_1.id, currentSpecs)
+ with(kosmos) {
+ testScope.runTest {
+ val tiles0 by collectLastValue(tileSpecRepository.tilesSpecs(USER_INFO_0.id))
+ val tiles1 by collectLastValue(tileSpecRepository.tilesSpecs(USER_INFO_1.id))
+ val currentSpecs =
+ listOf(TileSpec.create("a"), TileSpec.create("b"), TileSpec.create("c"))
+ tileSpecRepository.setTiles(USER_INFO_0.id, currentSpecs)
+ tileSpecRepository.setTiles(USER_INFO_1.id, currentSpecs)
- switchUser(USER_INFO_1)
- runCurrent()
+ switchUser(USER_INFO_1)
+ runCurrent()
- underTest.removeTiles(currentSpecs.subList(0, 2))
+ underTest.removeTiles(currentSpecs.subList(0, 2))
- assertThat(tiles0).isEqualTo(currentSpecs)
- assertThat(tiles1).isEqualTo(currentSpecs.subList(2, 3))
+ assertThat(tiles0).isEqualTo(currentSpecs)
+ assertThat(tiles1).isEqualTo(currentSpecs.subList(2, 3))
+ }
}
@Test
fun setTiles() =
- testScope.runTest(USER_INFO_0) {
- val tiles by collectLastValue(tileSpecRepository.tilesSpecs(USER_INFO_0.id))
+ with(kosmos) {
+ testScope.runTest(USER_INFO_0) {
+ val tiles by collectLastValue(tileSpecRepository.tilesSpecs(USER_INFO_0.id))
- val currentSpecs = listOf(TileSpec.create("a"), TileSpec.create("b"))
- tileSpecRepository.setTiles(USER_INFO_0.id, currentSpecs)
- runCurrent()
+ val currentSpecs = listOf(TileSpec.create("a"), TileSpec.create("b"))
+ tileSpecRepository.setTiles(USER_INFO_0.id, currentSpecs)
+ runCurrent()
- val newSpecs = listOf(TileSpec.create("b"), TileSpec.create("c"), TileSpec.create("a"))
- underTest.setTiles(newSpecs)
- runCurrent()
+ val newSpecs =
+ listOf(TileSpec.create("b"), TileSpec.create("c"), TileSpec.create("a"))
+ underTest.setTiles(newSpecs)
+ runCurrent()
- assertThat(tiles).isEqualTo(newSpecs)
+ assertThat(tiles).isEqualTo(newSpecs)
+ }
}
@Test
fun setTiles_customTiles_lifecycleEndedIfGone() =
- testScope.runTest(USER_INFO_0) {
- val otherCustomTileSpec = TileSpec.create("custom(b/c)")
+ with(kosmos) {
+ testScope.runTest(USER_INFO_0) {
+ val otherCustomTileSpec = TileSpec.create("custom(b/c)")
- val currentSpecs = listOf(CUSTOM_TILE_SPEC, TileSpec.create("a"), otherCustomTileSpec)
- tileSpecRepository.setTiles(USER_INFO_0.id, currentSpecs)
- runCurrent()
+ val currentSpecs =
+ listOf(CUSTOM_TILE_SPEC, TileSpec.create("a"), otherCustomTileSpec)
+ tileSpecRepository.setTiles(USER_INFO_0.id, currentSpecs)
+ runCurrent()
- val newSpecs = listOf(otherCustomTileSpec, TileSpec.create("a"))
+ val newSpecs = listOf(otherCustomTileSpec, TileSpec.create("a"))
- underTest.setTiles(newSpecs)
- runCurrent()
+ underTest.setTiles(newSpecs)
+ runCurrent()
- val tileLifecycleManager =
- tileLifecycleManagerFactory.created[USER_INFO_0.id to TEST_COMPONENT]!!
+ val tileLifecycleManager =
+ (tileLifecycleManagerFactory as TLMFactory)
+ .created[USER_INFO_0.id to TEST_COMPONENT]!!
- with(inOrder(tileLifecycleManager)) {
- verify(tileLifecycleManager).onStopListening()
- verify(tileLifecycleManager).onTileRemoved()
- verify(tileLifecycleManager).flushMessagesAndUnbind()
+ with(inOrder(tileLifecycleManager)) {
+ verify(tileLifecycleManager).onStopListening()
+ verify(tileLifecycleManager).onTileRemoved()
+ verify(tileLifecycleManager).flushMessagesAndUnbind()
+ }
+ assertThat(customTileAddedRepository.isTileAdded(TEST_COMPONENT, USER_INFO_0.id))
+ .isFalse()
+ assertThat(
+ customTileStatePersister.readState(
+ TileServiceKey(TEST_COMPONENT, USER_INFO_0.id)
+ )
+ )
+ .isNull()
}
- assertThat(customTileAddedRepository.isTileAdded(TEST_COMPONENT, USER_INFO_0.id))
- .isFalse()
- verify(customTileStatePersister)
- .removeState(TileServiceKey(TEST_COMPONENT, USER_INFO_0.id))
}
@Test
fun protoDump() =
- testScope.runTest(USER_INFO_0) {
- val tiles by collectLastValue(underTest.currentTiles)
- val specs = listOf(TileSpec.create("a"), CUSTOM_TILE_SPEC)
+ with(kosmos) {
+ testScope.runTest(USER_INFO_0) {
+ val tiles by collectLastValue(underTest.currentTiles)
+ val specs = listOf(TileSpec.create("a"), CUSTOM_TILE_SPEC)
- tileSpecRepository.setTiles(USER_INFO_0.id, specs)
+ tileSpecRepository.setTiles(USER_INFO_0.id, specs)
- val stateA = tiles!![0].tile.state
- stateA.fillIn(Tile.STATE_INACTIVE, "A", "AA")
- val stateCustom = QSTile.BooleanState()
- stateCustom.fillIn(Tile.STATE_ACTIVE, "B", "BB")
- stateCustom.spec = CUSTOM_TILE_SPEC.spec
- whenever(tiles!![1].tile.state).thenReturn(stateCustom)
+ val stateA = tiles!![0].tile.state
+ stateA.fillIn(Tile.STATE_INACTIVE, "A", "AA")
+ val stateCustom = QSTile.BooleanState()
+ stateCustom.fillIn(Tile.STATE_ACTIVE, "B", "BB")
+ stateCustom.spec = CUSTOM_TILE_SPEC.spec
+ whenever(tiles!![1].tile.state).thenReturn(stateCustom)
- val proto = SystemUIProtoDump()
- underTest.dumpProto(proto, emptyArray())
+ val proto = SystemUIProtoDump()
+ underTest.dumpProto(proto, emptyArray())
- assertThat(MessageNano.messageNanoEquals(proto.tiles[0], stateA.toProto())).isTrue()
- assertThat(MessageNano.messageNanoEquals(proto.tiles[1], stateCustom.toProto()))
- .isTrue()
+ assertThat(MessageNano.messageNanoEquals(proto.tiles[0], stateA.toProto())).isTrue()
+ assertThat(MessageNano.messageNanoEquals(proto.tiles[1], stateCustom.toProto()))
+ .isTrue()
+ }
}
@Test
fun retainedTiles_callbackNotRemoved() =
- testScope.runTest(USER_INFO_0) {
- val tiles by collectLastValue(underTest.currentTiles)
- tileSpecRepository.setTiles(USER_INFO_0.id, listOf(TileSpec.create("a")))
+ with(kosmos) {
+ testScope.runTest(USER_INFO_0) {
+ val tiles by collectLastValue(underTest.currentTiles)
+ tileSpecRepository.setTiles(USER_INFO_0.id, listOf(TileSpec.create("a")))
- val tileA = tiles!![0].tile
- val callback = mock<QSTile.Callback>()
- tileA.addCallback(callback)
+ val tileA = tiles!![0].tile
+ val callback = mock<QSTile.Callback>()
+ tileA.addCallback(callback)
- tileSpecRepository.setTiles(
- USER_INFO_0.id,
- listOf(TileSpec.create("a"), CUSTOM_TILE_SPEC),
- )
- val newTileA = tiles!![0].tile
- assertThat(tileA).isSameInstanceAs(newTileA)
+ tileSpecRepository.setTiles(
+ USER_INFO_0.id,
+ listOf(TileSpec.create("a"), CUSTOM_TILE_SPEC),
+ )
+ val newTileA = tiles!![0].tile
+ assertThat(tileA).isSameInstanceAs(newTileA)
- assertThat((tileA as FakeQSTile).callbacks).containsExactly(callback)
+ assertThat((tileA as FakeQSTile).callbacks).containsExactly(callback)
+ }
}
@Test
fun packageNotInstalled_customTileNotVisible() =
- testScope.runTest(USER_INFO_0) {
- installedTilesPackageRepository.setInstalledPackagesForUser(USER_INFO_0.id, emptySet())
+ with(kosmos) {
+ testScope.runTest(USER_INFO_0) {
+ fakeInstalledTilesRepository.setInstalledPackagesForUser(USER_INFO_0.id, emptySet())
- val tiles by collectLastValue(underTest.currentTiles)
+ val tiles by collectLastValue(underTest.currentTiles)
- val specs = listOf(TileSpec.create("a"), CUSTOM_TILE_SPEC)
- tileSpecRepository.setTiles(USER_INFO_0.id, specs)
+ val specs = listOf(TileSpec.create("a"), CUSTOM_TILE_SPEC)
+ tileSpecRepository.setTiles(USER_INFO_0.id, specs)
- assertThat(tiles!!.size).isEqualTo(1)
- assertThat(tiles!![0].spec).isEqualTo(specs[0])
+ assertThat(tiles!!.size).isEqualTo(1)
+ assertThat(tiles!![0].spec).isEqualTo(specs[0])
+ }
}
@Test
fun packageInstalledLater_customTileAdded() =
- testScope.runTest(USER_INFO_0) {
- installedTilesPackageRepository.setInstalledPackagesForUser(USER_INFO_0.id, emptySet())
+ with(kosmos) {
+ testScope.runTest(USER_INFO_0) {
+ fakeInstalledTilesRepository.setInstalledPackagesForUser(USER_INFO_0.id, emptySet())
- val tiles by collectLastValue(underTest.currentTiles)
- val specs = listOf(TileSpec.create("a"), CUSTOM_TILE_SPEC, TileSpec.create("b"))
- tileSpecRepository.setTiles(USER_INFO_0.id, specs)
+ val tiles by collectLastValue(underTest.currentTiles)
+ val specs = listOf(TileSpec.create("a"), CUSTOM_TILE_SPEC, TileSpec.create("b"))
+ tileSpecRepository.setTiles(USER_INFO_0.id, specs)
- assertThat(tiles!!.size).isEqualTo(2)
+ assertThat(tiles!!.size).isEqualTo(2)
- installedTilesPackageRepository.setInstalledPackagesForUser(
- USER_INFO_0.id,
- setOf(TEST_COMPONENT),
- )
+ fakeInstalledTilesRepository.setInstalledPackagesForUser(
+ USER_INFO_0.id,
+ setOf(TEST_COMPONENT),
+ )
- assertThat(tiles!!.size).isEqualTo(3)
- assertThat(tiles!![1].spec).isEqualTo(CUSTOM_TILE_SPEC)
+ assertThat(tiles!!.size).isEqualTo(3)
+ assertThat(tiles!![1].spec).isEqualTo(CUSTOM_TILE_SPEC)
+ }
}
@Test
fun tileAddedOnEmptyList_blocked() =
- testScope.runTest(USER_INFO_0) {
- val tiles by collectLastValue(underTest.currentTiles)
- val specs = listOf(TileSpec.create("a"), TileSpec.create("b"))
- val newTile = TileSpec.create("c")
+ with(kosmos) {
+ testScope.runTest(USER_INFO_0) {
+ val tiles by collectLastValue(underTest.currentTiles)
+ val specs = listOf(TileSpec.create("a"), TileSpec.create("b"))
+ val newTile = TileSpec.create("c")
- underTest.addTile(newTile)
+ underTest.addTile(newTile)
- assertThat(tiles!!.isEmpty()).isTrue()
+ assertThat(tiles!!.isEmpty()).isTrue()
- tileSpecRepository.setTiles(USER_INFO_0.id, specs)
+ tileSpecRepository.setTiles(USER_INFO_0.id, specs)
- assertThat(tiles!!.size).isEqualTo(3)
+ assertThat(tiles!!.size).isEqualTo(3)
+ }
}
@Test
fun changeInPackagesTiles_doesntTriggerUserChange_logged() =
- testScope.runTest(USER_INFO_0) {
- val specs = listOf(TileSpec.create("a"))
- tileSpecRepository.setTiles(USER_INFO_0.id, specs)
- runCurrent()
- // Settled on the same list of tiles.
- assertThat(underTest.currentTilesSpecs).isEqualTo(specs)
+ with(kosmos) {
+ testScope.runTest(USER_INFO_0) {
+ val specs = listOf(TileSpec.create("a"))
+ tileSpecRepository.setTiles(USER_INFO_0.id, specs)
+ runCurrent()
+ // Settled on the same list of tiles.
+ assertThat(underTest.currentTilesSpecs).isEqualTo(specs)
- installedTilesPackageRepository.setInstalledPackagesForUser(USER_INFO_0.id, emptySet())
- runCurrent()
+ fakeInstalledTilesRepository.setInstalledPackagesForUser(USER_INFO_0.id, emptySet())
+ runCurrent()
- verify(logger, never()).logTileUserChanged(TileSpec.create("a"), 0)
+ verify(qsLogger, never()).logTileUserChanged(TileSpec.create("a"), 0)
+ }
}
@Test
fun getTileDetails() =
- testScope.runTest(USER_INFO_0) {
- val tiles by collectLastValue(underTest.currentTiles)
- val tileA = TileSpec.create("a")
- val tileB = TileSpec.create("b")
- val tileNoDetails = TileSpec.create("NoDetails")
+ with(kosmos) {
+ testScope.runTest(USER_INFO_0) {
+ val tiles by collectLastValue(underTest.currentTiles)
+ val tileA = TileSpec.create("a")
+ val tileB = TileSpec.create("b")
+ val tileNoDetails = TileSpec.create("NoDetails")
- val specs = listOf(tileA, tileB, tileNoDetails)
+ val specs = listOf(tileA, tileB, tileNoDetails)
- assertThat(tiles!!.isEmpty()).isTrue()
+ assertThat(tiles!!.isEmpty()).isTrue()
- tileSpecRepository.setTiles(USER_INFO_0.id, specs)
- assertThat(tiles!!.size).isEqualTo(3)
+ tileSpecRepository.setTiles(USER_INFO_0.id, specs)
+ assertThat(tiles!!.size).isEqualTo(3)
- // The third tile doesn't have a details view.
- assertThat(tiles!![2].spec).isEqualTo(tileNoDetails)
- (tiles!![2].tile as FakeQSTile).hasDetailsViewModel = false
+ // The third tile doesn't have a details view.
+ assertThat(tiles!![2].spec).isEqualTo(tileNoDetails)
+ (tiles!![2].tile as FakeQSTile).hasDetailsViewModel = false
- var currentModel: TileDetailsViewModel? = null
- val setCurrentModel = { model: TileDetailsViewModel? -> currentModel = model }
- tiles!![0].tile.getDetailsViewModel(setCurrentModel)
- assertThat(currentModel?.getTitle()).isEqualTo("a")
+ var currentModel: TileDetailsViewModel? = null
+ val setCurrentModel = { model: TileDetailsViewModel? -> currentModel = model }
+ tiles!![0].tile.getDetailsViewModel(setCurrentModel)
+ assertThat(currentModel?.getTitle()).isEqualTo("a")
- currentModel = null
- tiles!![1].tile.getDetailsViewModel(setCurrentModel)
- assertThat(currentModel?.getTitle()).isEqualTo("b")
+ currentModel = null
+ tiles!![1].tile.getDetailsViewModel(setCurrentModel)
+ assertThat(currentModel?.getTitle()).isEqualTo("b")
- currentModel = null
- tiles!![2].tile.getDetailsViewModel(setCurrentModel)
- assertThat(currentModel).isNull()
+ currentModel = null
+ tiles!![2].tile.getDetailsViewModel(setCurrentModel)
+ assertThat(currentModel).isNull()
+ }
+ }
+
+ @Test
+ fun destroyedTilesNotReused() =
+ with(kosmos) {
+ testScope.runTest(USER_INFO_0) {
+ val tiles by collectLastValue(underTest.currentTiles)
+ val specs = listOf(TileSpec.create("a"), TileSpec.create("b"))
+ val newTile = TileSpec.create("c")
+
+ underTest.setTiles(specs)
+
+ val tileABefore = tiles!!.first { it.spec == specs[0] }.tile
+
+ // We destroy it manually, in prod, this could happen if the tile processing action
+ // is interrupted in the middle.
+ tileABefore.destroy()
+
+ underTest.addTile(newTile)
+
+ val tileAAfter = tiles!!.first { it.spec == specs[0] }.tile
+ assertThat(tileAAfter).isNotSameInstanceAs(tileABefore)
+ }
}
private fun QSTile.State.fillIn(state: Int, label: CharSequence, secondaryLabel: CharSequence) {
@@ -686,20 +735,21 @@
}
}
- private fun tileCreator(spec: String): QSTile? {
- val currentUser = userTracker.userId
+ private fun Kosmos.tileCreator(spec: String): QSTile? {
+ val currentUser = userRepository.getSelectedUserInfo().id
return when (spec) {
CUSTOM_TILE_SPEC.spec ->
mock<CustomTile> {
var tileSpecReference: String? = null
- whenever(user).thenReturn(currentUser)
- whenever(component).thenReturn(CUSTOM_TILE_SPEC.componentName)
- whenever(isAvailable).thenReturn(true)
- whenever(setTileSpec(anyString())).thenAnswer {
- tileSpecReference = it.arguments[0] as? String
- Unit
- }
- whenever(tileSpec).thenAnswer { tileSpecReference }
+ on { user } doReturn currentUser
+ on { component } doReturn CUSTOM_TILE_SPEC.componentName
+ on { isAvailable } doReturn true
+ on { setTileSpec(anyString()) }
+ .thenAnswer {
+ tileSpecReference = it.arguments[0] as? String
+ Unit
+ }
+ on { tileSpec }.thenAnswer { tileSpecReference }
// Also, add it to the set of added tiles (as this happens as part of the tile
// creation).
customTileAddedRepository.setTileAdded(
@@ -714,22 +764,16 @@
}
private fun TestScope.runTest(user: UserInfo, body: suspend TestScope.() -> Unit) {
- return runTest {
+ return kosmos.runTest {
switchUser(user)
body()
}
}
- private suspend fun switchUser(user: UserInfo) {
- setUserTracker(user.id)
- installedTilesPackageRepository.setInstalledPackagesForUser(user.id, setOf(TEST_COMPONENT))
- userRepository.setSelectedUserInfo(user)
- }
-
- private fun setUserTracker(user: Int) {
- val mockContext = mockUserContext(user)
- whenever(userTracker.userContext).thenReturn(mockContext)
- whenever(userTracker.userId).thenReturn(user)
+ private suspend fun Kosmos.switchUser(user: UserInfo) {
+ fakeUserTracker.set(listOf(user), 0)
+ fakeInstalledTilesRepository.setInstalledPackagesForUser(user.id, setOf(TEST_COMPONENT))
+ fakeUserRepository.setSelectedUserInfo(user)
}
private class TLMFactory : TileLifecycleManager.Factory {
@@ -745,13 +789,6 @@
}
}
- private fun mockUserContext(user: Int): Context {
- return mock {
- whenever(this.userId).thenReturn(user)
- whenever(this.user).thenReturn(UserHandle.of(user))
- }
- }
-
companion object {
private val USER_INFO_0 = UserInfo().apply { id = 0 }
private val USER_INFO_1 = UserInfo().apply { id = 1 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
index 296478b..1d8c6cc 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
@@ -508,6 +508,12 @@
assertThat(mTile.mRefreshes).isEqualTo(1);
}
+ @Test
+ public void testIsDestroyedImmediately() {
+ mTile.destroy();
+ assertThat(mTile.isDestroyed()).isTrue();
+ }
+
private void assertEvent(UiEventLogger.UiEventEnum eventType,
UiEventLoggerFake.FakeUiEvent fakeEvent) {
assertEquals(eventType.getId(), fakeEvent.eventId);
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImplTest.kt
index fba6151..da3cebd 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImplTest.kt
@@ -22,6 +22,7 @@
import com.android.systemui.classifier.FalsingManagerFake
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.qs.FakeTileDetailsViewModel
import com.android.systemui.qs.tiles.base.analytics.QSTileAnalytics
import com.android.systemui.qs.tiles.base.interactor.FakeDisabledByPolicyInteractor
import com.android.systemui.qs.tiles.base.interactor.FakeQSTileDataInteractor
@@ -97,6 +98,7 @@
testCoroutineDispatcher,
testCoroutineDispatcher,
testScope.backgroundScope,
+ FakeTileDetailsViewModel("QSTileViewModelImplTest"),
)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/internet/domain/interactor/InternetTileUserActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/internet/domain/interactor/InternetTileUserActionInteractorTest.kt
index 3db5efc..261e3de 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/internet/domain/interactor/InternetTileUserActionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/internet/domain/interactor/InternetTileUserActionInteractorTest.kt
@@ -26,8 +26,6 @@
import com.android.systemui.qs.tiles.base.actions.FakeQSTileIntentUserInputHandler
import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandlerSubject
import com.android.systemui.qs.tiles.base.interactor.QSTileInputTestKtx
-import com.android.systemui.qs.tiles.dialog.InternetDetailsContentManager
-import com.android.systemui.qs.tiles.dialog.InternetDetailsViewModel
import com.android.systemui.qs.tiles.dialog.InternetDialogManager
import com.android.systemui.qs.tiles.impl.internet.domain.model.InternetTileModel
import com.android.systemui.statusbar.connectivity.AccessPointController
@@ -39,11 +37,8 @@
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.anyBoolean
import org.mockito.ArgumentMatchers.eq
-import org.mockito.kotlin.any
import org.mockito.kotlin.mock
-import org.mockito.kotlin.times
import org.mockito.kotlin.verify
-import org.mockito.kotlin.whenever
@SmallTest
@EnabledOnRavenwood
@@ -56,31 +51,17 @@
private lateinit var internetDialogManager: InternetDialogManager
private lateinit var controller: AccessPointController
- private lateinit var internetDetailsViewModelFactory: InternetDetailsViewModel.Factory
- private lateinit var internetDetailsContentManagerFactory: InternetDetailsContentManager.Factory
- private lateinit var internetDetailsViewModel: InternetDetailsViewModel
@Before
fun setup() {
internetDialogManager = mock<InternetDialogManager>()
controller = mock<AccessPointController>()
- internetDetailsViewModelFactory = mock<InternetDetailsViewModel.Factory>()
- internetDetailsContentManagerFactory = mock<InternetDetailsContentManager.Factory>()
- internetDetailsViewModel =
- InternetDetailsViewModel(
- onLongClick = {},
- accessPointController = mock<AccessPointController>(),
- contentManagerFactory = internetDetailsContentManagerFactory,
- )
- whenever(internetDetailsViewModelFactory.create(any())).thenReturn(internetDetailsViewModel)
-
underTest =
InternetTileUserActionInteractor(
kosmos.testScope.coroutineContext,
internetDialogManager,
controller,
inputHandler,
- internetDetailsViewModelFactory,
)
}
@@ -127,12 +108,4 @@
assertThat(it.intent.action).isEqualTo(Settings.ACTION_WIFI_SETTINGS)
}
}
-
- @Test
- fun detailsViewModel() =
- kosmos.testScope.runTest {
- assertThat(underTest.detailsViewModel.getTitle()).isEqualTo("Internet")
- assertThat(underTest.detailsViewModel.getSubTitle())
- .isEqualTo("Tab a network to connect")
- }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelTest.kt
index 0598a8b..4e9b635 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelTest.kt
@@ -25,6 +25,7 @@
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.coroutines.collectValues
+import com.android.systemui.qs.FakeTileDetailsViewModel
import com.android.systemui.qs.tiles.base.analytics.QSTileAnalytics
import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger
import com.android.systemui.qs.tiles.base.interactor.FakeDisabledByPolicyInteractor
@@ -171,21 +172,6 @@
.isEqualTo(FakeQSTileDataInteractor.AvailabilityRequest(USER))
}
- @Test
- fun tileDetails() =
- testScope.runTest {
- assertThat(tileUserActionInteractor.detailsViewModel).isNotNull()
- assertThat(tileUserActionInteractor.detailsViewModel?.getTitle())
- .isEqualTo("FakeQSTileUserActionInteractor")
- assertThat(underTest.detailsViewModel).isNotNull()
- assertThat(underTest.detailsViewModel?.getTitle())
- .isEqualTo("FakeQSTileUserActionInteractor")
-
- tileUserActionInteractor.detailsViewModel = null
- assertThat(tileUserActionInteractor.detailsViewModel).isNull()
- assertThat(underTest.detailsViewModel).isNull()
- }
-
private fun createViewModel(
scope: TestScope,
config: QSTileConfig = tileConfig,
@@ -209,6 +195,7 @@
testCoroutineDispatcher,
testCoroutineDispatcher,
scope.backgroundScope,
+ FakeTileDetailsViewModel("QSTileViewModelTest"),
)
private companion object {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelUserInputTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelUserInputTest.kt
index ece21e1..166e950 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelUserInputTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelUserInputTest.kt
@@ -22,6 +22,7 @@
import com.android.systemui.classifier.FalsingManagerFake
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.qs.FakeTileDetailsViewModel
import com.android.systemui.qs.tiles.base.analytics.QSTileAnalytics
import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger
import com.android.systemui.qs.tiles.base.interactor.FakeDisabledByPolicyInteractor
@@ -253,5 +254,6 @@
testCoroutineDispatcher,
testCoroutineDispatcher,
scope.backgroundScope,
+ FakeTileDetailsViewModel("QSTileViewModelUserInputTest"),
)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationTransitionAnimatorControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationTransitionAnimatorControllerTest.kt
index 510167d..d3cd240 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationTransitionAnimatorControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationTransitionAnimatorControllerTest.kt
@@ -84,7 +84,7 @@
controller.onIntentStarted(willAnimate = false)
assertTrue(HeadsUpUtil.isClickedHeadsUpNotification(notification))
- assertFalse(notification.entry.isExpandAnimationRunning)
+ assertFalse(notification.isLaunchAnimationRunning)
val isExpandAnimationRunning by
testScope.collectLastValue(
notificationLaunchAnimationInteractor.isLaunchAnimationRunning
@@ -107,7 +107,7 @@
controller.onTransitionAnimationCancelled()
assertTrue(HeadsUpUtil.isClickedHeadsUpNotification(notification))
- assertFalse(notification.entry.isExpandAnimationRunning)
+ assertFalse(notification.isLaunchAnimationRunning)
val isExpandAnimationRunning by
testScope.collectLastValue(
notificationLaunchAnimationInteractor.isLaunchAnimationRunning
@@ -130,7 +130,7 @@
controller.onTransitionAnimationEnd(isExpandingFullyAbove = true)
assertFalse(HeadsUpUtil.isClickedHeadsUpNotification(notification))
- assertFalse(notification.entry.isExpandAnimationRunning)
+ assertFalse(notification.isLaunchAnimationRunning)
val isExpandAnimationRunning by
testScope.collectLastValue(
notificationLaunchAnimationInteractor.isLaunchAnimationRunning
@@ -199,7 +199,7 @@
fun testNotificationIsExpandingDuringAnimation() {
controller.onIntentStarted(willAnimate = true)
- assertTrue(notification.entry.isExpandAnimationRunning)
+ assertTrue(notification.isLaunchAnimationRunning)
val isExpandAnimationRunning by
testScope.collectLastValue(
notificationLaunchAnimationInteractor.isLaunchAnimationRunning
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt
index 92b8c3a..13da04e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt
@@ -24,6 +24,7 @@
import com.android.systemui.flags.andSceneContainer
import com.android.systemui.shade.transition.LargeScreenShadeInterpolator
import com.android.systemui.statusbar.StatusBarState
+import com.android.systemui.statusbar.notification.data.repository.HeadsUpRepository
import com.android.systemui.statusbar.notification.headsup.AvalancheController
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
import com.android.systemui.util.mockito.mock
@@ -47,6 +48,7 @@
private val statusBarKeyguardViewManager = mock<StatusBarKeyguardViewManager>()
private val largeScreenShadeInterpolator = mock<LargeScreenShadeInterpolator>()
private val avalancheController = mock<AvalancheController>()
+ private val headsupRepository = mock<HeadsUpRepository>()
private lateinit var sut: AmbientState
@@ -72,6 +74,7 @@
bypassController,
statusBarKeyguardViewManager,
largeScreenShadeInterpolator,
+ headsupRepository,
avalancheController,
)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
index 33211d4..ce655ef 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
@@ -22,6 +22,7 @@
import com.android.systemui.statusbar.notification.RoundableState
import com.android.systemui.statusbar.notification.collection.EntryAdapter
import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.data.repository.HeadsUpRepository
import com.android.systemui.statusbar.notification.emptyshade.ui.view.EmptyShadeView
import com.android.systemui.statusbar.notification.footer.ui.view.FooterView
import com.android.systemui.statusbar.notification.footer.ui.view.FooterView.FooterViewState
@@ -61,6 +62,7 @@
private val dumpManager = mock<DumpManager>()
private val mStatusBarKeyguardViewManager = mock<StatusBarKeyguardViewManager>()
private val notificationShelf = mock<NotificationShelf>()
+ private val headsUpRepository = mock<HeadsUpRepository>()
private val emptyShadeView =
EmptyShadeView(context, /* attrs= */ null).apply {
layout(/* l= */ 0, /* t= */ 0, /* r= */ 100, /* b= */ 100)
@@ -74,6 +76,7 @@
/* bypassController */ { false },
mStatusBarKeyguardViewManager,
largeScreenShadeInterpolator,
+ headsUpRepository,
avalancheController,
)
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
index 56176cf..d197cdb7 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
@@ -42,7 +42,7 @@
@DependsOn(target = Icon.class)
@DependsOn(target = State.class)
public interface QSTile {
- int VERSION = 4;
+ int VERSION = 5;
String getTileSpec();
@@ -78,6 +78,7 @@
void longClick(@Nullable Expandable expandable);
void userSwitch(int currentUser);
+ int getCurrentTileUser();
/**
* @deprecated not needed as {@link com.android.internal.logging.UiEvent} will use
@@ -150,6 +151,8 @@
return null;
}
+ boolean isDestroyed();
+
@ProvidesInterface(version = Callback.VERSION)
interface Callback {
static final int VERSION = 2;
diff --git a/packages/SystemUI/res/drawable/notification_2025_guts_priority_button_bg.xml b/packages/SystemUI/res/drawable/notification_2025_guts_priority_button_bg.xml
new file mode 100644
index 0000000..1de8c2b
--- /dev/null
+++ b/packages/SystemUI/res/drawable/notification_2025_guts_priority_button_bg.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2025 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle" >
+ <solid
+ android:color="@color/notification_guts_priority_button_bg_fill" />
+
+ <stroke
+ android:width="1.5dp"
+ android:color="@color/notification_guts_priority_button_bg_stroke" />
+
+ <corners android:radius="16dp" />
+</shape>
diff --git a/packages/SystemUI/res/layout/notification_2025_info.xml b/packages/SystemUI/res/layout/notification_2025_info.xml
new file mode 100644
index 0000000..7b69166
--- /dev/null
+++ b/packages/SystemUI/res/layout/notification_2025_info.xml
@@ -0,0 +1,365 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2025, 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.
+-->
+
+<!-- extends LinearLayout -->
+<com.android.systemui.statusbar.notification.row.NotificationInfo
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:id="@+id/notification_guts"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:focusable="true"
+ android:clipChildren="false"
+ android:clipToPadding="true"
+ android:orientation="vertical"
+ android:paddingStart="@*android:dimen/notification_2025_margin">
+
+ <!-- Package Info -->
+ <LinearLayout
+ android:id="@+id/header"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:clipChildren="false"
+ android:clipToPadding="true">
+ <ImageView
+ android:id="@+id/pkg_icon"
+ android:layout_width="@*android:dimen/notification_2025_icon_circle_size"
+ android:layout_height="@*android:dimen/notification_2025_icon_circle_size"
+ android:layout_marginTop="@*android:dimen/notification_2025_margin"
+ android:layout_marginEnd="@*android:dimen/notification_2025_margin" />
+ <LinearLayout
+ android:id="@+id/names"
+ android:layout_weight="1"
+ android:layout_width="0dp"
+ android:orientation="vertical"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@*android:dimen/notification_2025_margin"
+ android:minHeight="@*android:dimen/notification_2025_icon_circle_size">
+ <TextView
+ android:id="@+id/channel_name"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textDirection="locale"
+ style="@style/TextAppearance.NotificationImportanceChannel"/>
+ <TextView
+ android:id="@+id/group_name"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textDirection="locale"
+ android:ellipsize="end"
+ style="@style/TextAppearance.NotificationImportanceChannelGroup"/>
+ <TextView
+ android:id="@+id/pkg_name"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ style="@style/TextAppearance.NotificationImportanceApp"
+ android:ellipsize="end"
+ android:textDirection="locale"
+ android:maxLines="1"/>
+ <TextView
+ android:id="@+id/delegate_name"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ style="@style/TextAppearance.NotificationImportanceHeader"
+ android:ellipsize="end"
+ android:textDirection="locale"
+ android:text="@string/notification_delegate_header"
+ android:maxLines="1" />
+
+ </LinearLayout>
+
+ <!-- feedback for notificationassistantservice -->
+ <ImageButton
+ android:id="@+id/feedback"
+ android:layout_width="@dimen/notification_2025_guts_button_size"
+ android:layout_height="@dimen/notification_2025_guts_button_size"
+ android:visibility="gone"
+ android:background="@drawable/ripple_drawable"
+ android:contentDescription="@string/notification_guts_bundle_feedback"
+ android:src="@*android:drawable/ic_feedback"
+ android:paddingTop="@*android:dimen/notification_2025_margin"
+ android:tint="@androidprv:color/materialColorPrimary"/>
+
+ <!-- Optional link to app. Only appears if the channel is not disabled and the app
+ asked for it -->
+ <ImageButton
+ android:id="@+id/app_settings"
+ android:layout_width="@dimen/notification_2025_guts_button_size"
+ android:layout_height="@dimen/notification_2025_guts_button_size"
+ android:visibility="gone"
+ android:background="@drawable/ripple_drawable"
+ android:contentDescription="@string/notification_app_settings"
+ android:src="@drawable/ic_info"
+ android:paddingTop="@*android:dimen/notification_2025_margin"
+ android:tint="@androidprv:color/materialColorPrimary"/>
+
+ <!-- System notification settings -->
+ <ImageButton
+ android:id="@+id/info"
+ android:layout_width="@dimen/notification_2025_guts_button_size"
+ android:layout_height="@dimen/notification_2025_guts_button_size"
+ android:contentDescription="@string/notification_more_settings"
+ android:background="@drawable/ripple_drawable"
+ android:src="@drawable/ic_settings"
+ android:padding="@*android:dimen/notification_2025_margin"
+ android:tint="@androidprv:color/materialColorPrimary" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/inline_controls"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@*android:dimen/notification_2025_margin"
+ android:layout_marginTop="@*android:dimen/notification_2025_margin"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:orientation="vertical">
+
+ <!-- Non configurable app/channel text. appears instead of @+id/interruptiveness_settings-->
+ <TextView
+ android:id="@+id/non_configurable_text"
+ android:text="@string/notification_unblockable_desc"
+ android:visibility="gone"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ style="@*android:style/TextAppearance.DeviceDefault.Notification" />
+
+ <!-- Non configurable app/channel text. appears instead of @+id/interruptiveness_settings-->
+ <TextView
+ android:id="@+id/non_configurable_call_text"
+ android:text="@string/notification_unblockable_call_desc"
+ android:visibility="gone"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ style="@*android:style/TextAppearance.DeviceDefault.Notification" />
+
+ <!-- Non configurable multichannel text. appears instead of @+id/interruptiveness_settings-->
+ <TextView
+ android:id="@+id/non_configurable_multichannel_text"
+ android:text="@string/notification_multichannel_desc"
+ android:visibility="gone"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ style="@*android:style/TextAppearance.DeviceDefault.Notification" />
+
+ <LinearLayout
+ android:id="@+id/interruptiveness_settings"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:orientation="vertical">
+ <com.android.systemui.statusbar.notification.row.ButtonLinearLayout
+ android:id="@+id/automatic"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingVertical="@dimen/notification_2025_importance_button_padding_vertical"
+ android:paddingHorizontal="@dimen/notification_2025_importance_button_padding_horizontal"
+ android:gravity="center_vertical"
+ android:clickable="true"
+ android:focusable="true"
+ android:background="@drawable/notification_2025_guts_priority_button_bg"
+ android:orientation="horizontal"
+ android:visibility="gone">
+ <ImageView
+ android:id="@+id/automatic_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingEnd="@*android:dimen/notification_2025_margin"
+ android:src="@drawable/ic_notifications_automatic"
+ android:background="@android:color/transparent"
+ android:tint="@color/notification_guts_priority_contents"
+ android:clickable="false"
+ android:focusable="false"/>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:gravity="center"
+ >
+ <TextView
+ android:id="@+id/automatic_label"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:ellipsize="end"
+ android:maxLines="1"
+ android:clickable="false"
+ android:focusable="false"
+ android:textAppearance="@style/TextAppearance.NotificationImportanceButton"
+ android:text="@string/notification_automatic_title"/>
+ <TextView
+ android:id="@+id/automatic_summary"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/notification_importance_button_description_top_margin"
+ android:visibility="gone"
+ android:text="@string/notification_channel_summary_automatic"
+ android:clickable="false"
+ android:focusable="false"
+ android:ellipsize="end"
+ android:maxLines="2"
+ android:textAppearance="@style/TextAppearance.NotificationImportanceDetail"/>
+ </LinearLayout>
+ </com.android.systemui.statusbar.notification.row.ButtonLinearLayout>
+
+ <com.android.systemui.statusbar.notification.row.ButtonLinearLayout
+ android:id="@+id/alert"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingVertical="@dimen/notification_2025_importance_button_padding_vertical"
+ android:paddingHorizontal="@dimen/notification_2025_importance_button_padding_horizontal"
+ android:gravity="center_vertical"
+ android:clickable="true"
+ android:focusable="true"
+ android:background="@drawable/notification_2025_guts_priority_button_bg"
+ android:orientation="horizontal">
+ <ImageView
+ android:id="@+id/alert_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingEnd="@*android:dimen/notification_2025_margin"
+ android:src="@drawable/ic_notifications_alert"
+ android:background="@android:color/transparent"
+ android:tint="@color/notification_guts_priority_contents"
+ android:clickable="false"
+ android:focusable="false"/>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:gravity="center"
+ >
+ <TextView
+ android:id="@+id/alert_label"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:ellipsize="end"
+ android:maxLines="1"
+ android:clickable="false"
+ android:focusable="false"
+ android:textAppearance="@style/TextAppearance.NotificationImportanceButton"
+ android:text="@string/notification_alert_title"/>
+ <TextView
+ android:id="@+id/alert_summary"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:visibility="gone"
+ android:text="@string/notification_channel_summary_default"
+ android:clickable="false"
+ android:focusable="false"
+ android:ellipsize="end"
+ android:maxLines="2"
+ android:textAppearance="@style/TextAppearance.NotificationImportanceDetail"/>
+ </LinearLayout>
+ </com.android.systemui.statusbar.notification.row.ButtonLinearLayout>
+
+ <com.android.systemui.statusbar.notification.row.ButtonLinearLayout
+ android:id="@+id/silence"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/notification_importance_button_separation"
+ android:paddingVertical="@dimen/notification_2025_importance_button_padding_vertical"
+ android:paddingHorizontal="@dimen/notification_2025_importance_button_padding_horizontal"
+ android:gravity="center_vertical"
+ android:clickable="true"
+ android:focusable="true"
+ android:background="@drawable/notification_2025_guts_priority_button_bg"
+ android:orientation="horizontal">
+ <ImageView
+ android:id="@+id/silence_icon"
+ android:src="@drawable/ic_notifications_silence"
+ android:background="@android:color/transparent"
+ android:tint="@color/notification_guts_priority_contents"
+ android:layout_gravity="center"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingEnd="@*android:dimen/notification_2025_margin"
+ android:clickable="false"
+ android:focusable="false"/>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:gravity="center"
+ >
+ <TextView
+ android:id="@+id/silence_label"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:ellipsize="end"
+ android:maxLines="1"
+ android:clickable="false"
+ android:focusable="false"
+ android:layout_toEndOf="@id/silence_icon"
+ android:textAppearance="@style/TextAppearance.NotificationImportanceButton"
+ android:text="@string/notification_silence_title"/>
+ <TextView
+ android:id="@+id/silence_summary"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:visibility="gone"
+ android:text="@string/notification_channel_summary_low"
+ android:clickable="false"
+ android:focusable="false"
+ android:ellipsize="end"
+ android:maxLines="2"
+ android:textAppearance="@style/TextAppearance.NotificationImportanceDetail"/>
+ </LinearLayout>
+ </com.android.systemui.statusbar.notification.row.ButtonLinearLayout>
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/bottom_buttons"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@*android:dimen/notification_2025_margin"
+ android:minHeight="@dimen/notification_2025_guts_button_size"
+ android:gravity="center_vertical"
+ >
+ <TextView
+ android:id="@+id/turn_off_notifications"
+ android:text="@string/inline_turn_off_notifications"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="32dp"
+ android:paddingTop="8dp"
+ android:paddingBottom="@*android:dimen/notification_2025_margin"
+ android:gravity="center"
+ android:minWidth="@dimen/notification_2025_min_tap_target_size"
+ android:minHeight="@dimen/notification_2025_min_tap_target_size"
+ android:maxWidth="200dp"
+ style="@style/TextAppearance.NotificationInfo.Button"
+ android:textSize="@*android:dimen/notification_2025_action_text_size"/>
+ <TextView
+ android:id="@+id/done"
+ android:text="@string/inline_ok_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="8dp"
+ android:paddingBottom="@*android:dimen/notification_2025_margin"
+ android:gravity="center"
+ android:minWidth="@dimen/notification_2025_min_tap_target_size"
+ android:minHeight="@dimen/notification_2025_min_tap_target_size"
+ android:maxWidth="125dp"
+ style="@style/TextAppearance.NotificationInfo.Button"
+ android:textSize="@*android:dimen/notification_2025_action_text_size"/>
+ </LinearLayout>
+ </LinearLayout>
+</com.android.systemui.statusbar.notification.row.NotificationInfo>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 640e1fa..7c370d3 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -390,6 +390,12 @@
<!-- Extra space for guts bundle feedback button -->
<dimen name="notification_guts_bundle_feedback_size">48dp</dimen>
+ <!-- Size of icon buttons in notification info. -->
+ <!-- 24dp for the icon itself + 16dp * 2 for top and bottom padding -->
+ <dimen name="notification_2025_guts_button_size">56dp</dimen>
+
+ <dimen name="notification_2025_min_tap_target_size">48dp</dimen>
+
<dimen name="notification_importance_toggle_size">48dp</dimen>
<dimen name="notification_importance_button_separation">8dp</dimen>
<dimen name="notification_importance_drawable_padding">8dp</dimen>
@@ -402,6 +408,10 @@
<dimen name="notification_importance_button_description_top_margin">12dp</dimen>
<dimen name="rect_button_radius">8dp</dimen>
+ <!-- Padding for importance selection buttons in notification info, 2025 redesign version -->
+ <dimen name="notification_2025_importance_button_padding_vertical">12dp</dimen>
+ <dimen name="notification_2025_importance_button_padding_horizontal">16dp</dimen>
+
<!-- The minimum height for the snackbar shown after the snooze option has been chosen. -->
<dimen name="snooze_snackbar_min_height">56dp</dimen>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
index 4a4cb7a..8f8bcf2 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
@@ -239,7 +239,6 @@
R.dimen.keyguard_pattern_activated_dot_size));
mLockPatternView.setPathWidth(
getResources().getDimensionPixelSize(R.dimen.keyguard_pattern_stroke_width));
- mLockPatternView.setKeepDotActivated(true);
}
mEcaView = findViewById(R.id.keyguard_selector_fade_container);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
index 7fb6664..f6df425 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
@@ -36,6 +36,7 @@
import com.android.internal.widget.LockscreenCredential;
import com.android.keyguard.EmergencyButtonController.EmergencyButtonCallback;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
+import com.android.systemui.Flags;
import com.android.systemui.bouncer.ui.helper.BouncerHapticPlayer;
import com.android.systemui.classifier.FalsingClassifier;
import com.android.systemui.classifier.FalsingCollector;
@@ -237,8 +238,12 @@
super.onViewAttached();
mLockPatternView.setOnPatternListener(new UnlockPatternListener());
mLockPatternView.setSaveEnabled(false);
- mLockPatternView.setInStealthMode(!mLockPatternUtils.isVisiblePatternEnabled(
- mSelectedUserInteractor.getSelectedUserId()));
+ boolean visiblePatternEnabled = mLockPatternUtils.isVisiblePatternEnabled(
+ mSelectedUserInteractor.getSelectedUserId());
+ mLockPatternView.setInStealthMode(!visiblePatternEnabled);
+ if (Flags.bouncerUiRevamp2()) {
+ mLockPatternView.setKeepDotActivated(visiblePatternEnabled);
+ }
mLockPatternView.setOnTouchListener((v, event) -> {
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
mFalsingCollector.avoidGesture();
diff --git a/packages/SystemUI/src/com/android/systemui/common/data/repository/PackageInstallerMonitor.kt b/packages/SystemUI/src/com/android/systemui/common/data/repository/PackageInstallerMonitor.kt
index 208adc2..5f7dca8 100644
--- a/packages/SystemUI/src/com/android/systemui/common/data/repository/PackageInstallerMonitor.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/data/repository/PackageInstallerMonitor.kt
@@ -64,15 +64,14 @@
synchronized(sessions) {
sessions.putAll(
packageInstaller.allSessions
- .filter { !TextUtils.isEmpty(it.appPackageName) }
- .map { session -> session.toModel() }
+ .mapNotNull { session -> session.toModel() }
.associateBy { it.sessionId }
)
updateInstallerSessionsFlow()
}
packageInstaller.registerSessionCallback(
this@PackageInstallerMonitor,
- bgHandler
+ bgHandler,
)
} else {
synchronized(sessions) {
@@ -130,7 +129,7 @@
if (session == null) {
sessions.remove(sessionId)
} else {
- sessions[sessionId] = session.toModel()
+ session.toModel()?.apply { sessions[sessionId] = this }
}
updateInstallerSessionsFlow()
}
@@ -144,7 +143,11 @@
companion object {
const val TAG = "PackageInstallerMonitor"
- private fun PackageInstaller.SessionInfo.toModel(): PackageInstallSession {
+ private fun PackageInstaller.SessionInfo.toModel(): PackageInstallSession? {
+ if (TextUtils.isEmpty(this.appPackageName)) {
+ return null
+ }
+
return PackageInstallSession(
sessionId = this.sessionId,
packageName = this.appPackageName,
diff --git a/packages/SystemUI/src/com/android/systemui/common/shared/colors/SurfaceEffectColors.kt b/packages/SystemUI/src/com/android/systemui/common/shared/colors/SurfaceEffectColors.kt
index 5e8c21f9..4451f07 100644
--- a/packages/SystemUI/src/com/android/systemui/common/shared/colors/SurfaceEffectColors.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/shared/colors/SurfaceEffectColors.kt
@@ -16,23 +16,27 @@
package com.android.systemui.common.shared.colors
-import android.content.res.Resources
+import android.content.Context
object SurfaceEffectColors {
@JvmStatic
- fun surfaceEffect0(r: Resources): Int {
- return r.getColor(com.android.internal.R.color.surface_effect_0)
+ fun surfaceEffect0(context: Context): Int {
+ return context.resources.getColor(
+ com.android.internal.R.color.surface_effect_0, context.theme)
}
@JvmStatic
- fun surfaceEffect1(r: Resources): Int {
- return r.getColor(com.android.internal.R.color.surface_effect_1)
+ fun surfaceEffect1(context: Context): Int {
+ return context.resources.getColor(
+ com.android.internal.R.color.surface_effect_1, context.theme)
}
@JvmStatic
- fun surfaceEffect2(r: Resources): Int {
- return r.getColor(com.android.internal.R.color.surface_effect_2)
+ fun surfaceEffect2(context: Context): Int {
+ return context.resources.getColor(
+ com.android.internal.R.color.surface_effect_2, context.theme)
}
@JvmStatic
- fun surfaceEffect3(r: Resources): Int {
- return r.getColor(com.android.internal.R.color.surface_effect_3)
+ fun surfaceEffect3(context: Context): Int {
+ return context.resources.getColor(
+ com.android.internal.R.color.surface_effect_3, context.theme)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToPrimaryBouncerTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToPrimaryBouncerTransitionViewModel.kt
index 74d471c..e119ec9 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToPrimaryBouncerTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToPrimaryBouncerTransitionViewModel.kt
@@ -101,7 +101,7 @@
if (Flags.notificationShadeBlur()) {
transitionAnimation.immediatelyTransitionTo(blurConfig.maxBlurRadiusPx)
} else {
- emptyFlow()
+ transitionAnimation.immediatelyTransitionTo(blurConfig.minBlurRadiusPx)
},
flowWhenShadeIsNotExpanded =
transitionAnimation.sharedFlow(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToPrimaryBouncerTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToPrimaryBouncerTransitionViewModel.kt
index 3c126aa..f14a5a2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToPrimaryBouncerTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToPrimaryBouncerTransitionViewModel.kt
@@ -51,7 +51,7 @@
if (Flags.notificationShadeBlur()) {
transitionAnimation.immediatelyTransitionTo(blurConfig.maxBlurRadiusPx)
} else {
- emptyFlow()
+ transitionAnimation.immediatelyTransitionTo(blurConfig.minBlurRadiusPx)
},
flowWhenShadeIsNotExpanded =
transitionAnimation.immediatelyTransitionTo(blurConfig.maxBlurRadiusPx),
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModel.kt
index 5a111aa..4a39421 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModel.kt
@@ -32,7 +32,6 @@
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.emptyFlow
/**
* Breaks down PRIMARY BOUNCER->LOCKSCREEN transition into discrete steps for corresponding views to
@@ -81,7 +80,7 @@
if (Flags.notificationShadeBlur()) {
transitionAnimation.immediatelyTransitionTo(blurConfig.maxBlurRadiusPx)
} else {
- emptyFlow()
+ transitionAnimation.immediatelyTransitionTo(blurConfig.minBlurRadiusPx)
},
flowWhenShadeIsNotExpanded =
transitionAnimation.sharedFlow(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToOccludedTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToOccludedTransitionViewModel.kt
index 0f0e7b6..31b20a7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToOccludedTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToOccludedTransitionViewModel.kt
@@ -27,7 +27,6 @@
import com.android.systemui.keyguard.ui.transitions.PrimaryBouncerTransition
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.emptyFlow
@SysUISingleton
class PrimaryBouncerToOccludedTransitionViewModel
@@ -51,7 +50,7 @@
if (Flags.notificationShadeBlur()) {
transitionAnimation.immediatelyTransitionTo(blurConfig.maxBlurRadiusPx)
} else {
- emptyFlow()
+ transitionAnimation.immediatelyTransitionTo(blurConfig.minBlurRadiusPx)
},
flowWhenShadeIsNotExpanded =
transitionAnimation.immediatelyTransitionTo(blurConfig.minBlurRadiusPx),
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractor.kt
index 609541b..c70a854 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractor.kt
@@ -20,6 +20,7 @@
import android.content.Context
import android.content.Intent
import android.os.UserHandle
+import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.systemui.Dumpable
import com.android.systemui.ProtoDumpable
import com.android.systemui.dagger.SysUISingleton
@@ -62,7 +63,6 @@
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOn
-import com.android.app.tracing.coroutines.launchTraced as launch
import kotlinx.coroutines.withContext
/**
@@ -245,7 +245,6 @@
processExistingTile(
tileSpec,
specsToTiles.getValue(tileSpec),
- userChanged,
newUser,
) ?: createTile(tileSpec)
} else {
@@ -378,7 +377,6 @@
private fun processExistingTile(
tileSpec: TileSpec,
tileOrNotInstalled: TileOrNotInstalled,
- userChanged: Boolean,
user: Int,
): QSTile? {
return when (tileOrNotInstalled) {
@@ -386,6 +384,10 @@
is TileOrNotInstalled.Tile -> {
val qsTile = tileOrNotInstalled.tile
when {
+ qsTile.isDestroyed -> {
+ logger.logTileDestroyedIgnored(tileSpec)
+ null
+ }
!qsTile.isAvailable -> {
logger.logTileDestroyed(
tileSpec,
@@ -399,10 +401,11 @@
qsTile !is CustomTile -> {
// The tile is not a custom tile. Make sure they are reset to the correct
// user
- if (userChanged) {
+ if (qsTile.currentTileUser != user) {
qsTile.userSwitch(user)
logger.logTileUserChanged(tileSpec, user)
}
+
qsTile
}
qsTile.user == user -> {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLogger.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLogger.kt
index e237ca9..21a8ec6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLogger.kt
@@ -60,7 +60,7 @@
bool1 = usesDefault
int1 = user
},
- { "Parsed tiles (default=$bool1, user=$int1): $str1" }
+ { "Parsed tiles (default=$bool1, user=$int1): $str1" },
)
}
@@ -77,7 +77,7 @@
str2 = reconciledTiles.toString()
int1 = user
},
- { "Tiles restored and reconciled for user: $int1\nWas: $str1\nSet to: $str2" }
+ { "Tiles restored and reconciled for user: $int1\nWas: $str1\nSet to: $str2" },
)
}
@@ -94,7 +94,7 @@
str2 = newList.toString()
int1 = userId
},
- { "Processing $str1 for user $int1\nNew list: $str2" }
+ { "Processing $str1 for user $int1\nNew list: $str2" },
)
}
@@ -107,7 +107,16 @@
str1 = spec.toString()
str2 = reason.readable
},
- { "Tile $str1 destroyed. Reason: $str2" }
+ { "Tile $str1 destroyed. Reason: $str2" },
+ )
+ }
+
+ fun logTileDestroyedIgnored(spec: TileSpec) {
+ tileListLogBuffer.log(
+ TILE_LIST_TAG,
+ LogLevel.DEBUG,
+ { str1 = spec.toString() },
+ { "Tile $str1 ignored as it was already destroyed." },
)
}
@@ -117,7 +126,7 @@
TILE_LIST_TAG,
LogLevel.DEBUG,
{ str1 = spec.toString() },
- { "Tile $str1 created" }
+ { "Tile $str1 created" },
)
}
@@ -127,7 +136,7 @@
TILE_LIST_TAG,
LogLevel.VERBOSE,
{ str1 = spec.toString() },
- { "Tile $str1 not found in factory" }
+ { "Tile $str1 not found in factory" },
)
}
@@ -140,7 +149,7 @@
str1 = spec.toString()
int1 = user
},
- { "User changed to $int1 for tile $str1" }
+ { "User changed to $int1 for tile $str1" },
)
}
@@ -156,7 +165,7 @@
str1 = tiles.toString()
int1 = user
},
- { "Tiles kept for not installed packages for user $int1: $str1" }
+ { "Tiles kept for not installed packages for user $int1: $str1" },
)
}
@@ -168,7 +177,7 @@
str1 = tiles.toString()
int1 = userId
},
- { "Auto add tiles parsed for user $int1: $str1" }
+ { "Auto add tiles parsed for user $int1: $str1" },
)
}
@@ -180,7 +189,7 @@
str1 = tiles.toString()
int1 = userId
},
- { "Auto-add tiles reconciled for user $int1: $str1" }
+ { "Auto-add tiles reconciled for user $int1: $str1" },
)
}
@@ -193,7 +202,7 @@
int2 = position
str1 = spec.toString()
},
- { "Tile $str1 auto added for user $int1 at position $int2" }
+ { "Tile $str1 auto added for user $int1 at position $int2" },
)
}
@@ -205,7 +214,7 @@
int1 = userId
str1 = spec.toString()
},
- { "Tile $str1 auto removed for user $int1" }
+ { "Tile $str1 auto removed for user $int1" },
)
}
@@ -217,7 +226,7 @@
int1 = userId
str1 = spec.toString()
},
- { "Tile $str1 unmarked as auto-added for user $int1" }
+ { "Tile $str1 unmarked as auto-added for user $int1" },
)
}
@@ -226,7 +235,7 @@
RESTORE_TAG,
LogLevel.DEBUG,
{ int1 = userId },
- { "Restored from single intent after user setup complete for user $int1" }
+ { "Restored from single intent after user setup complete for user $int1" },
)
}
@@ -243,7 +252,7 @@
"Restored settings data for user $int1\n" +
"\tRestored tiles: $str1\n" +
"\tRestored auto added tiles: $str2"
- }
+ },
)
}
@@ -258,7 +267,7 @@
str1 = restoreProcessorClassName
str2 = step.name
},
- { "Restore $str2 processed by $str1" }
+ { "Restore $str2 processed by $str1" },
)
}
@@ -273,6 +282,6 @@
enum class RestorePreprocessorStep {
PREPROCESSING,
- POSTPROCESSING
+ POSTPROCESSING,
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
index 1d1e991..c6fc868 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -74,6 +74,8 @@
import java.io.PrintWriter;
import java.util.Objects;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* Base quick-settings tile, extend this to create a new tile.
@@ -127,6 +129,8 @@
private int mIsFullQs;
private final LifecycleRegistry mLifecycle = new LifecycleRegistry(this);
+ private final AtomicBoolean mIsDestroyed = new AtomicBoolean(false);
+ private final AtomicInteger mCurrentTileUser = new AtomicInteger();
/**
* Provides a new {@link TState} of the appropriate type to use between this tile and the
@@ -203,6 +207,7 @@
mMetricsLogger = metricsLogger;
mStatusBarStateController = statusBarStateController;
mActivityStarter = activityStarter;
+ mCurrentTileUser.set(host.getUserId());
resetStates();
mUiHandler.post(() -> mLifecycle.setCurrentState(CREATED));
@@ -352,11 +357,19 @@
}
public void userSwitch(int newUserId) {
+ mCurrentTileUser.set(newUserId);
mHandler.obtainMessage(H.USER_SWITCH, newUserId, 0).sendToTarget();
postStale();
}
+ @Override
+ public int getCurrentTileUser() {
+ return mCurrentTileUser.get();
+ }
+
public void destroy() {
+ // We mark it as soon as we start the destroy process, as nothing can interrupt it.
+ mIsDestroyed.set(true);
mHandler.sendEmptyMessage(H.DESTROY);
}
@@ -365,7 +378,7 @@
*
* Should be called upon creation of the tile, before performing other operations
*/
- public void initialize() {
+ public final void initialize() {
mHandler.sendEmptyMessage(H.INITIALIZE);
}
@@ -525,6 +538,11 @@
});
}
+ @Override
+ public final boolean isDestroyed() {
+ return mIsDestroyed.get();
+ }
+
protected void checkIfRestrictionEnforcedByAdminOnly(State state, String userRestriction) {
EnforcedAdmin admin = RestrictedLockUtilsInternal.checkIfRestrictionEnforced(mContext,
userRestriction, mHost.getUserId());
@@ -799,7 +817,7 @@
*/
@Override
public void dump(PrintWriter pw, String[] args) {
- pw.println(this.getClass().getSimpleName() + ":");
+ pw.print(this.getClass().getSimpleName() + ":");
pw.print(" "); pw.println(getState().toString());
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTileNewImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTileNewImpl.kt
index f80b8fb..e48e943 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTileNewImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTileNewImpl.kt
@@ -99,7 +99,7 @@
}
override fun getDetailsViewModel(): TileDetailsViewModel {
- return internetDetailsViewModelFactory.create { longClick(null) }
+ return internetDetailsViewModelFactory.create()
}
override fun handleUpdateState(state: QSTile.BooleanState, arg: Any?) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/QSTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/QSTileUserActionInteractor.kt
index e8c4274..8ad4e16 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/QSTileUserActionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/QSTileUserActionInteractor.kt
@@ -28,17 +28,4 @@
* It's safe to run long running computations inside this function.
*/
@WorkerThread suspend fun handleInput(input: QSTileInput<DATA_TYPE>)
-
- /**
- * Provides the [TileDetailsViewModel] for constructing the corresponding details view.
- *
- * This property is defined here to reuse the business logic. For example, reusing the user
- * long-click as the go-to-settings callback in the details view.
- * Subclasses can override this property to provide a specific [TileDetailsViewModel]
- * implementation.
- *
- * @return The [TileDetailsViewModel] instance, or null if not implemented.
- */
- val detailsViewModel: TileDetailsViewModel?
- get() = null
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelFactory.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelFactory.kt
index 8c75cf0..7f475f3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelFactory.kt
@@ -19,6 +19,7 @@
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.UiBackground
import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.plugins.qs.TileDetailsViewModel
import com.android.systemui.qs.pipeline.shared.TileSpec
import com.android.systemui.qs.tiles.base.analytics.QSTileAnalytics
import com.android.systemui.qs.tiles.base.interactor.DisabledByPolicyInteractor
@@ -70,9 +71,7 @@
* Creates [QSTileViewModelImpl] based on the interactors obtained from [QSTileComponent].
* Reference of that [QSTileComponent] is then stored along the view model.
*/
- fun create(
- tileSpec: TileSpec,
- ): QSTileViewModel {
+ fun create(tileSpec: TileSpec): QSTileViewModel {
val config = qsTileConfigProvider.getConfig(tileSpec.spec)
val component =
customTileComponentBuilder.qsTileConfigModule(QSTileConfigModule(config)).build()
@@ -90,6 +89,7 @@
backgroundDispatcher,
uiBackgroundDispatcher,
component.coroutineScope(),
+ /* tileDetailsViewModel= */ null,
)
}
}
@@ -127,6 +127,7 @@
userActionInteractor: QSTileUserActionInteractor<T>,
tileDataInteractor: QSTileDataInteractor<T>,
mapper: QSTileDataToStateMapper<T>,
+ tileDetailsViewModel: TileDetailsViewModel? = null,
): QSTileViewModelImpl<T> =
QSTileViewModelImpl(
qsTileConfigProvider.getConfig(tileSpec.spec),
@@ -142,6 +143,7 @@
backgroundDispatcher,
uiBackgroundDispatcher,
coroutineScopeFactory.create(),
+ tileDetailsViewModel,
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImpl.kt
index 30bf5b3..3866c17 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImpl.kt
@@ -83,6 +83,7 @@
private val backgroundDispatcher: CoroutineDispatcher,
uiBackgroundDispatcher: CoroutineDispatcher,
private val tileScope: CoroutineScope,
+ override val tileDetailsViewModel: TileDetailsViewModel? = null,
) : QSTileViewModel, Dumpable {
private val users: MutableStateFlow<UserHandle> =
@@ -96,6 +97,9 @@
private val tileData: SharedFlow<DATA_TYPE?> = createTileDataFlow()
+ override val currentTileUser: Int
+ get() = users.value.identifier
+
override val state: StateFlow<QSTileState?> =
tileData
.map { data ->
@@ -114,9 +118,6 @@
.flowOn(backgroundDispatcher)
.stateIn(tileScope, SharingStarted.WhileSubscribed(), true)
- override val detailsViewModel: TileDetailsViewModel?
- get() = userActionInteractor().detailsViewModel
-
override fun forceUpdate() {
tileScope.launch(context = backgroundDispatcher) { forceUpdates.emit(Unit) }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDetailsViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDetailsViewModel.kt
index 0ed56f6..6709fd2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDetailsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDetailsViewModel.kt
@@ -16,9 +16,11 @@
package com.android.systemui.qs.tiles.dialog
+import android.content.Intent
+import android.provider.Settings
import com.android.systemui.plugins.qs.TileDetailsViewModel
+import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandler
import com.android.systemui.statusbar.connectivity.AccessPointController
-import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
@@ -27,10 +29,13 @@
constructor(
private val accessPointController: AccessPointController,
val contentManagerFactory: InternetDetailsContentManager.Factory,
- @Assisted private val onLongClick: () -> Unit,
+ private val qsTileIntentUserActionHandler: QSTileIntentUserInputHandler,
) : TileDetailsViewModel() {
override fun clickOnSettingsButton() {
- onLongClick()
+ qsTileIntentUserActionHandler.handle(
+ /* expandable= */ null,
+ Intent(Settings.ACTION_WIFI_SETTINGS),
+ )
}
override fun getTitle(): String {
@@ -58,7 +63,7 @@
}
@AssistedFactory
- interface Factory {
- fun create(onLongClick: () -> Unit): InternetDetailsViewModel
+ fun interface Factory {
+ fun create(): InternetDetailsViewModel
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/di/QSTileComponent.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/di/QSTileComponent.kt
index 0ed46e7..5f692f2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/di/QSTileComponent.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/di/QSTileComponent.kt
@@ -16,6 +16,7 @@
package com.android.systemui.qs.tiles.impl.di
+import com.android.systemui.plugins.qs.TileDetailsViewModel
import com.android.systemui.qs.tiles.base.interactor.QSTileDataInteractor
import com.android.systemui.qs.tiles.base.interactor.QSTileDataToStateMapper
import com.android.systemui.qs.tiles.base.interactor.QSTileUserActionInteractor
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/internet/domain/interactor/InternetTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/internet/domain/interactor/InternetTileUserActionInteractor.kt
index 8e48fe4..0431e36 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/internet/domain/interactor/InternetTileUserActionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/internet/domain/interactor/InternetTileUserActionInteractor.kt
@@ -18,13 +18,10 @@
import android.content.Intent
import android.provider.Settings
-import com.android.systemui.animation.Expandable
import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.plugins.qs.TileDetailsViewModel
import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandler
import com.android.systemui.qs.tiles.base.interactor.QSTileInput
import com.android.systemui.qs.tiles.base.interactor.QSTileUserActionInteractor
-import com.android.systemui.qs.tiles.dialog.InternetDetailsViewModel
import com.android.systemui.qs.tiles.dialog.InternetDialogManager
import com.android.systemui.qs.tiles.impl.internet.domain.model.InternetTileModel
import com.android.systemui.qs.tiles.viewmodel.QSTileUserAction
@@ -41,7 +38,6 @@
private val internetDialogManager: InternetDialogManager,
private val accessPointController: AccessPointController,
private val qsTileIntentUserActionHandler: QSTileIntentUserInputHandler,
- private val internetDetailsViewModelFactory: InternetDetailsViewModel.Factory,
) : QSTileUserActionInteractor<InternetTileModel> {
override suspend fun handleInput(input: QSTileInput<InternetTileModel>): Unit =
@@ -58,16 +54,12 @@
}
}
is QSTileUserAction.LongClick -> {
- handleLongClick(action.expandable)
+ qsTileIntentUserActionHandler.handle(
+ action.expandable,
+ Intent(Settings.ACTION_WIFI_SETTINGS),
+ )
}
else -> {}
}
}
-
- override val detailsViewModel: TileDetailsViewModel =
- internetDetailsViewModelFactory.create { handleLongClick(null) }
-
- private fun handleLongClick(expandable: Expandable?) {
- qsTileIntentUserActionHandler.handle(expandable, Intent(Settings.ACTION_WIFI_SETTINGS))
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModel.kt
index e8b9926..7a53388 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModel.kt
@@ -39,9 +39,12 @@
val isAvailable: StateFlow<Boolean>
/** Specifies the [TileDetailsViewModel] for constructing the corresponding details view. */
- val detailsViewModel: TileDetailsViewModel?
+ val tileDetailsViewModel: TileDetailsViewModel?
get() = null
+ /** Returns the current user for this tile */
+ val currentTileUser: Int
+
/**
* Notifies about the user change. Implementations should avoid using 3rd party userId sources
* and use this value instead. This is to maintain consistent and concurrency-free behaviour
@@ -65,8 +68,6 @@
fun destroy()
}
-/**
- * Returns the immediate state of the tile or null if the state haven't been collected yet.
- */
+/** Returns the immediate state of the tile or null if the state haven't been collected yet. */
val QSTileViewModel.currentState: QSTileState?
get() = state.value
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt
index 30d1f05..e607eae 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt
@@ -19,7 +19,6 @@
import android.content.Context
import android.os.UserHandle
import android.util.Log
-import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.internal.logging.InstanceId
import com.android.systemui.Dumpable
import com.android.systemui.animation.Expandable
@@ -156,8 +155,12 @@
qsTileViewModel.onUserChanged(UserHandle.of(currentUser))
}
+ override fun getCurrentTileUser(): Int {
+ return qsTileViewModel.currentTileUser
+ }
+
override fun getDetailsViewModel(): TileDetailsViewModel? {
- return qsTileViewModel.detailsViewModel
+ return qsTileViewModel.tileDetailsViewModel
}
@Deprecated(
@@ -213,6 +216,10 @@
qsTileViewModel.destroy()
}
+ override fun isDestroyed(): Boolean {
+ return !(tileAdapterJob?.isActive ?: false)
+ }
+
override fun getState(): QSTile.AdapterState =
qsTileViewModel.currentState?.let { mapState(context, it, qsTileViewModel.config) }
?: QSTile.AdapterState()
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/StubQSTileViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/StubQSTileViewModel.kt
index 00b7e61..bdd5c73 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/StubQSTileViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/StubQSTileViewModel.kt
@@ -37,4 +37,7 @@
override fun onActionPerformed(userAction: QSTileUserAction) = error("Don't call stubs")
override fun destroy() = error("Don't call stubs")
+
+ override val currentTileUser: Int
+ get() = error("Don't call stubs")
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
index 13737dbff..934404d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -36,6 +36,7 @@
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.row.ExpandableView
+import com.android.systemui.statusbar.notification.shared.NotificationBundleUi
import com.android.systemui.statusbar.notification.stack.AmbientState
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
import com.android.systemui.statusbar.phone.CentralSurfaces
@@ -391,7 +392,9 @@
}
if (view is ExpandableNotificationRow) {
// Only drag down on sensitive views, otherwise the ExpandHelper will take this
- return view.entry.isSensitive.value
+ return if (NotificationBundleUi.isEnabled)
+ view.entryAdapter?.isSensitive?.value == true
+ else view.entry.isSensitive.value
}
}
return false
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/ConnectivityModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/ConnectivityModule.kt
index 10090283..48f0245 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/ConnectivityModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/ConnectivityModule.kt
@@ -34,6 +34,7 @@
import com.android.systemui.qs.tiles.NfcTile
import com.android.systemui.qs.tiles.base.interactor.QSTileAvailabilityInteractor
import com.android.systemui.qs.tiles.base.viewmodel.QSTileViewModelFactory
+import com.android.systemui.qs.tiles.dialog.InternetDetailsViewModel
import com.android.systemui.qs.tiles.impl.airplane.domain.AirplaneModeMapper
import com.android.systemui.qs.tiles.impl.airplane.domain.interactor.AirplaneModeTileDataInteractor
import com.android.systemui.qs.tiles.impl.airplane.domain.interactor.AirplaneModeTileUserActionInteractor
@@ -162,13 +163,15 @@
factory: QSTileViewModelFactory.Static<AirplaneModeTileModel>,
mapper: AirplaneModeMapper,
stateInteractor: AirplaneModeTileDataInteractor,
- userActionInteractor: AirplaneModeTileUserActionInteractor
+ userActionInteractor: AirplaneModeTileUserActionInteractor,
+ internetDetailsViewModelFactory: InternetDetailsViewModel.Factory
): QSTileViewModel =
factory.create(
TileSpec.create(AIRPLANE_MODE_TILE_SPEC),
userActionInteractor,
stateInteractor,
mapper,
+ internetDetailsViewModelFactory.create(),
)
@Provides
@@ -226,13 +229,15 @@
factory: QSTileViewModelFactory.Static<InternetTileModel>,
mapper: InternetTileMapper,
stateInteractor: InternetTileDataInteractor,
- userActionInteractor: InternetTileUserActionInteractor
+ userActionInteractor: InternetTileUserActionInteractor,
+ internetDetailsViewModelFactory: InternetDetailsViewModel.Factory
): QSTileViewModel =
factory.create(
TileSpec.create(INTERNET_TILE_SPEC),
userActionInteractor,
stateInteractor,
mapper,
+ internetDetailsViewModelFactory.create(),
)
@Provides
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTransitionAnimatorController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTransitionAnimatorController.kt
index 243a868..874a059 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTransitionAnimatorController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTransitionAnimatorController.kt
@@ -26,6 +26,7 @@
import com.android.systemui.statusbar.notification.headsup.HeadsUpManager
import com.android.systemui.statusbar.notification.headsup.HeadsUpUtil
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+import com.android.systemui.statusbar.notification.shared.NotificationBundleUi
import com.android.systemui.statusbar.notification.stack.NotificationListContainer
import kotlin.math.ceil
import kotlin.math.max
@@ -117,7 +118,7 @@
params.startNotificationTop = location[1]
params.notificationParentTop =
notificationListContainer
- .getViewParentForNotification(notificationEntry)
+ .getViewParentForNotification()
.locationOnScreen[1]
params.startRoundedTopClipping = roundedTopClipping
params.startClipTopAmount = notification.clipTopAmount
@@ -148,7 +149,7 @@
Log.d(TAG, reason)
}
notificationLaunchAnimationInteractor.setIsLaunchAnimationRunning(willAnimate)
- notificationEntry.isExpandAnimationRunning = willAnimate
+ notification.isLaunchAnimationRunning = willAnimate
if (!willAnimate) {
removeHun(animate = true, reason)
@@ -158,7 +159,8 @@
private val headsUpNotificationRow: ExpandableNotificationRow?
get() {
- val pipelineParent = notificationEntry.parent
+ val pipelineParent = if (NotificationBundleUi.isEnabled)
+ notification.entryAdapter?.parent else notificationEntry.parent
val summaryEntry = (pipelineParent as? GroupEntry)?.summary
return when {
headsUpManager.isHeadsUpEntry(notificationKey) -> notification
@@ -190,7 +192,7 @@
// TODO(b/184121838): Should we call InteractionJankMonitor.cancel if the animation started
// here?
notificationLaunchAnimationInteractor.setIsLaunchAnimationRunning(false)
- notificationEntry.isExpandAnimationRunning = false
+ notification.isLaunchAnimationRunning = false
removeHun(animate = true, "onLaunchAnimationCancelled()")
onFinishAnimationCallback?.run()
}
@@ -210,7 +212,7 @@
notification.isExpandAnimationRunning = false
notificationLaunchAnimationInteractor.setIsLaunchAnimationRunning(false)
- notificationEntry.isExpandAnimationRunning = false
+ notification.isLaunchAnimationRunning = false
notificationListContainer.setExpandingNotification(null)
applyParams(null)
removeHun(animate = false, "onLaunchAnimationEnd()")
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
index 9ed1632..c2f0806 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
@@ -136,9 +136,7 @@
@NonNull NotifInflater.Params params,
NotificationRowContentBinder.InflationCallback callback)
throws InflationException {
- //TODO(b/217799515): Remove the entry parameter from getViewParentForNotification(), this
- // function returns the NotificationStackScrollLayout regardless of the entry.
- ViewGroup parent = mListContainer.getViewParentForNotification(entry);
+ ViewGroup parent = mListContainer.getViewParentForNotification();
if (entry.rowExists()) {
mLogger.logUpdatingRow(entry, params);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java
index 25deec3..d09546f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java
@@ -391,7 +391,7 @@
if (!notificationFooterBackgroundTintOptimization()) {
if (notificationShadeBlur()) {
Color backgroundColor = Color.valueOf(
- SurfaceEffectColors.surfaceEffect1(getResources()));
+ SurfaceEffectColors.surfaceEffect1(getContext()));
scHigh = ColorUtils.setAlphaComponent(backgroundColor.toArgb(), 0xFF);
// Apply alpha on background drawables.
int backgroundAlpha = (int) (backgroundColor.alpha() * 0xFF);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java
index 7c5f3b5..5157e7a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java
@@ -332,7 +332,9 @@
onEntryAdded(headsUpEntry, requestedPinnedStatus);
// TODO(b/328390331) move accessibility events to the view layer
entry.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
- entry.setIsHeadsUpEntry(true);
+ if (!NotificationBundleUi.isEnabled()) {
+ entry.setIsHeadsUpEntry(true);
+ }
updateNotificationInternal(entry.getKey(), requestedPinnedStatus);
entry.setInterruption();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
index 4ed9dce..a081ad5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
@@ -129,7 +129,7 @@
private void updateColors() {
if (notificationRowTransparency()) {
- mNormalColor = SurfaceEffectColors.surfaceEffect1(getResources());
+ mNormalColor = SurfaceEffectColors.surfaceEffect1(getContext());
} else {
mNormalColor = mContext.getColor(
com.android.internal.R.color.materialColorSurfaceContainerHigh);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 6134d1d..185e7fa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -300,6 +300,7 @@
private boolean mIsSystemChildExpanded;
private PinnedStatus mPinnedStatus = PinnedStatus.NotPinned;
private boolean mExpandAnimationRunning;
+ private boolean mLaunchAnimationRunning;
private AboveShelfChangedListener mAboveShelfChangedListener;
private HeadsUpManager mHeadsUpManager;
private Consumer<Boolean> mHeadsUpAnimatingAwayListener;
@@ -4487,4 +4488,22 @@
}
mLogger.logRemoveTransientRow(row.getLoggingKey(), mLoggingKey);
}
+
+ /** Set whether this notification is currently used to animate a launch. */
+ public void setLaunchAnimationRunning(boolean launchAnimationRunning) {
+ if (NotificationBundleUi.isEnabled()) {
+ mLaunchAnimationRunning = launchAnimationRunning;
+ } else {
+ getEntry().setExpandAnimationRunning(launchAnimationRunning);
+ }
+ }
+
+ /** Whether this notification is currently used to animate a launch. */
+ public boolean isLaunchAnimationRunning() {
+ if (NotificationBundleUi.isEnabled()) {
+ return mLaunchAnimationRunning;
+ } else {
+ return getEntry().isExpandAnimationRunning();
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java
index 33c36d8c..c0bc132 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java
@@ -88,7 +88,7 @@
mDarkColoredStatefulColors = getResources().getColorStateList(
R.color.notification_state_color_dark);
if (notificationRowTransparency()) {
- mNormalColor = SurfaceEffectColors.surfaceEffect1(getResources());
+ mNormalColor = SurfaceEffectColors.surfaceEffect1(getContext());
} else {
mNormalColor = mContext.getColor(
com.android.internal.R.color.materialColorSurfaceContainerHigh);
@@ -321,7 +321,7 @@
new PorterDuffColorFilter(
isColorized()
? ColorUtils.setAlphaComponent(mTintColor, (int) (255 * 0.9f))
- : SurfaceEffectColors.surfaceEffect1(getResources()),
+ : SurfaceEffectColors.surfaceEffect1(getContext()),
PorterDuff.Mode.SRC)); // SRC operator discards the drawable's color+alpha
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
index ab382df..e89a76f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
@@ -16,7 +16,7 @@
package com.android.systemui.statusbar.notification.row;
-import static android.app.NotificationChannel.SYSTEM_RESERVED_IDS;
+import static android.app.Flags.notificationsRedesignTemplates;
import static android.view.HapticFeedbackConstants.CLOCK_TICK;
import static com.android.systemui.SwipeHelper.SWIPED_FAR_ENOUGH_SIZE_FRACTION;
@@ -706,8 +706,11 @@
static NotificationMenuItem createInfoItem(Context context) {
Resources res = context.getResources();
String infoDescription = res.getString(R.string.notification_menu_gear_description);
+ int layoutId = notificationsRedesignTemplates()
+ ? R.layout.notification_2025_info
+ : R.layout.notification_info;
NotificationInfo infoContent = (NotificationInfo) LayoutInflater.from(context).inflate(
- R.layout.notification_info, null, false);
+ layoutId, null, false);
return new NotificationMenuItem(context, infoDescription, infoContent,
R.drawable.ic_settings);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
index 64ca815..1e24952 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
@@ -35,8 +35,10 @@
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.data.repository.HeadsUpRepository;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
+import com.android.systemui.statusbar.notification.shared.NotificationBundleUi;
import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.BypassController;
import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.SectionProvider;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
@@ -60,6 +62,7 @@
private final BypassController mBypassController;
private final LargeScreenShadeInterpolator mLargeScreenShadeInterpolator;
private final AvalancheController mAvalancheController;
+ private final HeadsUpRepository mHeadsUpRepository;
/**
* Used to read bouncer states.
@@ -304,6 +307,7 @@
@NonNull BypassController bypassController,
@Nullable StatusBarKeyguardViewManager statusBarKeyguardViewManager,
@NonNull LargeScreenShadeInterpolator largeScreenShadeInterpolator,
+ @NonNull HeadsUpRepository headsUpRepository,
AvalancheController avalancheController
) {
mSectionProvider = sectionProvider;
@@ -311,6 +315,7 @@
mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
mLargeScreenShadeInterpolator = largeScreenShadeInterpolator;
mAvalancheController = avalancheController;
+ mHeadsUpRepository = headsUpRepository;
reload(context);
dumpManager.registerDumpable(this);
}
@@ -690,7 +695,10 @@
}
public boolean isPulsing(NotificationEntry entry) {
- return mPulsing && entry.isHeadsUpEntry();
+ boolean isHeadsUp = NotificationBundleUi.isEnabled()
+ ? mHeadsUpRepository.isHeadsUpEntry(entry.getKey())
+ : entry.isHeadsUpEntry();
+ return mPulsing && isHeadsUp;
}
public void setPulsingRow(ExpandableNotificationRow row) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImpl.kt
index da98858..9bd5a5b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImpl.kt
@@ -291,7 +291,7 @@
* currently being swiped. From the center outwards, the multipliers apply to the neighbors
* of the swiped view.
*/
- private val MAGNETIC_TRANSLATION_MULTIPLIERS = listOf(0.18f, 0.28f, 0.5f, 0.28f, 0.18f)
+ private val MAGNETIC_TRANSLATION_MULTIPLIERS = listOf(0.04f, 0.12f, 0.5f, 0.12f, 0.04f)
const val MAGNETIC_REDUCTION = 0.65f
@@ -299,7 +299,7 @@
private const val DETACH_STIFFNESS = 800f
private const val DETACH_DAMPING_RATIO = 0.95f
private const val SNAP_BACK_STIFFNESS = 550f
- private const val SNAP_BACK_DAMPING_RATIO = 0.52f
+ private const val SNAP_BACK_DAMPING_RATIO = 0.6f
// Maximum value of corner roundness that gets applied during the pre-detach dragging
private const val MAX_PRE_DETACH_ROUNDNESS = 0.8f
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
index f85545e..47fc2fb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
@@ -113,10 +113,9 @@
/**
* Get the view parent for a notification entry. For example, NotificationStackScrollLayout.
*
- * @param entry entry to get the view parent for
* @return the view parent for entry
*/
- ViewGroup getViewParentForNotification(NotificationEntry entry);
+ ViewGroup getViewParentForNotification();
/**
* Resets the currently exposed menu view.
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 6313258..e7a77eb 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
@@ -2134,7 +2134,7 @@
}
}
- public ViewGroup getViewParentForNotification(NotificationEntry entry) {
+ public ViewGroup getViewParentForNotification() {
return this;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index 5c96470..4459430 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -1908,8 +1908,8 @@
}
@Override
- public ViewGroup getViewParentForNotification(NotificationEntry entry) {
- return mView.getViewParentForNotification(entry);
+ public ViewGroup getViewParentForNotification() {
+ return mView.getViewParentForNotification();
}
@Override
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 955de273..7101df1 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
@@ -85,10 +85,12 @@
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
+import com.android.systemui.statusbar.notification.data.repository.HeadsUpRepository;
import com.android.systemui.statusbar.notification.emptyshade.shared.ModesEmptyShadeFix;
import com.android.systemui.statusbar.notification.emptyshade.ui.view.EmptyShadeView;
import com.android.systemui.statusbar.notification.footer.ui.view.FooterView;
import com.android.systemui.statusbar.notification.headsup.AvalancheController;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun;
@@ -157,6 +159,7 @@
@Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@Mock private LargeScreenShadeInterpolator mLargeScreenShadeInterpolator;
@Mock private AvalancheController mAvalancheController;
+ @Mock private HeadsUpRepository mHeadsUpRepository;
public NotificationStackScrollLayoutTest(FlagsParameterization flags) {
super();
@@ -176,6 +179,7 @@
mBypassController,
mStatusBarKeyguardViewManager,
mLargeScreenShadeInterpolator,
+ mHeadsUpRepository,
mAvalancheController
));
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/FakeQSTile.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/FakeQSTile.kt
index 4714969..c7ea6db 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/FakeQSTile.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/FakeQSTile.kt
@@ -22,7 +22,7 @@
class FakeQSTile(var user: Int, var available: Boolean = true) : QSTile {
private var tileSpec: String? = null
- var destroyed = false
+ private var destroyed = false
var hasDetailsViewModel: Boolean = true
private var state = QSTile.State()
val callbacks = mutableListOf<QSTile.Callback>()
@@ -64,6 +64,10 @@
user = currentUser
}
+ override fun getCurrentTileUser(): Int {
+ return user
+ }
+
override fun getMetricsCategory(): Int {
return 0
}
@@ -76,6 +80,10 @@
destroyed = true
}
+ override fun isDestroyed(): Boolean {
+ return destroyed
+ }
+
override fun getTileLabel(): CharSequence {
return ""
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/external/TileLifecycleManagerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/external/TileLifecycleManagerKosmos.kt
index 4978558..f038fdd 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/external/TileLifecycleManagerKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/external/TileLifecycleManagerKosmos.kt
@@ -26,7 +26,7 @@
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.time.fakeSystemClock
-val Kosmos.tileLifecycleManagerFactory: TileLifecycleManager.Factory by
+var Kosmos.tileLifecycleManagerFactory: TileLifecycleManager.Factory by
Kosmos.Fixture {
TileLifecycleManager.Factory { intent, userHandle ->
TileLifecycleManager(
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLoggerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLoggerKosmos.kt
index 7d52f5d..c153183 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLoggerKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLoggerKosmos.kt
@@ -17,7 +17,14 @@
package com.android.systemui.qs.pipeline.shared.logging
import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.util.mockito.mock
+import com.android.systemui.log.logcatLogBuffer
/** mock */
-var Kosmos.qsLogger: QSPipelineLogger by Kosmos.Fixture { mock<QSPipelineLogger>() }
+var Kosmos.qsLogger: QSPipelineLogger by
+ Kosmos.Fixture {
+ QSPipelineLogger(
+ logcatLogBuffer(QSPipelineLogger.TILE_LIST_TAG),
+ logcatLogBuffer(QSPipelineLogger.AUTO_ADD_TAG),
+ logcatLogBuffer(QSPipelineLogger.RESTORE_TAG),
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/interactor/FakeQSTileUserActionInteractor.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/interactor/FakeQSTileUserActionInteractor.kt
index bc1c60c..c058490 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/interactor/FakeQSTileUserActionInteractor.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/interactor/FakeQSTileUserActionInteractor.kt
@@ -33,7 +33,4 @@
override suspend fun handleInput(input: QSTileInput<T>) {
mutex.withLock { mutableInputs.add(input) }
}
-
- override var detailsViewModel: TileDetailsViewModel? =
- FakeTileDetailsViewModel("FakeQSTileUserActionInteractor")
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/di/NewQSTileFactoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/di/NewQSTileFactoryKosmos.kt
index 6787b8e..c223be4 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/di/NewQSTileFactoryKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/di/NewQSTileFactoryKosmos.kt
@@ -19,6 +19,7 @@
import android.os.UserHandle
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.qs.instanceIdSequenceFake
+import com.android.systemui.qs.pipeline.domain.interactor.currentTilesInteractor
import com.android.systemui.qs.pipeline.shared.TileSpec
import com.android.systemui.qs.shared.model.TileCategory
import com.android.systemui.qs.tiles.base.viewmodel.QSTileViewModelFactory
@@ -56,7 +57,11 @@
override val config: QSTileConfig = config
override val isAvailable: StateFlow<Boolean> = MutableStateFlow(true)
- override fun onUserChanged(user: UserHandle) {}
+ override var currentTileUser = currentTilesInteractor.userId.value
+
+ override fun onUserChanged(user: UserHandle) {
+ currentTileUser = user.identifier
+ }
override fun forceUpdate() {}
@@ -68,7 +73,7 @@
}
}
-val Kosmos.newQSTileFactory by
+var Kosmos.newQSTileFactory by
Kosmos.Fixture {
NewQSTileFactory(
qSTileConfigProvider,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/AmbientStateKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/AmbientStateKosmos.kt
index d65a4a0..4f1bf95 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/AmbientStateKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/AmbientStateKosmos.kt
@@ -22,6 +22,7 @@
import com.android.systemui.kosmos.Kosmos.Fixture
import com.android.systemui.shade.transition.largeScreenShadeInterpolator
import com.android.systemui.statusbar.notification.headsup.mockAvalancheController
+import com.android.systemui.statusbar.notification.stack.data.repository.headsUpNotificationRepository
import com.android.systemui.statusbar.phone.statusBarKeyguardViewManager
val Kosmos.ambientState by Fixture {
@@ -32,6 +33,7 @@
/*bypassController=*/ stackScrollAlgorithmBypassController,
/*statusBarKeyguardViewManager=*/ statusBarKeyguardViewManager,
/*largeScreenShadeInterpolator=*/ largeScreenShadeInterpolator,
+ /*headsUpRepository=*/ headsUpNotificationRepository,
/*avalancheController=*/ mockAvalancheController,
)
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index 4b04248..47aa8f5 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -1115,14 +1115,12 @@
if (svcConnTracingEnabled()) {
logTraceSvcConn("performGlobalAction", "action=" + action);
}
- int currentUserId;
synchronized (mLock) {
if (!hasRightsToCurrentUserLocked()) {
return false;
}
- currentUserId = mSystemSupport.getCurrentUserIdLocked();
}
- enforceCurrentUserIfVisibleBackgroundEnabled(currentUserId);
+ enforceCurrentUserIfVisibleBackgroundEnabled();
final long identity = Binder.clearCallingIdentity();
try {
return mSystemActionPerformer.performSystemAction(action);
@@ -2791,11 +2789,7 @@
@RequiresNoPermission
@Override
public void setAnimationScale(float scale) {
- int currentUserId;
- synchronized (mLock) {
- currentUserId = mSystemSupport.getCurrentUserIdLocked();
- }
- enforceCurrentUserIfVisibleBackgroundEnabled(currentUserId);
+ enforceCurrentUserIfVisibleBackgroundEnabled();
final long identity = Binder.clearCallingIdentity();
try {
Settings.Global.putFloat(
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 9eb8442..1c95184 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -1402,11 +1402,7 @@
@EnforcePermission(MANAGE_ACCESSIBILITY)
public void registerSystemAction(RemoteAction action, int actionId) {
registerSystemAction_enforcePermission();
- int currentUserId;
- synchronized (mLock) {
- currentUserId = mCurrentUserId;
- }
- enforceCurrentUserIfVisibleBackgroundEnabled(currentUserId);
+ enforceCurrentUserIfVisibleBackgroundEnabled();
if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
mTraceManager.logTrace(LOG_TAG + ".registerSystemAction",
FLAGS_ACCESSIBILITY_MANAGER, "action=" + action + ";actionId=" + actionId);
@@ -1423,11 +1419,7 @@
@EnforcePermission(MANAGE_ACCESSIBILITY)
public void unregisterSystemAction(int actionId) {
unregisterSystemAction_enforcePermission();
- int currentUserId;
- synchronized (mLock) {
- currentUserId = mCurrentUserId;
- }
- enforceCurrentUserIfVisibleBackgroundEnabled(currentUserId);
+ enforceCurrentUserIfVisibleBackgroundEnabled();
if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
mTraceManager.logTrace(LOG_TAG + ".unregisterSystemAction",
FLAGS_ACCESSIBILITY_MANAGER, "actionId=" + actionId);
@@ -1759,7 +1751,7 @@
synchronized (mLock) {
currentUserId = mCurrentUserId;
}
- enforceCurrentUserIfVisibleBackgroundEnabled(currentUserId);
+ enforceCurrentUserIfVisibleBackgroundEnabled();
if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
mTraceManager.logTrace(LOG_TAG + ".notifyAccessibilityButtonClicked",
FLAGS_ACCESSIBILITY_MANAGER,
@@ -1807,11 +1799,7 @@
@EnforcePermission(STATUS_BAR_SERVICE)
public void notifyAccessibilityButtonVisibilityChanged(boolean shown) {
notifyAccessibilityButtonVisibilityChanged_enforcePermission();
- int currentUserId;
- synchronized (mLock) {
- currentUserId = mCurrentUserId;
- }
- enforceCurrentUserIfVisibleBackgroundEnabled(currentUserId);
+ enforceCurrentUserIfVisibleBackgroundEnabled();
if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
mTraceManager.logTrace(LOG_TAG + ".notifyAccessibilityButtonVisibilityChanged",
FLAGS_ACCESSIBILITY_MANAGER, "shown=" + shown);
@@ -5002,11 +4990,7 @@
throws RemoteException {
registerProxyForDisplay_enforcePermission();
mSecurityPolicy.checkForAccessibilityPermissionOrRole();
- int currentUserId;
- synchronized (mLock) {
- currentUserId = mCurrentUserId;
- }
- enforceCurrentUserIfVisibleBackgroundEnabled(currentUserId);
+ enforceCurrentUserIfVisibleBackgroundEnabled();
if (client == null) {
return false;
}
diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
index bd34f33..c182c26 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
@@ -149,7 +149,6 @@
OperationStorage mOperationStorage;
List<PackageInfo> mPackages;
- PackageInfo mCurrentPackage;
boolean mUpdateSchedule;
CountDownLatch mLatch;
FullBackupJob mJob; // if a scheduled job needs to be finished afterwards
@@ -207,10 +206,9 @@
for (String pkg : whichPackages) {
try {
PackageManager pm = backupManagerService.getPackageManager();
- PackageInfo info = pm.getPackageInfoAsUser(pkg,
+ PackageInfo packageInfo = pm.getPackageInfoAsUser(pkg,
PackageManager.GET_SIGNING_CERTIFICATES, mUserId);
- mCurrentPackage = info;
- if (!mBackupEligibilityRules.appIsEligibleForBackup(info.applicationInfo)) {
+ if (!mBackupEligibilityRules.appIsEligibleForBackup(packageInfo.applicationInfo)) {
// Cull any packages that have indicated that backups are not permitted,
// that run as system-domain uids but do not define their own backup agents,
// as well as any explicit mention of the 'special' shared-storage agent
@@ -220,13 +218,13 @@
}
mBackupManagerMonitorEventSender.monitorEvent(
BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_INELIGIBLE,
- mCurrentPackage,
+ packageInfo,
BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
- null);
+ /* extras= */ null);
BackupObserverUtils.sendBackupOnPackageResult(mBackupObserver, pkg,
BackupManager.ERROR_BACKUP_NOT_ALLOWED);
continue;
- } else if (!mBackupEligibilityRules.appGetsFullBackup(info)) {
+ } else if (!mBackupEligibilityRules.appGetsFullBackup(packageInfo)) {
// Cull any packages that are found in the queue but now aren't supposed
// to get full-data backup operations.
if (DEBUG) {
@@ -235,13 +233,13 @@
}
mBackupManagerMonitorEventSender.monitorEvent(
BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_KEY_VALUE_PARTICIPANT,
- mCurrentPackage,
+ packageInfo,
BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
- null);
+ /* extras= */ null);
BackupObserverUtils.sendBackupOnPackageResult(mBackupObserver, pkg,
BackupManager.ERROR_BACKUP_NOT_ALLOWED);
continue;
- } else if (mBackupEligibilityRules.appIsStopped(info.applicationInfo)) {
+ } else if (mBackupEligibilityRules.appIsStopped(packageInfo.applicationInfo)) {
// Cull any packages in the 'stopped' state: they've either just been
// installed or have explicitly been force-stopped by the user. In both
// cases we do not want to launch them for backup.
@@ -250,21 +248,21 @@
}
mBackupManagerMonitorEventSender.monitorEvent(
BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_STOPPED,
- mCurrentPackage,
+ packageInfo,
BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
- null);
+ /* extras= */ null);
BackupObserverUtils.sendBackupOnPackageResult(mBackupObserver, pkg,
BackupManager.ERROR_BACKUP_NOT_ALLOWED);
continue;
}
- mPackages.add(info);
+ mPackages.add(packageInfo);
} catch (NameNotFoundException e) {
Slog.i(TAG, "Requested package " + pkg + " not found; ignoring");
mBackupManagerMonitorEventSender.monitorEvent(
BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_NOT_FOUND,
- mCurrentPackage,
+ /* pkg= */ null,
BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
- null);
+ /* extras= */ null);
}
}
@@ -352,10 +350,11 @@
} else {
monitoringEvent = BackupManagerMonitor.LOG_EVENT_ID_DEVICE_NOT_PROVISIONED;
}
- mBackupManagerMonitorEventSender
- .monitorEvent(monitoringEvent, null,
- BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
- null);
+ mBackupManagerMonitorEventSender.monitorEvent(
+ monitoringEvent,
+ /* pkg= */ null,
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
+ /* extras= */ null);
mUpdateSchedule = false;
backupRunStatus = BackupManager.ERROR_BACKUP_NOT_ALLOWED;
return;
@@ -367,8 +366,9 @@
backupRunStatus = BackupManager.ERROR_TRANSPORT_ABORTED;
mBackupManagerMonitorEventSender.monitorEvent(
BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_TRANSPORT_NOT_PRESENT,
- mCurrentPackage, BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT,
- null);
+ /* pkg= */ null,
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT,
+ /* extras= */ null);
return;
}
@@ -461,9 +461,10 @@
}
mBackupManagerMonitorEventSender.monitorEvent(
BackupManagerMonitor.LOG_EVENT_ID_ERROR_PREFLIGHT,
- mCurrentPackage,
+ currentPackage,
BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
- mBackupManagerMonitorEventSender.putMonitoringExtra(null,
+ BackupManagerMonitorEventSender.putMonitoringExtra(
+ /* extras= */ null,
BackupManagerMonitor.EXTRA_LOG_PREFLIGHT_ERROR,
preflightResult));
backupPackageStatus = (int) preflightResult;
@@ -496,9 +497,9 @@
+ ": " + totalRead + " of " + quota);
mBackupManagerMonitorEventSender.monitorEvent(
BackupManagerMonitor.LOG_EVENT_ID_QUOTA_HIT_PREFLIGHT,
- mCurrentPackage,
+ currentPackage,
BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT,
- null);
+ /* extras= */ null);
mBackupRunner.sendQuotaExceeded(totalRead, quota);
}
}
@@ -645,9 +646,9 @@
Slog.w(TAG, "Exception trying full transport backup", e);
mBackupManagerMonitorEventSender.monitorEvent(
BackupManagerMonitor.LOG_EVENT_ID_EXCEPTION_FULL_BACKUP,
- mCurrentPackage,
+ /* pkg= */ null,
BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
- mBackupManagerMonitorEventSender.putMonitoringExtra(null,
+ BackupManagerMonitorEventSender.putMonitoringExtra(/* extras= */ null,
BackupManagerMonitor.EXTRA_LOG_EXCEPTION_FULL_BACKUP,
Log.getStackTraceString(e)));
@@ -966,9 +967,6 @@
}
}
-
- // BackupRestoreTask interface: specifically, timeout detection
-
@Override
public void execute() { /* intentionally empty */ }
@@ -981,7 +979,9 @@
mBackupManagerMonitorEventSender.monitorEvent(
BackupManagerMonitor.LOG_EVENT_ID_FULL_BACKUP_CANCEL,
- mCurrentPackage, BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT, null);
+ mTarget,
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT,
+ /* extras= */ null);
mIsCancelled = true;
// Cancel tasks spun off by this task.
mUserBackupManagerService.handleCancel(mEphemeralToken, cancelAll);
diff --git a/services/backup/java/com/android/server/backup/utils/BackupManagerMonitorEventSender.java b/services/backup/java/com/android/server/backup/utils/BackupManagerMonitorEventSender.java
index c4519b1..33668a6 100644
--- a/services/backup/java/com/android/server/backup/utils/BackupManagerMonitorEventSender.java
+++ b/services/backup/java/com/android/server/backup/utils/BackupManagerMonitorEventSender.java
@@ -71,6 +71,7 @@
mMonitor = monitor;
}
+ @Nullable
public IBackupManagerMonitor getMonitor() {
return mMonitor;
}
@@ -87,9 +88,9 @@
*/
public void monitorEvent(
int id,
- PackageInfo pkg,
+ @Nullable PackageInfo pkg,
int category,
- Bundle extras) {
+ @Nullable Bundle extras) {
try {
Bundle bundle = new Bundle();
bundle.putInt(BackupManagerMonitor.EXTRA_LOG_EVENT_ID, id);
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index b6fe0ad..e46bbe2 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -160,6 +160,7 @@
import com.android.server.pm.Installer;
import com.android.server.pm.UserManagerInternal;
import com.android.server.storage.AppFuseBridge;
+import com.android.server.storage.ImmutableVolumeInfo;
import com.android.server.storage.StorageSessionController;
import com.android.server.storage.StorageSessionController.ExternalStorageServiceException;
import com.android.server.storage.WatchedVolumeInfo;
@@ -777,7 +778,7 @@
break;
}
case H_VOLUME_UNMOUNT: {
- final WatchedVolumeInfo vol = (WatchedVolumeInfo) msg.obj;
+ final ImmutableVolumeInfo vol = (ImmutableVolumeInfo) msg.obj;
unmount(vol);
break;
}
@@ -898,8 +899,14 @@
for (int i = 0; i < size; i++) {
final WatchedVolumeInfo vol = mVolumes.valueAt(i);
if (vol.getMountUserId() == userId) {
+ // Capture the volume before we set mount user id to null,
+ // so that StorageSessionController remove the session from
+ // the correct user (old mount user id)
+ final ImmutableVolumeInfo volToUnmount
+ = vol.getClonedImmutableVolumeInfo();
vol.setMountUserId(UserHandle.USER_NULL);
- mHandler.obtainMessage(H_VOLUME_UNMOUNT, vol).sendToTarget();
+ mHandler.obtainMessage(H_VOLUME_UNMOUNT, volToUnmount)
+ .sendToTarget();
}
}
}
@@ -1295,7 +1302,12 @@
}
private void maybeRemountVolumes(int userId) {
- List<WatchedVolumeInfo> volumesToRemount = new ArrayList<>();
+ // We need to keep 2 lists
+ // 1. List of volumes before we set the mount user Id so that
+ // StorageSessionController is able to remove the session from the correct user (old one)
+ // 2. List of volumes to mount which should have the up to date info
+ List<ImmutableVolumeInfo> volumesToUnmount = new ArrayList<>();
+ List<WatchedVolumeInfo> volumesToMount = new ArrayList<>();
synchronized (mLock) {
for (int i = 0; i < mVolumes.size(); i++) {
final WatchedVolumeInfo vol = mVolumes.valueAt(i);
@@ -1303,16 +1315,19 @@
&& vol.getMountUserId() != mCurrentUserId) {
// If there's a visible secondary volume mounted,
// we need to update the currentUserId and remount
+ // But capture the volume with the old user id first to use it in unmounting
+ volumesToUnmount.add(vol.getClonedImmutableVolumeInfo());
vol.setMountUserId(mCurrentUserId);
- volumesToRemount.add(vol);
+ volumesToMount.add(vol);
}
}
}
- for (WatchedVolumeInfo vol : volumesToRemount) {
- Slog.i(TAG, "Remounting volume for user: " + userId + ". Volume: " + vol);
- mHandler.obtainMessage(H_VOLUME_UNMOUNT, vol).sendToTarget();
- mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
+ for (int i = 0; i < volumesToMount.size(); i++) {
+ Slog.i(TAG, "Remounting volume for user: " + userId + ". Volume: "
+ + volumesToUnmount.get(i));
+ mHandler.obtainMessage(H_VOLUME_UNMOUNT, volumesToUnmount.get(i)).sendToTarget();
+ mHandler.obtainMessage(H_VOLUME_MOUNT, volumesToMount.get(i)).sendToTarget();
}
}
@@ -2430,10 +2445,10 @@
super.unmount_enforcePermission();
final WatchedVolumeInfo vol = findVolumeByIdOrThrow(volId);
- unmount(vol);
+ unmount(vol.getClonedImmutableVolumeInfo());
}
- private void unmount(WatchedVolumeInfo vol) {
+ private void unmount(ImmutableVolumeInfo vol) {
try {
try {
if (vol.getType() == VolumeInfo.TYPE_PRIVATE) {
@@ -2444,7 +2459,7 @@
}
extendWatchdogTimeout("#unmount might be slow");
mVold.unmount(vol.getId());
- mStorageSessionController.onVolumeUnmount(vol.getImmutableVolumeInfo());
+ mStorageSessionController.onVolumeUnmount(vol);
} catch (Exception e) {
Slog.wtf(TAG, e);
}
diff --git a/services/core/java/com/android/server/SystemTimeZone.java b/services/core/java/com/android/server/SystemTimeZone.java
index dd07081..c8810f6 100644
--- a/services/core/java/com/android/server/SystemTimeZone.java
+++ b/services/core/java/com/android/server/SystemTimeZone.java
@@ -133,6 +133,7 @@
boolean timeZoneChanged = false;
synchronized (SystemTimeZone.class) {
String currentTimeZoneId = getTimeZoneId();
+ @TimeZoneConfidence int currentConfidence = getTimeZoneConfidence();
if (currentTimeZoneId == null || !currentTimeZoneId.equals(timeZoneId)) {
SystemProperties.set(TIME_ZONE_SYSTEM_PROPERTY, timeZoneId);
if (DEBUG) {
@@ -145,6 +146,8 @@
String logMsg = "Time zone or confidence set: "
+ " (new) timeZoneId=" + timeZoneId
+ ", (new) confidence=" + confidence
+ + ", (old) timeZoneId=" + currentTimeZoneId
+ + ", (old) confidence=" + currentConfidence
+ ", logInfo=" + logInfo;
addDebugLogEntry(logMsg);
}
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 8eda176..296f7cf 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -907,7 +907,7 @@
throw new IllegalArgumentException("Unknown mode: " + mode);
}
- enforceCurrentUserIfVisibleBackgroundEnabled(mCurrentUser);
+ enforceCurrentUserIfVisibleBackgroundEnabled();
final int user = UserHandle.getCallingUserId();
final long ident = Binder.clearCallingIdentity();
@@ -970,7 +970,7 @@
@AttentionModeThemeOverlayType int attentionModeThemeOverlayType) {
setAttentionModeThemeOverlay_enforcePermission();
- enforceCurrentUserIfVisibleBackgroundEnabled(mCurrentUser);
+ enforceCurrentUserIfVisibleBackgroundEnabled();
synchronized (mLock) {
if (mAttentionModeThemeOverlay != attentionModeThemeOverlayType) {
@@ -1070,7 +1070,7 @@
return false;
}
- enforceCurrentUserIfVisibleBackgroundEnabled(mCurrentUser);
+ enforceCurrentUserIfVisibleBackgroundEnabled();
// Store the last requested bedtime night mode state so that we don't need to notify
// anyone if the user decides to switch to the night mode to bedtime.
@@ -1124,7 +1124,7 @@
return;
}
- enforceCurrentUserIfVisibleBackgroundEnabled(mCurrentUser);
+ enforceCurrentUserIfVisibleBackgroundEnabled();
final int user = UserHandle.getCallingUserId();
final long ident = Binder.clearCallingIdentity();
@@ -1155,7 +1155,7 @@
return;
}
- enforceCurrentUserIfVisibleBackgroundEnabled(mCurrentUser);
+ enforceCurrentUserIfVisibleBackgroundEnabled();
final int user = UserHandle.getCallingUserId();
final long ident = Binder.clearCallingIdentity();
@@ -1178,7 +1178,7 @@
assertLegit(callingPackage);
assertSingleProjectionType(projectionType);
enforceProjectionTypePermissions(projectionType);
- enforceCurrentUserIfVisibleBackgroundEnabled(mCurrentUser);
+ enforceCurrentUserIfVisibleBackgroundEnabled();
synchronized (mLock) {
if (mProjectionHolders == null) {
@@ -1224,7 +1224,7 @@
assertLegit(callingPackage);
assertSingleProjectionType(projectionType);
enforceProjectionTypePermissions(projectionType);
- enforceCurrentUserIfVisibleBackgroundEnabled(mCurrentUser);
+ enforceCurrentUserIfVisibleBackgroundEnabled();
return releaseProjectionUnchecked(projectionType, callingPackage);
}
@@ -1266,7 +1266,7 @@
return;
}
- enforceCurrentUserIfVisibleBackgroundEnabled(mCurrentUser);
+ enforceCurrentUserIfVisibleBackgroundEnabled();
synchronized (mLock) {
if (mProjectionListeners == null) {
diff --git a/services/core/java/com/android/server/net/watchlist/WatchlistReportDbHelper.java b/services/core/java/com/android/server/net/watchlist/WatchlistReportDbHelper.java
index 7a96195..9937049 100644
--- a/services/core/java/com/android/server/net/watchlist/WatchlistReportDbHelper.java
+++ b/services/core/java/com/android/server/net/watchlist/WatchlistReportDbHelper.java
@@ -21,6 +21,7 @@
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteDatabaseCorruptException;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Environment;
@@ -204,6 +205,11 @@
return false;
}
final String clause = WhiteListReportContract.TIMESTAMP + "< " + untilTimestamp;
- return db.delete(WhiteListReportContract.TABLE, clause, null) != 0;
+ try {
+ return db.delete(WhiteListReportContract.TABLE, clause, null) != 0;
+ } catch (SQLiteDatabaseCorruptException e) {
+ Slog.e(TAG, "Error deleting records", e);
+ return false;
+ }
}
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 5a6d7a2..93837b3 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -2621,20 +2621,22 @@
* Valid user is the current user or the system or in the same profile group as the current
* user. Visible background users are not valid calling users.
*/
- public static void enforceCurrentUserIfVisibleBackgroundEnabled(@UserIdInt int currentUserId) {
+ public static void enforceCurrentUserIfVisibleBackgroundEnabled() {
if (!UserManager.isVisibleBackgroundUsersEnabled()) {
return;
}
final int callingUserId = UserHandle.getCallingUserId();
- if (DBG) {
- Slog.d(LOG_TAG, "enforceValidCallingUser: callingUserId=" + callingUserId
- + " isSystemUser=" + (callingUserId == USER_SYSTEM)
- + " currentUserId=" + currentUserId
- + " callingPid=" + Binder.getCallingPid()
- + " callingUid=" + Binder.getCallingUid());
- }
final long ident = Binder.clearCallingIdentity();
try {
+ final int currentUserId = ActivityManager.getCurrentUser();
+ if (DBG) {
+ Slog.d(LOG_TAG, "enforceCurrentUserIfVisibleBackgroundEnabled:"
+ + " callingUserId=" + callingUserId
+ + " isSystemUser=" + (callingUserId == USER_SYSTEM)
+ + " currentUserId=" + currentUserId
+ + " callingPid=" + Binder.getCallingPid()
+ + " callingUid=" + Binder.getCallingUid());
+ }
if (callingUserId != USER_SYSTEM && callingUserId != currentUserId
&& !UserManagerService.getInstance()
.isSameProfileGroup(callingUserId, currentUserId)) {
diff --git a/services/core/java/com/android/server/power/stats/BatteryHistoryDirectory.java b/services/core/java/com/android/server/power/stats/BatteryHistoryDirectory.java
index adf308a..29cc9ea 100644
--- a/services/core/java/com/android/server/power/stats/BatteryHistoryDirectory.java
+++ b/services/core/java/com/android/server/power/stats/BatteryHistoryDirectory.java
@@ -143,6 +143,7 @@
/**
* Returns the maximum storage size allocated to battery history.
*/
+ @Override
public int getMaxHistorySize() {
return mMaxHistorySize;
}
diff --git a/services/core/java/com/android/server/power/stats/processor/AggregatedPowerStats.java b/services/core/java/com/android/server/power/stats/processor/AggregatedPowerStats.java
index 53894a1..f2bbdfc 100644
--- a/services/core/java/com/android/server/power/stats/processor/AggregatedPowerStats.java
+++ b/services/core/java/com/android/server/power/stats/processor/AggregatedPowerStats.java
@@ -120,16 +120,18 @@
* {@link com.android.internal.os.MonotonicClock}
* @param currentTime current time in milliseconds, see {@link System#currentTimeMillis()}
*/
- void addClockUpdate(long monotonicTime, @CurrentTimeMillisLong long currentTime) {
+ boolean addClockUpdate(long monotonicTime, @CurrentTimeMillisLong long currentTime) {
ClockUpdate clockUpdate = new ClockUpdate();
clockUpdate.monotonicTime = monotonicTime;
clockUpdate.currentTime = currentTime;
if (mClockUpdates.size() < MAX_CLOCK_UPDATES) {
mClockUpdates.add(clockUpdate);
+ return true;
} else {
Slog.i(TAG, "Too many clock updates. Replacing the previous update with "
+ DateFormat.format("yyyy-MM-dd-HH-mm-ss", currentTime));
mClockUpdates.set(mClockUpdates.size() - 1, clockUpdate);
+ return false;
}
}
diff --git a/services/core/java/com/android/server/power/stats/processor/PowerStatsAggregator.java b/services/core/java/com/android/server/power/stats/processor/PowerStatsAggregator.java
index 8461a54..b9862aa 100644
--- a/services/core/java/com/android/server/power/stats/processor/PowerStatsAggregator.java
+++ b/services/core/java/com/android/server/power/stats/processor/PowerStatsAggregator.java
@@ -98,14 +98,18 @@
if (!startedSession) {
mStats.start(item.time);
- mStats.addClockUpdate(item.time, item.currentTime);
+ if (!mStats.addClockUpdate(item.time, item.currentTime)) {
+ break;
+ }
if (baseTime == UNINITIALIZED) {
baseTime = item.time;
}
startedSession = true;
} else if (item.cmd == BatteryStats.HistoryItem.CMD_CURRENT_TIME
|| item.cmd == BatteryStats.HistoryItem.CMD_RESET) {
- mStats.addClockUpdate(item.time, item.currentTime);
+ if (!mStats.addClockUpdate(item.time, item.currentTime)) {
+ break;
+ }
}
lastTime = item.time;
@@ -164,7 +168,9 @@
consumer.accept(mStats);
}
mStats.reset();
- mStats.addClockUpdate(item.time, item.currentTime);
+ if (!mStats.addClockUpdate(item.time, item.currentTime)) {
+ break;
+ }
baseTime = lastTime = item.time;
}
mStats.addPowerStats(item.powerStats, item.time);
diff --git a/services/core/java/com/android/server/storage/WatchedVolumeInfo.java b/services/core/java/com/android/server/storage/WatchedVolumeInfo.java
index 94e52cd..d4b20fb 100644
--- a/services/core/java/com/android/server/storage/WatchedVolumeInfo.java
+++ b/services/core/java/com/android/server/storage/WatchedVolumeInfo.java
@@ -68,6 +68,10 @@
return ImmutableVolumeInfo.fromVolumeInfo(mVolumeInfo);
}
+ public ImmutableVolumeInfo getClonedImmutableVolumeInfo() {
+ return ImmutableVolumeInfo.fromVolumeInfo(mVolumeInfo.clone());
+ }
+
public StorageVolume buildStorageVolume(Context context, int userId, boolean reportUnmounted) {
return mVolumeInfo.buildStorageVolume(context, userId, reportUnmounted);
}
diff --git a/services/core/java/com/android/server/vibrator/VendorVibrationSession.java b/services/core/java/com/android/server/vibrator/VendorVibrationSession.java
index bda3d44..621a128 100644
--- a/services/core/java/com/android/server/vibrator/VendorVibrationSession.java
+++ b/services/core/java/com/android/server/vibrator/VendorVibrationSession.java
@@ -51,6 +51,7 @@
final class VendorVibrationSession extends IVibrationSession.Stub
implements VibrationSession, CancellationSignal.OnCancelListener, IBinder.DeathRecipient {
private static final String TAG = "VendorVibrationSession";
+ private static final boolean DEBUG = false;
/** Calls into VibratorManager functionality needed for playing an {@link ExternalVibration}. */
interface VibratorManagerHooks {
@@ -73,8 +74,8 @@
private final ICancellationSignal mCancellationSignal = CancellationSignal.createTransport();
private final int[] mVibratorIds;
private final long mCreateUptime;
- private final long mCreateTime; // for debugging
- private final IVibrationSessionCallback mCallback;
+ private final long mCreateTime;
+ private final VendorCallbackWrapper mCallback;
private final CallerInfo mCallerInfo;
private final VibratorManagerHooks mManagerHooks;
private final DeviceAdapter mDeviceAdapter;
@@ -88,11 +89,11 @@
@GuardedBy("mLock")
private boolean mEndedByVendor;
@GuardedBy("mLock")
- private long mStartTime; // for debugging
+ private long mStartTime;
@GuardedBy("mLock")
private long mEndUptime;
@GuardedBy("mLock")
- private long mEndTime; // for debugging
+ private long mEndTime;
@GuardedBy("mLock")
private VibrationStepConductor mConductor;
@@ -103,7 +104,7 @@
mCreateTime = System.currentTimeMillis();
mVibratorIds = deviceAdapter.getAvailableVibratorIds();
mHandler = handler;
- mCallback = callback;
+ mCallback = new VendorCallbackWrapper(callback, handler);
mCallerInfo = callerInfo;
mManagerHooks = managerHooks;
mDeviceAdapter = deviceAdapter;
@@ -119,7 +120,9 @@
@Override
public void finishSession() {
- Slog.d(TAG, "Session finish requested, ending vibration session...");
+ if (DEBUG) {
+ Slog.d(TAG, "Session finish requested, ending vibration session...");
+ }
// Do not abort session in HAL, wait for ongoing vibration requests to complete.
// This might take a while to end the session, but it can be aborted by cancelSession.
requestEndSession(Status.FINISHED, /* shouldAbort= */ false, /* isVendorRequest= */ true);
@@ -127,7 +130,9 @@
@Override
public void cancelSession() {
- Slog.d(TAG, "Session cancel requested, aborting vibration session...");
+ if (DEBUG) {
+ Slog.d(TAG, "Session cancel requested, aborting vibration session...");
+ }
// Always abort session in HAL while cancelling it.
// This might be triggered after finishSession was already called.
requestEndSession(Status.CANCELLED_BY_USER, /* shouldAbort= */ true,
@@ -156,7 +161,7 @@
@Override
public IBinder getCallerToken() {
- return mCallback.asBinder();
+ return mCallback.getBinderToken();
}
@Override
@@ -176,36 +181,30 @@
@Override
public void onCancel() {
- Slog.d(TAG, "Session cancellation signal received, aborting vibration session...");
+ if (DEBUG) {
+ Slog.d(TAG, "Session cancellation signal received, aborting vibration session...");
+ }
requestEndSession(Status.CANCELLED_BY_USER, /* shouldAbort= */ true,
/* isVendorRequest= */ true);
}
@Override
public void binderDied() {
- Slog.d(TAG, "Session binder died, aborting vibration session...");
+ if (DEBUG) {
+ Slog.d(TAG, "Session binder died, aborting vibration session...");
+ }
requestEndSession(Status.CANCELLED_BINDER_DIED, /* shouldAbort= */ true,
/* isVendorRequest= */ false);
}
@Override
public boolean linkToDeath() {
- try {
- mCallback.asBinder().linkToDeath(this, 0);
- } catch (RemoteException e) {
- Slog.e(TAG, "Error linking session to token death", e);
- return false;
- }
- return true;
+ return mCallback.linkToDeath(this);
}
@Override
public void unlinkToDeath() {
- try {
- mCallback.asBinder().unlinkToDeath(this, 0);
- } catch (NoSuchElementException e) {
- Slog.wtf(TAG, "Failed to unlink session to token death", e);
- }
+ mCallback.unlinkToDeath(this);
}
@Override
@@ -219,26 +218,37 @@
@Override
public void notifyVibratorCallback(int vibratorId, long vibrationId, long stepId) {
- Slog.d(TAG, "Vibration callback received for vibration " + vibrationId + " step " + stepId
- + " on vibrator " + vibratorId + ", ignoring...");
+ if (DEBUG) {
+ Slog.d(TAG, "Vibration callback received for vibration " + vibrationId
+ + " step " + stepId + " on vibrator " + vibratorId + ", ignoring...");
+ }
}
@Override
public void notifySyncedVibratorsCallback(long vibrationId) {
- Slog.d(TAG, "Synced vibration callback received for vibration " + vibrationId
- + ", ignoring...");
+ if (DEBUG) {
+ Slog.d(TAG, "Synced vibration callback received for vibration " + vibrationId
+ + ", ignoring...");
+ }
}
@Override
public void notifySessionCallback() {
- Slog.d(TAG, "Session callback received, ending vibration session...");
+ if (DEBUG) {
+ Slog.d(TAG, "Session callback received, ending vibration session...");
+ }
synchronized (mLock) {
// If end was not requested then the HAL has cancelled the session.
- maybeSetEndRequestLocked(Status.CANCELLED_BY_UNKNOWN_REASON,
+ notifyEndRequestLocked(Status.CANCELLED_BY_UNKNOWN_REASON,
/* isVendorRequest= */ false);
maybeSetStatusToRequestedLocked();
clearVibrationConductor();
- mHandler.post(() -> mManagerHooks.onSessionReleased(mSessionId));
+ final Status endStatus = mStatus;
+ mHandler.post(() -> {
+ mManagerHooks.onSessionReleased(mSessionId);
+ // Only trigger client callback after session is released in the manager.
+ mCallback.notifyFinished(endStatus);
+ });
}
}
@@ -271,7 +281,7 @@
public boolean isEnded() {
synchronized (mLock) {
- return mStatus != Status.RUNNING;
+ return mEndTime > 0;
}
}
@@ -297,19 +307,17 @@
// Session already ended, skip start callbacks.
isAlreadyEnded = true;
} else {
+ if (DEBUG) {
+ Slog.d(TAG, "Session started at the HAL");
+ }
mStartTime = System.currentTimeMillis();
- // Run client callback in separate thread.
- mHandler.post(() -> {
- try {
- mCallback.onStarted(this);
- } catch (RemoteException e) {
- Slog.e(TAG, "Error notifying vendor session started", e);
- }
- });
+ mCallback.notifyStarted(this);
}
}
if (isAlreadyEnded) {
- Slog.d(TAG, "Session already ended after starting the HAL, aborting...");
+ if (DEBUG) {
+ Slog.d(TAG, "Session already ended after starting the HAL, aborting...");
+ }
mHandler.post(() -> mManagerHooks.endSession(mSessionId, /* shouldAbort= */ true));
}
}
@@ -337,8 +345,10 @@
public boolean maybeSetVibrationConductor(VibrationStepConductor conductor) {
synchronized (mLock) {
if (mConductor != null) {
- Slog.d(TAG, "Session still dispatching previous vibration, new vibration "
- + conductor.getVibration().id + " ignored");
+ if (DEBUG) {
+ Slog.d(TAG, "Session still dispatching previous vibration, new vibration "
+ + conductor.getVibration().id + " ignored");
+ }
return false;
}
mConductor = conductor;
@@ -347,53 +357,45 @@
}
private void requestEndSession(Status status, boolean shouldAbort, boolean isVendorRequest) {
- Slog.d(TAG, "Session end request received with status " + status);
- boolean shouldTriggerSessionHook = false;
+ if (DEBUG) {
+ Slog.d(TAG, "Session end request received with status " + status);
+ }
synchronized (mLock) {
- maybeSetEndRequestLocked(status, isVendorRequest);
+ notifyEndRequestLocked(status, isVendorRequest);
if (!isEnded() && isStarted()) {
// Trigger session hook even if it was already triggered, in case a second request
// is aborting the ongoing/ending session. This might cause it to end right away.
// Wait for HAL callback before setting the end status.
- shouldTriggerSessionHook = true;
+ if (DEBUG) {
+ Slog.d(TAG, "Requesting HAL session end with abort=" + shouldAbort);
+ }
+ mHandler.post(() -> mManagerHooks.endSession(mSessionId, shouldAbort));
} else {
- // Session not active in the HAL, set end status right away.
+ // Session not active in the HAL, try to set end status right away.
maybeSetStatusToRequestedLocked();
+ // Use status used to end this session, which might be different from requested.
+ mCallback.notifyFinished(mStatus);
}
}
- if (shouldTriggerSessionHook) {
- Slog.d(TAG, "Requesting HAL session end with abort=" + shouldAbort);
- mHandler.post(() -> mManagerHooks.endSession(mSessionId, shouldAbort));
- }
}
@GuardedBy("mLock")
- private void maybeSetEndRequestLocked(Status status, boolean isVendorRequest) {
+ private void notifyEndRequestLocked(Status status, boolean isVendorRequest) {
if (mEndStatusRequest != null) {
- // End already requested, keep first requested status and time.
+ // End already requested, keep first requested status.
return;
}
- Slog.d(TAG, "Session end request accepted for status " + status);
+ if (DEBUG) {
+ Slog.d(TAG, "Session end request accepted for status " + status);
+ }
mEndStatusRequest = status;
mEndedByVendor = isVendorRequest;
- mEndTime = System.currentTimeMillis();
- mEndUptime = SystemClock.uptimeMillis();
+ mCallback.notifyFinishing();
if (mConductor != null) {
// Vibration is being dispatched when session end was requested, cancel it.
mConductor.notifyCancelled(new Vibration.EndInfo(status),
/* immediate= */ status != Status.FINISHED);
}
- if (isStarted()) {
- // Only trigger "finishing" callback if session started.
- // Run client callback in separate thread.
- mHandler.post(() -> {
- try {
- mCallback.onFinishing();
- } catch (RemoteException e) {
- Slog.e(TAG, "Error notifying vendor session is finishing", e);
- }
- });
- }
}
@GuardedBy("mLock")
@@ -406,40 +408,123 @@
// No end status was requested, nothing to set.
return;
}
- Slog.d(TAG, "Session end request applied for status " + mEndStatusRequest);
+ if (DEBUG) {
+ Slog.d(TAG, "Session end request applied for status " + mEndStatusRequest);
+ }
mStatus = mEndStatusRequest;
- // Run client callback in separate thread.
- final Status endStatus = mStatus;
- mHandler.post(() -> {
- try {
- mCallback.onFinished(toSessionStatus(endStatus));
- } catch (RemoteException e) {
- Slog.e(TAG, "Error notifying vendor session finished", e);
- }
- });
+ mEndTime = System.currentTimeMillis();
+ mEndUptime = SystemClock.uptimeMillis();
}
- @android.os.vibrator.VendorVibrationSession.Status
- private static int toSessionStatus(Status status) {
- // Exhaustive switch to cover all possible internal status.
- return switch (status) {
- case FINISHED
- -> android.os.vibrator.VendorVibrationSession.STATUS_SUCCESS;
- case IGNORED_UNSUPPORTED
- -> STATUS_UNSUPPORTED;
- case CANCELLED_BINDER_DIED, CANCELLED_BY_APP_OPS, CANCELLED_BY_USER,
- CANCELLED_SUPERSEDED, CANCELLED_BY_FOREGROUND_USER, CANCELLED_BY_SCREEN_OFF,
- CANCELLED_BY_SETTINGS_UPDATE, CANCELLED_BY_UNKNOWN_REASON
- -> android.os.vibrator.VendorVibrationSession.STATUS_CANCELED;
- case IGNORED_APP_OPS, IGNORED_BACKGROUND, IGNORED_FOR_EXTERNAL, IGNORED_FOR_ONGOING,
- IGNORED_FOR_POWER, IGNORED_FOR_SETTINGS, IGNORED_FOR_HIGHER_IMPORTANCE,
- IGNORED_FOR_RINGER_MODE, IGNORED_FROM_VIRTUAL_DEVICE, IGNORED_SUPERSEDED,
- IGNORED_MISSING_PERMISSION, IGNORED_ON_WIRELESS_CHARGER
- -> android.os.vibrator.VendorVibrationSession.STATUS_IGNORED;
- case UNKNOWN, IGNORED_ERROR_APP_OPS, IGNORED_ERROR_CANCELLING, IGNORED_ERROR_SCHEDULING,
- IGNORED_ERROR_TOKEN, FORWARDED_TO_INPUT_DEVICES, FINISHED_UNEXPECTED, RUNNING
- -> android.os.vibrator.VendorVibrationSession.STATUS_UNKNOWN_ERROR;
- };
+ /**
+ * Wrapper class to handle client callbacks asynchronously.
+ *
+ * <p>This class is also responsible for link/unlink to the client process binder death, and for
+ * making sure the callbacks are only triggered once. The conversion between session status and
+ * the API status code is also defined here.
+ */
+ private static final class VendorCallbackWrapper {
+ private final IVibrationSessionCallback mCallback;
+ private final Handler mHandler;
+
+ private boolean mIsStarted;
+ private boolean mIsFinishing;
+ private boolean mIsFinished;
+
+ VendorCallbackWrapper(@NonNull IVibrationSessionCallback callback,
+ @NonNull Handler handler) {
+ mCallback = callback;
+ mHandler = handler;
+ }
+
+ synchronized IBinder getBinderToken() {
+ return mCallback.asBinder();
+ }
+
+ synchronized boolean linkToDeath(DeathRecipient recipient) {
+ try {
+ mCallback.asBinder().linkToDeath(recipient, 0);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Error linking session to token death", e);
+ return false;
+ }
+ return true;
+ }
+
+ synchronized void unlinkToDeath(DeathRecipient recipient) {
+ try {
+ mCallback.asBinder().unlinkToDeath(recipient, 0);
+ } catch (NoSuchElementException e) {
+ Slog.wtf(TAG, "Failed to unlink session to token death", e);
+ }
+ }
+
+ synchronized void notifyStarted(IVibrationSession session) {
+ if (mIsStarted) {
+ return;
+ }
+ mIsStarted = true;
+ mHandler.post(() -> {
+ try {
+ mCallback.onStarted(session);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Error notifying vendor session started", e);
+ }
+ });
+ }
+
+ synchronized void notifyFinishing() {
+ if (!mIsStarted || mIsFinishing || mIsFinished) {
+ // Ignore if never started or if already finishing or finished.
+ return;
+ }
+ mIsFinishing = true;
+ mHandler.post(() -> {
+ try {
+ mCallback.onFinishing();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Error notifying vendor session is finishing", e);
+ }
+ });
+ }
+
+ synchronized void notifyFinished(Status status) {
+ if (mIsFinished) {
+ return;
+ }
+ mIsFinished = true;
+ mHandler.post(() -> {
+ try {
+ mCallback.onFinished(toSessionStatus(status));
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Error notifying vendor session finished", e);
+ }
+ });
+ }
+
+ @android.os.vibrator.VendorVibrationSession.Status
+ private static int toSessionStatus(Status status) {
+ // Exhaustive switch to cover all possible internal status.
+ return switch (status) {
+ case FINISHED
+ -> android.os.vibrator.VendorVibrationSession.STATUS_SUCCESS;
+ case IGNORED_UNSUPPORTED
+ -> STATUS_UNSUPPORTED;
+ case CANCELLED_BINDER_DIED, CANCELLED_BY_APP_OPS, CANCELLED_BY_USER,
+ CANCELLED_SUPERSEDED, CANCELLED_BY_FOREGROUND_USER, CANCELLED_BY_SCREEN_OFF,
+ CANCELLED_BY_SETTINGS_UPDATE, CANCELLED_BY_UNKNOWN_REASON
+ -> android.os.vibrator.VendorVibrationSession.STATUS_CANCELED;
+ case IGNORED_APP_OPS, IGNORED_BACKGROUND, IGNORED_FOR_EXTERNAL, IGNORED_FOR_ONGOING,
+ IGNORED_FOR_POWER, IGNORED_FOR_SETTINGS, IGNORED_FOR_HIGHER_IMPORTANCE,
+ IGNORED_FOR_RINGER_MODE, IGNORED_FROM_VIRTUAL_DEVICE, IGNORED_SUPERSEDED,
+ IGNORED_MISSING_PERMISSION, IGNORED_ON_WIRELESS_CHARGER
+ -> android.os.vibrator.VendorVibrationSession.STATUS_IGNORED;
+ case UNKNOWN, IGNORED_ERROR_APP_OPS, IGNORED_ERROR_CANCELLING,
+ IGNORED_ERROR_SCHEDULING, IGNORED_ERROR_TOKEN, FORWARDED_TO_INPUT_DEVICES,
+ FINISHED_UNEXPECTED, RUNNING
+ -> android.os.vibrator.VendorVibrationSession.STATUS_UNKNOWN_ERROR;
+ };
+ }
}
/**
@@ -499,7 +584,7 @@
@Override
public void logMetrics(VibratorFrameworkStatsLogger statsLogger) {
if (mStartTime > 0) {
- // Only log sessions that have started.
+ // Only log sessions that have started in the HAL.
statsLogger.logVibrationVendorSessionStarted(mCallerInfo.uid);
statsLogger.logVibrationVendorSessionVibrations(mCallerInfo.uid,
mVibrations.size());
diff --git a/services/core/java/com/android/server/wm/DesktopModeHelper.java b/services/core/java/com/android/server/wm/DesktopModeHelper.java
index c2255d8..dc42b32 100644
--- a/services/core/java/com/android/server/wm/DesktopModeHelper.java
+++ b/services/core/java/com/android/server/wm/DesktopModeHelper.java
@@ -79,7 +79,7 @@
}
@VisibleForTesting
- static boolean isDeviceEligibleForDesktopMode(@NonNull Context context) {
+ public static boolean isDeviceEligibleForDesktopMode(@NonNull Context context) {
if (!shouldEnforceDeviceRestrictions()) {
return true;
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index e190a04..50f12c3 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -6938,6 +6938,8 @@
/** The actual requested visible inset types for this display */
private @InsetsType int mRequestedVisibleTypes = WindowInsets.Type.defaultVisible();
+ private @InsetsType int mAnimatingTypes = 0;
+
/** The component name of the top focused window on this display */
private ComponentName mTopFocusedComponentName = null;
@@ -7075,6 +7077,18 @@
}
return 0;
}
+
+ @Override
+ public @InsetsType int getAnimatingTypes() {
+ return mAnimatingTypes;
+ }
+
+ @Override
+ public void setAnimatingTypes(@InsetsType int animatingTypes) {
+ if (mAnimatingTypes != animatingTypes) {
+ mAnimatingTypes = animatingTypes;
+ }
+ }
}
MagnificationSpec getMagnificationSpec() {
diff --git a/services/core/java/com/android/server/wm/InsetsControlTarget.java b/services/core/java/com/android/server/wm/InsetsControlTarget.java
index cee4967..6462a37 100644
--- a/services/core/java/com/android/server/wm/InsetsControlTarget.java
+++ b/services/core/java/com/android/server/wm/InsetsControlTarget.java
@@ -97,6 +97,20 @@
@NonNull ImeTracker.Token statsToken) {
}
+ /**
+ * @return {@link WindowInsets.Type.InsetsType}s which are currently animating (showing or
+ * hiding).
+ */
+ default @InsetsType int getAnimatingTypes() {
+ return 0;
+ }
+
+ /**
+ * @param animatingTypes the {@link InsetsType}s, that are currently animating
+ */
+ default void setAnimatingTypes(@InsetsType int animatingTypes) {
+ }
+
/** Returns {@code target.getWindow()}, or null if {@code target} is {@code null}. */
static WindowState asWindowOrNull(InsetsControlTarget target) {
return target != null ? target.getWindow() : null;
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index 009d482..2872214 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -790,8 +790,6 @@
private final Handler mHandler;
private final String mName;
- private boolean mInsetsAnimationRunning;
-
Host(Handler handler, String name) {
mHandler = handler;
mName = name;
@@ -901,10 +899,5 @@
public IBinder getWindowToken() {
return null;
}
-
- @Override
- public void notifyAnimationRunningStateChanged(boolean running) {
- mInsetsAnimationRunning = running;
- }
}
}
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 8d198b2..3ed16db 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -737,6 +737,17 @@
}
}
+ @Override
+ public void updateAnimatingTypes(IWindow window, @InsetsType int animatingTypes) {
+ synchronized (mService.mGlobalLock) {
+ final WindowState win = mService.windowForClientLocked(this, window,
+ false /* throwOnError */);
+ if (win != null) {
+ win.setAnimatingTypes(animatingTypes);
+ }
+ }
+ }
+
void onWindowAdded(WindowState w) {
if (mPackageName == null) {
mPackageName = mProcess.mInfo.packageName;
@@ -1015,15 +1026,4 @@
}
}
}
-
- @Override
- public void notifyInsetsAnimationRunningStateChanged(IWindow window, boolean running) {
- synchronized (mService.mGlobalLock) {
- final WindowState win = mService.windowForClientLocked(this, window,
- false /* throwOnError */);
- if (win != null) {
- win.notifyInsetsAnimationRunningStateChanged(running);
- }
- }
- }
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 2e699ca..28f2825 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -4773,6 +4773,26 @@
}
}
+ @EnforcePermission(android.Manifest.permission.MANAGE_APP_TOKENS)
+ @Override
+ public void updateDisplayWindowAnimatingTypes(int displayId, @InsetsType int animatingTypes) {
+ updateDisplayWindowAnimatingTypes_enforcePermission();
+ if (android.view.inputmethod.Flags.reportAnimatingInsetsTypes()) {
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ final DisplayContent dc = mRoot.getDisplayContent(displayId);
+ if (dc == null || dc.mRemoteInsetsControlTarget == null) {
+ return;
+ }
+ dc.mRemoteInsetsControlTarget.setAnimatingTypes(animatingTypes);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+ }
+
@Override
public int watchRotation(IRotationWatcher watcher, int displayId) {
final DisplayContent displayContent;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index ce87ca5..3b7d312 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -736,6 +736,8 @@
private @InsetsType int mRequestedVisibleTypes = WindowInsets.Type.defaultVisible();
+ private @InsetsType int mAnimatingTypes = 0;
+
/**
* Freeze the insets state in some cases that not necessarily keeps up-to-date to the client.
* (e.g app exiting transition)
@@ -842,6 +844,27 @@
mRequestedVisibleTypes & ~mask | requestedVisibleTypes & mask);
}
+ @Override
+ public @InsetsType int getAnimatingTypes() {
+ return mAnimatingTypes;
+ }
+
+ @Override
+ public void setAnimatingTypes(@InsetsType int animatingTypes) {
+ if (mAnimatingTypes != animatingTypes) {
+ if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) {
+ Trace.instant(TRACE_TAG_WINDOW_MANAGER,
+ TextUtils.formatSimple("%s: setAnimatingTypes(%s)",
+ getName(),
+ animatingTypes));
+ }
+ mInsetsAnimationRunning = animatingTypes != 0;
+ mWmService.scheduleAnimationLocked();
+
+ mAnimatingTypes = animatingTypes;
+ }
+ }
+
/**
* Set a freeze state for the window to ignore dispatching its insets state to the client.
*
@@ -6078,17 +6101,6 @@
mWmService.scheduleAnimationLocked();
}
- void notifyInsetsAnimationRunningStateChanged(boolean running) {
- if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) {
- Trace.instant(TRACE_TAG_WINDOW_MANAGER,
- TextUtils.formatSimple("%s: notifyInsetsAnimationRunningStateChanged(%s)",
- getName(),
- Boolean.toString(running)));
- }
- mInsetsAnimationRunning = running;
- mWmService.scheduleAnimationLocked();
- }
-
boolean isInsetsAnimationRunning() {
return mInsetsAnimationRunning;
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index e158310..860b6fb 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1814,7 +1814,7 @@
t.traceEnd();
}
- if (!isWatch && !isTv && !isAutomotive
+ if (!isWatch && !isTv && !isAutomotive && !isDesktop
&& android.security.Flags.aapmApi()) {
t.traceBegin("StartAdvancedProtectionService");
mSystemServiceManager.startService(AdvancedProtectionService.Lifecycle.class);
diff --git a/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java b/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java
index bada337..6b8ef88 100644
--- a/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java
@@ -64,7 +64,6 @@
import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
import android.content.pm.ServiceInfo;
-import android.content.res.Resources;
import android.graphics.Color;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManager.DisplayListener;
@@ -95,6 +94,7 @@
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.LocalServices;
+import com.android.server.wm.DesktopModeHelper;
import com.android.server.wm.WindowManagerInternal;
import org.hamcrest.CoreMatchers;
@@ -155,8 +155,6 @@
private IPackageManager mIpm = AppGlobals.getPackageManager();
- private Resources mResources = sContext.getResources();
-
@Mock
private DisplayManager mDisplayManager;
@@ -178,6 +176,7 @@
.spyStatic(WallpaperUtils.class)
.spyStatic(LocalServices.class)
.spyStatic(WallpaperManager.class)
+ .spyStatic(DesktopModeHelper.class)
.startMocking();
sWindowManagerInternal = mock(WindowManagerInternal.class);
@@ -246,6 +245,8 @@
int userId = (invocation.getArgument(0));
return getWallpaperTestDir(userId);
}).when(() -> WallpaperUtils.getWallpaperDir(anyInt()));
+ ExtendedMockito.doAnswer(invocation -> true).when(
+ () -> DesktopModeHelper.isDeviceEligibleForDesktopMode(any()));
sContext.addMockSystemService(DisplayManager.class, mDisplayManager);
@@ -257,10 +258,6 @@
doReturn(displays).when(mDisplayManager).getDisplays();
spyOn(mIpm);
- spyOn(mResources);
- doReturn(true).when(mResources).getBoolean(eq(R.bool.config_isDesktopModeSupported));
- doReturn(true).when(mResources).getBoolean(
- eq(R.bool.config_canInternalDisplayHostDesktops));
mService = new TestWallpaperManagerService(sContext);
spyOn(mService);
mService.systemReady();
diff --git a/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java
index 45436e4..d3f3269 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java
@@ -33,6 +33,7 @@
import android.platform.test.annotations.Presubmit;
import android.view.Display.Mode;
import android.view.Surface;
+import android.view.WindowInsets;
import android.view.WindowManager.LayoutParams;
import androidx.test.filters.SmallTest;
@@ -283,7 +284,7 @@
assertEquals(0, mPolicy.getPreferredMinRefreshRate(overrideWindow), FLOAT_TOLERANCE);
assertEquals(0, mPolicy.getPreferredMaxRefreshRate(overrideWindow), FLOAT_TOLERANCE);
- overrideWindow.notifyInsetsAnimationRunningStateChanged(true);
+ overrideWindow.setAnimatingTypes(WindowInsets.Type.statusBars());
assertEquals(LOW_MODE_ID, mPolicy.getPreferredModeId(overrideWindow));
assertTrue(mPolicy.updateFrameRateVote(overrideWindow));
assertEquals(FRAME_RATE_VOTE_NONE, overrideWindow.mFrameRateVote);
@@ -303,7 +304,7 @@
assertEquals(0, mPolicy.getPreferredMinRefreshRate(overrideWindow), FLOAT_TOLERANCE);
assertEquals(0, mPolicy.getPreferredMaxRefreshRate(overrideWindow), FLOAT_TOLERANCE);
- overrideWindow.notifyInsetsAnimationRunningStateChanged(true);
+ overrideWindow.setAnimatingTypes(WindowInsets.Type.statusBars());
assertEquals(0, mPolicy.getPreferredModeId(overrideWindow));
assertTrue(mPolicy.updateFrameRateVote(overrideWindow));
assertEquals(FRAME_RATE_VOTE_NONE, overrideWindow.mFrameRateVote);
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 6e0304b..fbba999 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -10579,9 +10579,19 @@
public boolean hasCarrierPrivileges(int subId) {
try {
ITelephony telephony = getITelephony();
- if (telephony != null) {
- return telephony.getCarrierPrivilegeStatus(subId)
- == CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
+ if (telephony == null) {
+ Rlog.e(TAG, "hasCarrierPrivileges: no Telephony service");
+ return false;
+ }
+ int status = telephony.getCarrierPrivilegeStatus(subId);
+ switch (status) {
+ case CARRIER_PRIVILEGE_STATUS_HAS_ACCESS:
+ return true;
+ case CARRIER_PRIVILEGE_STATUS_NO_ACCESS:
+ return false;
+ default:
+ Rlog.e(TAG, "hasCarrierPrivileges: " + status);
+ return false;
}
} catch (RemoteException ex) {
Rlog.e(TAG, "hasCarrierPrivileges RemoteException", ex);