Merge "Reland "Conform to 1D VelocityTracker" (--try 2)"
diff --git a/core/java/android/app/ActivityTransitionState.java b/core/java/android/app/ActivityTransitionState.java
index 877e7d3..6f4bb45 100644
--- a/core/java/android/app/ActivityTransitionState.java
+++ b/core/java/android/app/ActivityTransitionState.java
@@ -145,7 +145,10 @@
* that it is preserved through activty destroy and restore.
*/
private ArrayList<String> getPendingExitNames() {
- if (mPendingExitNames == null && mEnterTransitionCoordinator != null) {
+ if (mPendingExitNames == null
+ && mEnterTransitionCoordinator != null
+ && !mEnterTransitionCoordinator.isReturning()
+ ) {
mPendingExitNames = mEnterTransitionCoordinator.getPendingExitSharedElementNames();
}
return mPendingExitNames;
@@ -202,6 +205,7 @@
restoreExitedViews();
activity.getWindow().getDecorView().setVisibility(View.VISIBLE);
}
+ getPendingExitNames(); // Set mPendingExitNames before resetting mEnterTransitionCoordinator
mEnterTransitionCoordinator = new EnterTransitionCoordinator(activity,
resultReceiver, sharedElementNames, mEnterActivityOptions.isReturning(),
mEnterActivityOptions.isCrossTask());
@@ -250,6 +254,7 @@
public void onStop(Activity activity) {
restoreExitedViews();
if (mEnterTransitionCoordinator != null) {
+ getPendingExitNames(); // Set mPendingExitNames before clearing
mEnterTransitionCoordinator.stop();
mEnterTransitionCoordinator = null;
}
@@ -275,6 +280,7 @@
restoreReenteringViews();
} else if (mEnterTransitionCoordinator.isReturning()) {
mEnterTransitionCoordinator.runAfterTransitionsComplete(() -> {
+ getPendingExitNames(); // Set mPendingExitNames before clearing
mEnterTransitionCoordinator = null;
});
}
@@ -374,6 +380,7 @@
}
public void startExitOutTransition(Activity activity, Bundle options) {
+ getPendingExitNames(); // Set mPendingExitNames before clearing mEnterTransitionCoordinator
mEnterTransitionCoordinator = null;
if (!activity.getWindow().hasFeature(Window.FEATURE_ACTIVITY_TRANSITIONS) ||
mExitTransitionCoordinators == null) {
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 65265da..ab11d6a 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -15423,7 +15423,7 @@
*
* @see #setWifiSsidPolicy(WifiSsidPolicy)
* @throws SecurityException if the caller is not a device owner or a profile owner on
- * an organization-owned managed profile or a system app.
+ * an organization-owned managed profile.
*/
@Nullable
public WifiSsidPolicy getWifiSsidPolicy() {
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
index 18d86d6..1c4898a 100644
--- a/core/java/android/hardware/SystemSensorManager.java
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -882,6 +882,7 @@
}
// Indicate if the discontinuity count changed
+ t.firstEventAfterDiscontinuity = false;
if (t.sensor.getType() == Sensor.TYPE_HEAD_TRACKER) {
final int lastCount = mSensorDiscontinuityCounts.get(handle);
final int curCount = Float.floatToIntBits(values[6]);
diff --git a/core/java/android/service/games/TEST_MAPPING b/core/java/android/service/games/TEST_MAPPING
new file mode 100644
index 0000000..3e551ef
--- /dev/null
+++ b/core/java/android/service/games/TEST_MAPPING
@@ -0,0 +1,16 @@
+{
+ "presubmit": [
+ // TODO(b/245615658): fix flaky CTS test CtsGameServiceTestCases and add it as presubmit
+ {
+ "name": "FrameworksMockingServicesTests",
+ "options": [
+ {
+ "include-filter": "android.service.games"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/core/java/android/service/trust/TrustAgentService.java b/core/java/android/service/trust/TrustAgentService.java
index ad4f9f7..684d566 100644
--- a/core/java/android/service/trust/TrustAgentService.java
+++ b/core/java/android/service/trust/TrustAgentService.java
@@ -141,7 +141,9 @@
*
* Without this flag, the message passed to {@code grantTrust} is only used for debugging
* purposes. With the flag, it may be displayed to the user as the reason why the device is
- * unlocked.
+ * unlocked. If this flag isn't set OR the message is set to null, the device will display
+ * its own default message for trust granted. If the TrustAgent intentionally doesn't want to
+ * show any message, then it can set this flag AND set the message to an empty string.
*/
public static final int FLAG_GRANT_TRUST_DISPLAY_MESSAGE = 1 << 3;
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 586c193..7acf319 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -107,14 +107,6 @@
* and scaling a SurfaceView on screen will not cause rendering artifacts. Such
* artifacts may occur on previous versions of the platform when its window is
* positioned asynchronously.</p>
- *
- * <p class="note"><strong>Note:</strong> Starting in platform version
- * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, SurfaceView will support arbitrary
- * alpha blending. Prior platform versions ignored alpha values on the SurfaceView if they were
- * between 0 and 1. If the SurfaceView is configured with Z-above, then the alpha is applied
- * directly to the Surface. If the SurfaceView is configured with Z-below, then the alpha is
- * applied to the hole punch directly. Note that when using Z-below, overlapping SurfaceViews
- * may not blend properly as a consequence of not applying alpha to the surface content directly.
*/
public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCallback {
private static final String TAG = "SurfaceView";
@@ -154,7 +146,6 @@
Paint mRoundedViewportPaint;
int mSubLayer = APPLICATION_MEDIA_SUBLAYER;
- int mRequestedSubLayer = APPLICATION_MEDIA_SUBLAYER;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
boolean mIsCreating = false;
@@ -186,7 +177,8 @@
@UnsupportedAppUsage
int mRequestedFormat = PixelFormat.RGB_565;
- float mAlpha = 1f;
+ boolean mUseAlpha = false;
+ float mSurfaceAlpha = 1f;
boolean mClipSurfaceToBounds;
int mBackgroundColor = Color.BLACK;
@@ -343,25 +335,58 @@
* @hide
*/
public void setUseAlpha() {
- // TODO(b/241474646): Remove me
- return;
+ if (!mUseAlpha) {
+ mUseAlpha = true;
+ updateSurfaceAlpha();
+ }
}
@Override
public void setAlpha(float alpha) {
+ // Sets the opacity of the view to a value, where 0 means the view is completely transparent
+ // and 1 means the view is completely opaque.
+ //
+ // Note: Alpha value of this view is ignored by default. To enable alpha blending, you need
+ // to call setUseAlpha() as well.
+ // This view doesn't support translucent opacity if the view is located z-below, since the
+ // logic to punch a hole in the view hierarchy cannot handle such case. See also
+ // #clearSurfaceViewPort(Canvas)
if (DEBUG) {
Log.d(TAG, System.identityHashCode(this)
- + " setAlpha: alpha=" + alpha);
+ + " setAlpha: mUseAlpha = " + mUseAlpha + " alpha=" + alpha);
}
super.setAlpha(alpha);
+ updateSurfaceAlpha();
}
- @Override
- protected boolean onSetAlpha(int alpha) {
- if (Math.round(mAlpha * 255) != alpha) {
- updateSurface();
+ private float getFixedAlpha() {
+ // Compute alpha value to be set on the underlying surface.
+ final float alpha = getAlpha();
+ return mUseAlpha && (mSubLayer > 0 || alpha == 0f) ? alpha : 1f;
+ }
+
+ private void updateSurfaceAlpha() {
+ if (!mUseAlpha || !mHaveFrame || mSurfaceControl == null) {
+ return;
}
- return true;
+ final float viewAlpha = getAlpha();
+ if (mSubLayer < 0 && 0f < viewAlpha && viewAlpha < 1f) {
+ Log.w(TAG, System.identityHashCode(this)
+ + " updateSurfaceAlpha:"
+ + " translucent color is not supported for a surface placed z-below.");
+ }
+ final ViewRootImpl viewRoot = getViewRootImpl();
+ if (viewRoot == null) {
+ return;
+ }
+ final float alpha = getFixedAlpha();
+ if (alpha != mSurfaceAlpha) {
+ final Transaction transaction = new Transaction();
+ transaction.setAlpha(mSurfaceControl, alpha);
+ viewRoot.applyTransactionOnDraw(transaction);
+ damageInParent();
+ mSurfaceAlpha = alpha;
+ }
}
private void performDrawFinished() {
@@ -509,15 +534,7 @@
invalidate();
}
- @Override
- public boolean hasOverlappingRendering() {
- // SurfaceViews only alpha composite by modulating the Surface alpha for Z-above, or
- // applying alpha on the hole punch for Z-below - no deferral to a layer is necessary.
- return false;
- }
-
private void clearSurfaceViewPort(Canvas canvas) {
- final float alpha = getAlpha();
if (mCornerRadius > 0f) {
canvas.getClipBounds(mTmpRect);
if (mClipSurfaceToBounds && mClipBounds != null) {
@@ -529,11 +546,10 @@
mTmpRect.right,
mTmpRect.bottom,
mCornerRadius,
- mCornerRadius,
- alpha
+ mCornerRadius
);
} else {
- canvas.punchHole(0f, 0f, getWidth(), getHeight(), 0f, 0f, alpha);
+ canvas.punchHole(0f, 0f, getWidth(), getHeight(), 0f, 0f);
}
}
@@ -636,10 +652,10 @@
} else {
subLayer = APPLICATION_MEDIA_SUBLAYER;
}
- if (mRequestedSubLayer == subLayer) {
+ if (mSubLayer == subLayer) {
return false;
}
- mRequestedSubLayer = subLayer;
+ mSubLayer = subLayer;
if (!allowDynamicChange) {
return false;
@@ -651,8 +667,9 @@
if (viewRoot == null) {
return true;
}
-
- updateSurface();
+ final Transaction transaction = new SurfaceControl.Transaction();
+ updateRelativeZ(transaction);
+ viewRoot.applyTransactionOnDraw(transaction);
invalidate();
return true;
}
@@ -705,7 +722,8 @@
}
private void releaseSurfaces(boolean releaseSurfacePackage) {
- mAlpha = 1f;
+ mSurfaceAlpha = 1f;
+
synchronized (mSurfaceControlLock) {
mSurface.destroy();
if (mBlastBufferQueue != null) {
@@ -752,7 +770,7 @@
}
private boolean performSurfaceTransaction(ViewRootImpl viewRoot, Translator translator,
- boolean creating, boolean sizeChanged, boolean hintChanged, boolean relativeZChanged,
+ boolean creating, boolean sizeChanged, boolean hintChanged,
Transaction surfaceUpdateTransaction) {
boolean realSizeChanged = false;
@@ -782,20 +800,14 @@
surfaceUpdateTransaction.hide(mSurfaceControl);
}
+
+
updateBackgroundVisibility(surfaceUpdateTransaction);
updateBackgroundColor(surfaceUpdateTransaction);
- if (isAboveParent()) {
- float alpha = getAlpha();
+ if (mUseAlpha) {
+ float alpha = getFixedAlpha();
surfaceUpdateTransaction.setAlpha(mSurfaceControl, alpha);
- }
-
- if (relativeZChanged) {
- if (!isAboveParent()) {
- // If we're moving from z-above to z-below, then restore the surface alpha back to 1
- // and let the holepunch drive visibility and blending.
- surfaceUpdateTransaction.setAlpha(mSurfaceControl, 1.f);
- }
- updateRelativeZ(surfaceUpdateTransaction);
+ mSurfaceAlpha = alpha;
}
surfaceUpdateTransaction.setCornerRadius(mSurfaceControl, mCornerRadius);
@@ -861,7 +873,6 @@
} finally {
mSurfaceLock.unlock();
}
-
return realSizeChanged;
}
@@ -895,10 +906,10 @@
int myHeight = mRequestedHeight;
if (myHeight <= 0) myHeight = getHeight();
- final float alpha = getAlpha();
+ final float alpha = getFixedAlpha();
final boolean formatChanged = mFormat != mRequestedFormat;
final boolean visibleChanged = mVisible != mRequestedVisible;
- final boolean alphaChanged = mAlpha != alpha;
+ final boolean alphaChanged = mSurfaceAlpha != alpha;
final boolean creating = (mSurfaceControl == null || formatChanged || visibleChanged)
&& mRequestedVisible;
final boolean sizeChanged = mSurfaceWidth != myWidth || mSurfaceHeight != myHeight;
@@ -910,17 +921,17 @@
|| getHeight() != mScreenRect.height();
final boolean hintChanged = (viewRoot.getBufferTransformHint() != mTransformHint)
&& mRequestedVisible;
- final boolean relativeZChanged = mSubLayer != mRequestedSubLayer;
- if (creating || formatChanged || sizeChanged || visibleChanged
- || alphaChanged || windowVisibleChanged || positionChanged
- || layoutSizeChanged || hintChanged || relativeZChanged) {
+ if (creating || formatChanged || sizeChanged || visibleChanged ||
+ (mUseAlpha && alphaChanged) || windowVisibleChanged ||
+ positionChanged || layoutSizeChanged || hintChanged) {
if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+ "Changes: creating=" + creating
+ " format=" + formatChanged + " size=" + sizeChanged
+ " visible=" + visibleChanged + " alpha=" + alphaChanged
+ " hint=" + hintChanged
+ + " mUseAlpha=" + mUseAlpha
+ " visible=" + visibleChanged
+ " left=" + (mWindowSpaceLeft != mLocation[0])
+ " top=" + (mWindowSpaceTop != mLocation[1]));
@@ -932,10 +943,8 @@
mSurfaceWidth = myWidth;
mSurfaceHeight = myHeight;
mFormat = mRequestedFormat;
- mAlpha = alpha;
mLastWindowVisibility = mWindowVisibility;
mTransformHint = viewRoot.getBufferTransformHint();
- mSubLayer = mRequestedSubLayer;
mScreenRect.left = mWindowSpaceLeft;
mScreenRect.top = mWindowSpaceTop;
@@ -959,7 +968,7 @@
}
final boolean redrawNeeded = sizeChanged || creating || hintChanged
- || (mVisible && !mDrawFinished) || alphaChanged || relativeZChanged;
+ || (mVisible && !mDrawFinished);
boolean shouldSyncBuffer =
redrawNeeded && viewRoot.wasRelayoutRequested() && viewRoot.isInLocalSync();
SyncBufferTransactionCallback syncBufferTransactionCallback = null;
@@ -970,9 +979,8 @@
syncBufferTransactionCallback::onTransactionReady);
}
- final boolean realSizeChanged = performSurfaceTransaction(viewRoot, translator,
- creating, sizeChanged, hintChanged, relativeZChanged,
- surfaceUpdateTransaction);
+ final boolean realSizeChanged = performSurfaceTransaction(viewRoot,
+ translator, creating, sizeChanged, hintChanged, surfaceUpdateTransaction);
try {
SurfaceHolder.Callback[] callbacks = null;
@@ -1614,8 +1622,11 @@
*/
@Override
public void unlockCanvasAndPost(Canvas canvas) {
- mSurface.unlockCanvasAndPost(canvas);
- mSurfaceLock.unlock();
+ try {
+ mSurface.unlockCanvasAndPost(canvas);
+ } finally {
+ mSurfaceLock.unlock();
+ }
}
@Override
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index ffae3df..8fee4db 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -12890,7 +12890,6 @@
if (mViewTranslationCallback != null) {
mViewTranslationCallback.onClearTranslation(this);
}
- clearViewTranslationCallback();
clearViewTranslationResponse();
if (hasTranslationTransientState()) {
setHasTransientState(false);
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index a49caaf..8656af2 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -285,12 +285,18 @@
int TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER = 21;
/**
- * Keyguard is being occluded.
+ * Keyguard is being occluded by non-Dream.
* @hide
*/
int TRANSIT_OLD_KEYGUARD_OCCLUDE = 22;
/**
+ * Keyguard is being occluded by Dream.
+ * @hide
+ */
+ int TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM = 33;
+
+ /**
* Keyguard is being unoccluded.
* @hide
*/
diff --git a/core/java/com/android/internal/os/BatteryStatsHistory.java b/core/java/com/android/internal/os/BatteryStatsHistory.java
index 7001c69..f097bf7 100644
--- a/core/java/com/android/internal/os/BatteryStatsHistory.java
+++ b/core/java/com/android/internal/os/BatteryStatsHistory.java
@@ -16,17 +16,23 @@
package com.android.internal.os;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.BatteryManager;
+import android.os.BatteryStats;
+import android.os.BatteryStats.BitDescription;
import android.os.BatteryStats.HistoryItem;
import android.os.BatteryStats.HistoryStepDetails;
import android.os.BatteryStats.HistoryTag;
import android.os.BatteryStats.MeasuredEnergyDetails;
+import android.os.Build;
import android.os.Parcel;
import android.os.ParcelFormatException;
import android.os.Process;
import android.os.StatFs;
import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.os.Trace;
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.Slog;
@@ -210,6 +216,42 @@
}
/**
+ * A delegate for android.os.Trace to allow testing static calls. Due to
+ * limitations in Android Tracing (b/153319140), the delegate also records
+ * counter values in system properties which allows reading the value at the
+ * start of a tracing session. This overhead is limited to userdebug builds.
+ * On user builds, tracing still occurs but the counter value will be missing
+ * until the first change occurs.
+ */
+ @VisibleForTesting
+ public static class TraceDelegate {
+ // Note: certain tests currently run as platform_app which is not allowed
+ // to set debug system properties. To ensure that system properties are set
+ // only when allowed, we check the current UID.
+ private final boolean mShouldSetProperty =
+ Build.IS_USERDEBUG && (Process.myUid() == Process.SYSTEM_UID);
+
+ /**
+ * Returns true if trace counters should be recorded.
+ */
+ public boolean tracingEnabled() {
+ return Trace.isTagEnabled(Trace.TRACE_TAG_POWER) || mShouldSetProperty;
+ }
+
+ /**
+ * Records the counter value with the given name.
+ */
+ public void traceCounter(@NonNull String name, int value) {
+ Trace.traceCounter(Trace.TRACE_TAG_POWER, name, value);
+ if (mShouldSetProperty) {
+ SystemProperties.set("debug.tracing." + name, Integer.toString(value));
+ }
+ }
+ }
+
+ private TraceDelegate mTracer;
+
+ /**
* Constructor
*
* @param systemDir typically /data/system
@@ -219,19 +261,20 @@
public BatteryStatsHistory(File systemDir, int maxHistoryFiles, int maxHistoryBufferSize,
HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock) {
this(Parcel.obtain(), systemDir, maxHistoryFiles, maxHistoryBufferSize,
- stepDetailsCalculator, clock);
+ stepDetailsCalculator, clock, new TraceDelegate());
initHistoryBuffer();
}
@VisibleForTesting
public BatteryStatsHistory(Parcel historyBuffer, File systemDir,
int maxHistoryFiles, int maxHistoryBufferSize,
- HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock) {
+ HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock, TraceDelegate tracer) {
mHistoryBuffer = historyBuffer;
mSystemDir = systemDir;
mMaxHistoryFiles = maxHistoryFiles;
mMaxHistoryBufferSize = maxHistoryBufferSize;
mStepDetailsCalculator = stepDetailsCalculator;
+ mTracer = tracer;
mClock = clock;
mHistoryDir = new File(systemDir, HISTORY_DIR);
@@ -272,6 +315,7 @@
public BatteryStatsHistory(HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock) {
mStepDetailsCalculator = stepDetailsCalculator;
+ mTracer = new TraceDelegate();
mClock = clock;
mHistoryBuffer = Parcel.obtain();
@@ -287,6 +331,7 @@
private BatteryStatsHistory(Parcel historyBuffer,
HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock) {
mHistoryBuffer = historyBuffer;
+ mTracer = new TraceDelegate();
mClock = clock;
mSystemDir = null;
mHistoryDir = null;
@@ -338,7 +383,7 @@
// Make a copy of battery history to avoid concurrent modification.
Parcel historyBuffer = Parcel.obtain();
historyBuffer.appendFrom(mHistoryBuffer, 0, mHistoryBuffer.dataSize());
- return new BatteryStatsHistory(historyBuffer, mSystemDir, 0, 0, null, null);
+ return new BatteryStatsHistory(historyBuffer, mSystemDir, 0, 0, null, null, mTracer);
}
/**
@@ -1120,6 +1165,30 @@
}
/**
+ * Writes changes to a HistoryItem state bitmap to Atrace.
+ */
+ private void recordTraceCounters(int oldval, int newval, BitDescription[] descriptions) {
+ if (!mTracer.tracingEnabled()) return;
+
+ int diff = oldval ^ newval;
+ if (diff == 0) return;
+
+ for (int i = 0; i < descriptions.length; i++) {
+ BitDescription bd = descriptions[i];
+ if ((diff & bd.mask) == 0) continue;
+
+ int value;
+ if (bd.shift < 0) {
+ value = (newval & bd.mask) != 0 ? 1 : 0;
+ } else {
+ value = (newval & bd.mask) >> bd.shift;
+ }
+
+ mTracer.traceCounter("battery_stats." + bd.name, value);
+ }
+ }
+
+ /**
* Writes the current history item to history.
*/
public void writeHistoryItem(long elapsedRealtimeMs, long uptimeMs) {
@@ -1159,6 +1228,12 @@
+ Integer.toHexString(diffStates2) + " lastDiff2="
+ Integer.toHexString(lastDiffStates2));
}
+
+ recordTraceCounters(mHistoryLastWritten.states,
+ cur.states & mActiveHistoryStates, BatteryStats.HISTORY_STATE_DESCRIPTIONS);
+ recordTraceCounters(mHistoryLastWritten.states2,
+ cur.states2 & mActiveHistoryStates2, BatteryStats.HISTORY_STATE2_DESCRIPTIONS);
+
if (mHistoryBufferLastPos >= 0 && mHistoryLastWritten.cmd == HistoryItem.CMD_UPDATE
&& timeDiffMs < 1000 && (diffStates & lastDiffStates) == 0
&& (diffStates2 & lastDiffStates2) == 0
diff --git a/core/java/com/android/internal/widget/ConversationLayout.java b/core/java/com/android/internal/widget/ConversationLayout.java
index 9f21760..4cf0ba1 100644
--- a/core/java/com/android/internal/widget/ConversationLayout.java
+++ b/core/java/com/android/internal/widget/ConversationLayout.java
@@ -111,6 +111,7 @@
private Icon mLargeIcon;
private View mExpandButtonContainer;
private ViewGroup mExpandButtonAndContentContainer;
+ private ViewGroup mExpandButtonContainerA11yContainer;
private NotificationExpandButton mExpandButton;
private MessagingLinearLayout mImageMessageContainer;
private int mBadgeProtrusion;
@@ -234,6 +235,8 @@
});
mConversationText = findViewById(R.id.conversation_text);
mExpandButtonContainer = findViewById(R.id.expand_button_container);
+ mExpandButtonContainerA11yContainer =
+ findViewById(R.id.expand_button_a11y_container);
mConversationHeader = findViewById(R.id.conversation_header);
mContentContainer = findViewById(R.id.notification_action_list_margin_target);
mExpandButtonAndContentContainer = findViewById(R.id.expand_button_and_content_container);
@@ -1091,7 +1094,7 @@
newContainer = mExpandButtonAndContentContainer;
} else {
buttonGravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
- newContainer = this;
+ newContainer = mExpandButtonContainerA11yContainer;
}
mExpandButton.setExpanded(!mIsCollapsed);
diff --git a/core/res/res/layout/notification_template_material_conversation.xml b/core/res/res/layout/notification_template_material_conversation.xml
index 42fb4a2..ce8a904 100644
--- a/core/res/res/layout/notification_template_material_conversation.xml
+++ b/core/res/res/layout/notification_template_material_conversation.xml
@@ -89,45 +89,62 @@
<include layout="@layout/notification_material_action_list" />
</com.android.internal.widget.RemeasuringLinearLayout>
- <!--This is dynamically placed between here and at the end of the layout. It starts here since
- only FrameLayout layout params have gravity-->
+ <!--expand_button_a11y_container ensures talkback focus order is correct when view is expanded.
+ The -1px of marginTop and 1px of paddingTop make sure expand_button_a11y_container is prior to
+ its sibling view in accessibility focus order.
+ {see android.view.ViewGroup.addChildrenForAccessibility()}
+ expand_button_container will be moved under expand_button_and_content_container when collapsed,
+ this dynamic movement ensures message can flow under expand button when expanded-->
<FrameLayout
- android:id="@+id/expand_button_container"
- android:layout_width="wrap_content"
+ android:id="@+id/expand_button_a11y_container"
+ android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="end|top"
android:clipChildren="false"
- android:clipToPadding="false">
- <!--This layout makes sure that we can nicely center the expand content in the
- collapsed layout while the parent makes sure that we're never laid out bigger
- than the messaging content.-->
- <LinearLayout
- android:id="@+id/expand_button_touch_container"
+ android:clipToPadding="false"
+ android:layout_marginTop="-1px"
+ android:paddingTop="1px"
+ >
+ <!--expand_button_container is dynamically placed between here and at the end of the
+ layout. It starts here since only FrameLayout layout params have gravity-->
+ <FrameLayout
+ android:id="@+id/expand_button_container"
android:layout_width="wrap_content"
- android:layout_height="@dimen/conversation_expand_button_height"
- android:orientation="horizontal"
+ android:layout_height="match_parent"
android:layout_gravity="end|top"
- android:paddingEnd="0dp"
- android:clipToPadding="false"
android:clipChildren="false"
- >
- <!-- Images -->
- <com.android.internal.widget.MessagingLinearLayout
- android:id="@+id/conversation_image_message_container"
- android:forceHasOverlappingRendering="false"
- android:layout_width="40dp"
- android:layout_height="40dp"
- android:layout_marginStart="@dimen/conversation_image_start_margin"
- android:spacing="0dp"
- android:layout_gravity="center"
+ android:clipToPadding="false">
+ <!--expand_button_touch_container makes sure that we can nicely center the expand
+ content in the collapsed layout while the parent makes sure that we're never laid out
+ bigger than the messaging content.-->
+ <LinearLayout
+ android:id="@+id/expand_button_touch_container"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/conversation_expand_button_height"
+ android:orientation="horizontal"
+ android:layout_gravity="end|top"
+ android:paddingEnd="0dp"
android:clipToPadding="false"
android:clipChildren="false"
- />
- <include layout="@layout/notification_expand_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- />
- </LinearLayout>
+ >
+ <!-- Images -->
+ <com.android.internal.widget.MessagingLinearLayout
+ android:id="@+id/conversation_image_message_container"
+ android:forceHasOverlappingRendering="false"
+ android:layout_width="40dp"
+ android:layout_height="40dp"
+ android:layout_marginStart="@dimen/conversation_image_start_margin"
+ android:spacing="0dp"
+ android:layout_gravity="center"
+ android:clipToPadding="false"
+ android:clipChildren="false"
+ />
+ <include layout="@layout/notification_expand_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ />
+ </LinearLayout>
+ </FrameLayout>
</FrameLayout>
</com.android.internal.widget.ConversationLayout>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index e5db96a..069bfe7 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -4288,6 +4288,7 @@
<java-symbol type="id" name="conversation_icon_badge_ring" />
<java-symbol type="id" name="conversation_icon_badge_bg" />
<java-symbol type="id" name="expand_button_container" />
+ <java-symbol type="id" name="expand_button_a11y_container" />
<java-symbol type="id" name="expand_button_touch_container" />
<java-symbol type="id" name="messaging_group_content_container" />
<java-symbol type="id" name="expand_button_and_content_container" />
diff --git a/graphics/java/android/graphics/BaseCanvas.java b/graphics/java/android/graphics/BaseCanvas.java
index 54d6428..a8ab6d9 100644
--- a/graphics/java/android/graphics/BaseCanvas.java
+++ b/graphics/java/android/graphics/BaseCanvas.java
@@ -670,9 +670,8 @@
/**
* @hide
*/
- public void punchHole(float left, float top, float right, float bottom, float rx, float ry,
- float alpha) {
- nPunchHole(mNativeCanvasWrapper, left, top, right, bottom, rx, ry, alpha);
+ public void punchHole(float left, float top, float right, float bottom, float rx, float ry) {
+ nPunchHole(mNativeCanvasWrapper, left, top, right, bottom, rx, ry);
}
/**
@@ -824,5 +823,5 @@
float hOffset, float vOffset, int flags, long nativePaint);
private static native void nPunchHole(long renderer, float left, float top, float right,
- float bottom, float rx, float ry, float alpha);
+ float bottom, float rx, float ry);
}
diff --git a/graphics/java/android/graphics/BaseRecordingCanvas.java b/graphics/java/android/graphics/BaseRecordingCanvas.java
index 1ba79b8..d06f665 100644
--- a/graphics/java/android/graphics/BaseRecordingCanvas.java
+++ b/graphics/java/android/graphics/BaseRecordingCanvas.java
@@ -610,9 +610,8 @@
* @hide
*/
@Override
- public void punchHole(float left, float top, float right, float bottom, float rx, float ry,
- float alpha) {
- nPunchHole(mNativeCanvasWrapper, left, top, right, bottom, rx, ry, alpha);
+ public void punchHole(float left, float top, float right, float bottom, float rx, float ry) {
+ nPunchHole(mNativeCanvasWrapper, left, top, right, bottom, rx, ry);
}
@FastNative
@@ -743,5 +742,5 @@
@FastNative
private static native void nPunchHole(long renderer, float left, float top, float right,
- float bottom, float rx, float ry, float alpha);
+ float bottom, float rx, float ry);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index 7c50982..347904e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -82,7 +82,7 @@
import com.android.wm.shell.sysui.ShellCommandHandler;
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;
-import com.android.wm.shell.transition.SplitscreenPipMixedHandler;
+import com.android.wm.shell.transition.DefaultMixedHandler;
import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.unfold.ShellUnfoldProgressProvider;
import com.android.wm.shell.unfold.UnfoldAnimationController;
@@ -484,13 +484,13 @@
@WMSingleton
@Provides
- static SplitscreenPipMixedHandler provideSplitscreenPipMixedHandler(
+ static DefaultMixedHandler provideDefaultMixedHandler(
ShellInit shellInit,
Optional<SplitScreenController> splitScreenOptional,
Optional<PipTouchHandler> pipTouchHandlerOptional,
Transitions transitions) {
- return new SplitscreenPipMixedHandler(shellInit, splitScreenOptional,
- pipTouchHandlerOptional, transitions);
+ return new DefaultMixedHandler(shellInit, transitions, splitScreenOptional,
+ pipTouchHandlerOptional);
}
//
@@ -619,7 +619,7 @@
@ShellCreateTriggerOverride
@Provides
static Object provideIndependentShellComponentsToCreate(
- SplitscreenPipMixedHandler splitscreenPipMixedHandler,
+ DefaultMixedHandler defaultMixedHandler,
Optional<DesktopModeController> desktopModeController) {
return new Object();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
index e26c259..bcf4fbd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
@@ -35,10 +35,14 @@
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.pip.PipTransitionController;
+import com.android.wm.shell.pip.phone.PipTouchHandler;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
+import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.splitscreen.StageCoordinator;
+import com.android.wm.shell.sysui.ShellInit;
import java.util.ArrayList;
+import java.util.Optional;
/**
* A handler for dealing with transitions involving multiple other handlers. For example: an
@@ -47,8 +51,8 @@
public class DefaultMixedHandler implements Transitions.TransitionHandler {
private final Transitions mPlayer;
- private final PipTransitionController mPipHandler;
- private final StageCoordinator mSplitHandler;
+ private PipTransitionController mPipHandler;
+ private StageCoordinator mSplitHandler;
private static class MixedTransition {
static final int TYPE_ENTER_PIP_FROM_SPLIT = 1;
@@ -77,13 +81,22 @@
mTransition = transition;
}
}
+
private final ArrayList<MixedTransition> mActiveTransitions = new ArrayList<>();
- public DefaultMixedHandler(@NonNull Transitions player,
- @NonNull PipTransitionController pipHandler, @NonNull StageCoordinator splitHandler) {
+ public DefaultMixedHandler(@NonNull ShellInit shellInit, @NonNull Transitions player,
+ Optional<SplitScreenController> splitScreenControllerOptional,
+ Optional<PipTouchHandler> pipTouchHandlerOptional) {
mPlayer = player;
- mPipHandler = pipHandler;
- mSplitHandler = splitHandler;
+ if (Transitions.ENABLE_SHELL_TRANSITIONS && pipTouchHandlerOptional.isPresent()
+ && splitScreenControllerOptional.isPresent()) {
+ // Add after dependencies because it is higher priority
+ shellInit.addInitCallback(() -> {
+ mPipHandler = pipTouchHandlerOptional.get().getTransitionHandler();
+ mSplitHandler = splitScreenControllerOptional.get().getTransitionHandler();
+ mPlayer.addHandler(this);
+ }, this);
+ }
}
@Nullable
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/SplitscreenPipMixedHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/SplitscreenPipMixedHandler.java
deleted file mode 100644
index 678e91f..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/SplitscreenPipMixedHandler.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.transition;
-
-import com.android.wm.shell.pip.phone.PipTouchHandler;
-import com.android.wm.shell.splitscreen.SplitScreenController;
-import com.android.wm.shell.sysui.ShellInit;
-
-import java.util.Optional;
-
-/**
- * Handles transitions between the Splitscreen and PIP components.
- */
-public class SplitscreenPipMixedHandler {
-
- private final Optional<SplitScreenController> mSplitScreenOptional;
- private final Optional<PipTouchHandler> mPipTouchHandlerOptional;
- private final Transitions mTransitions;
-
- public SplitscreenPipMixedHandler(ShellInit shellInit,
- Optional<SplitScreenController> splitScreenControllerOptional,
- Optional<PipTouchHandler> pipTouchHandlerOptional,
- Transitions transitions) {
- mSplitScreenOptional = splitScreenControllerOptional;
- mPipTouchHandlerOptional = pipTouchHandlerOptional;
- mTransitions = transitions;
- if (Transitions.ENABLE_SHELL_TRANSITIONS
- && mSplitScreenOptional.isPresent() && mPipTouchHandlerOptional.isPresent()) {
- shellInit.addInitCallback(this::onInit, this);
- }
- }
-
- private void onInit() {
- // Special handling for initializing based on multiple components
- final DefaultMixedHandler mixedHandler = new DefaultMixedHandler(mTransitions,
- mPipTouchHandlerOptional.get().getTransitionHandler(),
- mSplitScreenOptional.get().getTransitionHandler());
- // Added at end so that it has highest priority.
- mTransitions.addHandler(mixedHandler);
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/util/GroupedRecentTaskInfo.java b/libs/WindowManager/Shell/src/com/android/wm/shell/util/GroupedRecentTaskInfo.java
index eab75b9..c045ceb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/util/GroupedRecentTaskInfo.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/util/GroupedRecentTaskInfo.java
@@ -114,7 +114,8 @@
/**
* Get all {@link ActivityManager.RecentTaskInfo}s grouped together.
*/
- public List<ActivityManager.RecentTaskInfo> getAllTaskInfos() {
+ @NonNull
+ public List<ActivityManager.RecentTaskInfo> getTaskInfoList() {
return Arrays.asList(mTasks);
}
@@ -148,7 +149,7 @@
if (mSplitBounds != null) {
taskString.append(", SplitBounds: ").append(mSplitBounds);
}
- taskString.append(", Type=").append(mType);
+ taskString.append(", Type=");
switch (mType) {
case TYPE_SINGLE:
taskString.append("TYPE_SINGLE");
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/GroupedRecentTaskInfoTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/GroupedRecentTaskInfoTest.kt
new file mode 100644
index 0000000..baa06f2
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/GroupedRecentTaskInfoTest.kt
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.recents
+
+import android.app.ActivityManager
+import android.graphics.Rect
+import android.os.Parcel
+import android.testing.AndroidTestingRunner
+import android.window.IWindowContainerToken
+import android.window.WindowContainerToken
+import androidx.test.filters.SmallTest
+import com.android.wm.shell.ShellTestCase
+import com.android.wm.shell.util.GroupedRecentTaskInfo
+import com.android.wm.shell.util.GroupedRecentTaskInfo.CREATOR
+import com.android.wm.shell.util.GroupedRecentTaskInfo.TYPE_FREEFORM
+import com.android.wm.shell.util.GroupedRecentTaskInfo.TYPE_SINGLE
+import com.android.wm.shell.util.GroupedRecentTaskInfo.TYPE_SPLIT
+import com.android.wm.shell.util.SplitBounds
+import com.google.common.truth.Correspondence
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.mock
+
+/**
+ * Tests for [GroupedRecentTaskInfo]
+ */
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class GroupedRecentTaskInfoTest : ShellTestCase() {
+
+ @Test
+ fun testSingleTask_hasCorrectType() {
+ assertThat(singleTaskGroupInfo().type).isEqualTo(TYPE_SINGLE)
+ }
+
+ @Test
+ fun testSingleTask_task1Set_task2Null() {
+ val group = singleTaskGroupInfo()
+ assertThat(group.taskInfo1.taskId).isEqualTo(1)
+ assertThat(group.taskInfo2).isNull()
+ }
+
+ @Test
+ fun testSingleTask_taskInfoList_hasOneTask() {
+ val list = singleTaskGroupInfo().taskInfoList
+ assertThat(list).hasSize(1)
+ assertThat(list[0].taskId).isEqualTo(1)
+ }
+
+ @Test
+ fun testSplitTasks_hasCorrectType() {
+ assertThat(splitTasksGroupInfo().type).isEqualTo(TYPE_SPLIT)
+ }
+
+ @Test
+ fun testSplitTasks_task1Set_task2Set_boundsSet() {
+ val group = splitTasksGroupInfo()
+ assertThat(group.taskInfo1.taskId).isEqualTo(1)
+ assertThat(group.taskInfo2?.taskId).isEqualTo(2)
+ assertThat(group.splitBounds).isNotNull()
+ }
+
+ @Test
+ fun testSplitTasks_taskInfoList_hasTwoTasks() {
+ val list = splitTasksGroupInfo().taskInfoList
+ assertThat(list).hasSize(2)
+ assertThat(list[0].taskId).isEqualTo(1)
+ assertThat(list[1].taskId).isEqualTo(2)
+ }
+
+ @Test
+ fun testFreeformTasks_hasCorrectType() {
+ assertThat(freeformTasksGroupInfo().type).isEqualTo(TYPE_FREEFORM)
+ }
+
+ @Test
+ fun testSplitTasks_taskInfoList_hasThreeTasks() {
+ val list = freeformTasksGroupInfo().taskInfoList
+ assertThat(list).hasSize(3)
+ assertThat(list[0].taskId).isEqualTo(1)
+ assertThat(list[1].taskId).isEqualTo(2)
+ assertThat(list[2].taskId).isEqualTo(3)
+ }
+
+ @Test
+ fun testParcelling_singleTask() {
+ val recentTaskInfo = singleTaskGroupInfo()
+ val parcel = Parcel.obtain()
+ recentTaskInfo.writeToParcel(parcel, 0)
+ parcel.setDataPosition(0)
+ // Read the object back from the parcel
+ val recentTaskInfoParcel = CREATOR.createFromParcel(parcel)
+ assertThat(recentTaskInfoParcel.type).isEqualTo(TYPE_SINGLE)
+ assertThat(recentTaskInfoParcel.taskInfo1.taskId).isEqualTo(1)
+ assertThat(recentTaskInfoParcel.taskInfo2).isNull()
+ }
+
+ @Test
+ fun testParcelling_splitTasks() {
+ val recentTaskInfo = splitTasksGroupInfo()
+ val parcel = Parcel.obtain()
+ recentTaskInfo.writeToParcel(parcel, 0)
+ parcel.setDataPosition(0)
+ // Read the object back from the parcel
+ val recentTaskInfoParcel = CREATOR.createFromParcel(parcel)
+ assertThat(recentTaskInfoParcel.type).isEqualTo(TYPE_SPLIT)
+ assertThat(recentTaskInfoParcel.taskInfo1.taskId).isEqualTo(1)
+ assertThat(recentTaskInfoParcel.taskInfo2).isNotNull()
+ assertThat(recentTaskInfoParcel.taskInfo2!!.taskId).isEqualTo(2)
+ assertThat(recentTaskInfoParcel.splitBounds).isNotNull()
+ }
+
+ @Test
+ fun testParcelling_freeformTasks() {
+ val recentTaskInfo = freeformTasksGroupInfo()
+ val parcel = Parcel.obtain()
+ recentTaskInfo.writeToParcel(parcel, 0)
+ parcel.setDataPosition(0)
+ // Read the object back from the parcel
+ val recentTaskInfoParcel = CREATOR.createFromParcel(parcel)
+ assertThat(recentTaskInfoParcel.type).isEqualTo(TYPE_FREEFORM)
+ assertThat(recentTaskInfoParcel.taskInfoList).hasSize(3)
+ // Only compare task ids
+ val taskIdComparator = Correspondence.transforming<ActivityManager.RecentTaskInfo, Int>(
+ { it?.taskId }, "has taskId of"
+ )
+ assertThat(recentTaskInfoParcel.taskInfoList).comparingElementsUsing(taskIdComparator)
+ .containsExactly(1, 2, 3)
+ }
+
+ private fun createTaskInfo(id: Int) = ActivityManager.RecentTaskInfo().apply {
+ taskId = id
+ token = WindowContainerToken(mock(IWindowContainerToken::class.java))
+ }
+
+ private fun singleTaskGroupInfo(): GroupedRecentTaskInfo {
+ val task = createTaskInfo(id = 1)
+ return GroupedRecentTaskInfo.forSingleTask(task)
+ }
+
+ private fun splitTasksGroupInfo(): GroupedRecentTaskInfo {
+ val task1 = createTaskInfo(id = 1)
+ val task2 = createTaskInfo(id = 2)
+ val splitBounds = SplitBounds(Rect(), Rect(), 1, 2)
+ return GroupedRecentTaskInfo.forSplitTasks(task1, task2, splitBounds)
+ }
+
+ private fun freeformTasksGroupInfo(): GroupedRecentTaskInfo {
+ val task1 = createTaskInfo(id = 1)
+ val task2 = createTaskInfo(id = 2)
+ val task3 = createTaskInfo(id = 3)
+ return GroupedRecentTaskInfo.forFreeformTasks(task1, task2, task3)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
index 9e755dc..e9a1e25 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
@@ -213,8 +213,8 @@
assertEquals(GroupedRecentTaskInfo.TYPE_SINGLE, singleGroup2.getType());
// Check freeform group entries
- assertEquals(t1, freeformGroup.getAllTaskInfos().get(0));
- assertEquals(t3, freeformGroup.getAllTaskInfos().get(1));
+ assertEquals(t1, freeformGroup.getTaskInfoList().get(0));
+ assertEquals(t3, freeformGroup.getTaskInfoList().get(1));
// Check single entries
assertEquals(t2, singleGroup1.getTaskInfo1());
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 473afbd..397975d 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -18,7 +18,6 @@
#include "CanvasProperty.h"
#include "NinePatchUtils.h"
-#include "SkBlendMode.h"
#include "VectorDrawable.h"
#include "hwui/Bitmap.h"
#include "hwui/MinikinUtils.h"
@@ -252,11 +251,10 @@
return (rec && rec->saveCount == currentSaveCount) ? rec : nullptr;
}
-void SkiaCanvas::punchHole(const SkRRect& rect, float alpha) {
+void SkiaCanvas::punchHole(const SkRRect& rect) {
SkPaint paint = SkPaint();
- paint.setColor(SkColors::kBlack);
- paint.setAlphaf(alpha);
- paint.setBlendMode(SkBlendMode::kDstOut);
+ paint.setColor(0);
+ paint.setBlendMode(SkBlendMode::kClear);
mCanvas->drawRRect(rect, paint);
}
diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h
index 51007c5..c6313f6 100644
--- a/libs/hwui/SkiaCanvas.h
+++ b/libs/hwui/SkiaCanvas.h
@@ -65,7 +65,7 @@
LOG_ALWAYS_FATAL("SkiaCanvas does not support enableZ");
}
- virtual void punchHole(const SkRRect& rect, float alpha) override;
+ virtual void punchHole(const SkRRect& rect) override;
virtual void setBitmap(const SkBitmap& bitmap) override;
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
index 82d23b5..7378351 100644
--- a/libs/hwui/hwui/Canvas.h
+++ b/libs/hwui/hwui/Canvas.h
@@ -152,7 +152,7 @@
LOG_ALWAYS_FATAL("Not supported");
}
- virtual void punchHole(const SkRRect& rect, float alpha) = 0;
+ virtual void punchHole(const SkRRect& rect) = 0;
// ----------------------------------------------------------------------------
// Canvas state operations
diff --git a/libs/hwui/jni/android_graphics_Canvas.cpp b/libs/hwui/jni/android_graphics_Canvas.cpp
index 0513447..fb7d5f7 100644
--- a/libs/hwui/jni/android_graphics_Canvas.cpp
+++ b/libs/hwui/jni/android_graphics_Canvas.cpp
@@ -713,10 +713,9 @@
}
static void punchHole(JNIEnv* env, jobject, jlong canvasPtr, jfloat left, jfloat top, jfloat right,
- jfloat bottom, jfloat rx, jfloat ry, jfloat alpha) {
+ jfloat bottom, jfloat rx, jfloat ry) {
auto canvas = reinterpret_cast<Canvas*>(canvasPtr);
- canvas->punchHole(SkRRect::MakeRectXY(SkRect::MakeLTRB(left, top, right, bottom), rx, ry),
- alpha);
+ canvas->punchHole(SkRRect::MakeRectXY(SkRect::MakeLTRB(left, top, right, bottom), rx, ry));
}
}; // namespace CanvasJNI
@@ -791,7 +790,7 @@
{"nDrawTextRun","(JLjava/lang/String;IIIIFFZJ)V", (void*) CanvasJNI::drawTextRunString},
{"nDrawTextOnPath","(J[CIIJFFIJ)V", (void*) CanvasJNI::drawTextOnPathChars},
{"nDrawTextOnPath","(JLjava/lang/String;JFFIJ)V", (void*) CanvasJNI::drawTextOnPathString},
- {"nPunchHole", "(JFFFFFFF)V", (void*) CanvasJNI::punchHole}
+ {"nPunchHole", "(JFFFFFF)V", (void*) CanvasJNI::punchHole}
};
int register_android_graphics_Canvas(JNIEnv* env) {
diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
index f2282e66..3bf2b2e 100644
--- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
+++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
@@ -201,7 +201,6 @@
paint.setAlpha((uint8_t)paint.getAlpha() * mAlpha);
return true;
}
-
void onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) override {
// We unroll the drawable using "this" canvas, so that draw calls contained inside will
// get their alpha applied. The default SkPaintFilterCanvas::onDrawDrawable does not unroll.
@@ -293,7 +292,7 @@
// with the same canvas transformation + clip into the target
// canvas then draw the layer on top
if (renderNode->hasHolePunches()) {
- TransformCanvas transformCanvas(canvas, SkBlendMode::kDstOut);
+ TransformCanvas transformCanvas(canvas, SkBlendMode::kClear);
displayList->draw(&transformCanvas);
}
canvas->drawImageRect(snapshotImage, SkRect::Make(srcBounds),
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index 1f87865..5c6117d 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -69,22 +69,20 @@
mDisplayList->setHasHolePunches(false);
}
-void SkiaRecordingCanvas::punchHole(const SkRRect& rect, float alpha) {
- // Add the marker annotation to allow HWUI to determine the current
- // clip/transformation and alpha should be applied
+void SkiaRecordingCanvas::punchHole(const SkRRect& rect) {
+ // Add the marker annotation to allow HWUI to determine where the current
+ // clip/transformation should be applied
SkVector vector = rect.getSimpleRadii();
- float data[3];
+ float data[2];
data[0] = vector.x();
data[1] = vector.y();
- data[2] = alpha;
mRecorder.drawAnnotation(rect.rect(), HOLE_PUNCH_ANNOTATION.c_str(),
- SkData::MakeWithCopy(data, sizeof(data)));
+ SkData::MakeWithCopy(data, 2 * sizeof(float)));
// Clear the current rect within the layer itself
SkPaint paint = SkPaint();
- paint.setColor(SkColors::kBlack);
- paint.setAlphaf(alpha);
- paint.setBlendMode(SkBlendMode::kDstOut);
+ paint.setColor(0);
+ paint.setBlendMode(SkBlendMode::kClear);
mRecorder.drawRRect(rect, paint);
mDisplayList->setHasHolePunches(true);
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
index 7844e2c..89e3a2c 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
@@ -50,7 +50,7 @@
initDisplayList(renderNode, width, height);
}
- virtual void punchHole(const SkRRect& rect, float alpha) override;
+ virtual void punchHole(const SkRRect& rect) override;
virtual void finishRecording(uirenderer::RenderNode* destination) override;
std::unique_ptr<SkiaDisplayList> finishRecording();
diff --git a/libs/hwui/pipeline/skia/TransformCanvas.cpp b/libs/hwui/pipeline/skia/TransformCanvas.cpp
index c320df0..33160d0 100644
--- a/libs/hwui/pipeline/skia/TransformCanvas.cpp
+++ b/libs/hwui/pipeline/skia/TransformCanvas.cpp
@@ -29,15 +29,13 @@
void TransformCanvas::onDrawAnnotation(const SkRect& rect, const char* key, SkData* value) {
if (HOLE_PUNCH_ANNOTATION == key) {
auto* rectParams = reinterpret_cast<const float*>(value->data());
- const float radiusX = rectParams[0];
- const float radiusY = rectParams[1];
- const float alpha = rectParams[2];
+ float radiusX = rectParams[0];
+ float radiusY = rectParams[1];
SkRRect roundRect = SkRRect::MakeRectXY(rect, radiusX, radiusY);
SkPaint paint;
paint.setColor(SkColors::kBlack);
paint.setBlendMode(mHolePunchBlendMode);
- paint.setAlphaf(alpha);
mWrappedCanvas->drawRRect(roundRect, paint);
}
}
diff --git a/libs/hwui/tests/common/scenes/StretchyListViewAnimation.cpp b/libs/hwui/tests/common/scenes/StretchyListViewAnimation.cpp
index 7d3ca96..59230a7 100644
--- a/libs/hwui/tests/common/scenes/StretchyListViewAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/StretchyListViewAnimation.cpp
@@ -138,7 +138,7 @@
roundRectPaint.setColor(Color::White);
if (addHolePunch) {
// Punch a hole but then cover it up, we don't want to actually see it
- canvas.punchHole(SkRRect::MakeRect(SkRect::MakeWH(itemWidth, itemHeight)), 1.f);
+ canvas.punchHole(SkRRect::MakeRect(SkRect::MakeWH(itemWidth, itemHeight)));
}
canvas.drawRoundRect(0, 0, itemWidth, itemHeight, dp(6), dp(6), roundRectPaint);
@@ -235,4 +235,4 @@
StretchEffectBehavior stretchBehavior() override { return StretchEffectBehavior::UniformScale; }
bool haveHolePunch() override { return true; }
bool forceLayer() override { return true; }
-};
+};
\ No newline at end of file
diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SlowUserQueryDetector.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SlowUserQueryDetector.kt
new file mode 100644
index 0000000..b006615
--- /dev/null
+++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SlowUserQueryDetector.kt
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.systemui.lint
+
+import com.android.tools.lint.detector.api.Category
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Implementation
+import com.android.tools.lint.detector.api.Issue
+import com.android.tools.lint.detector.api.JavaContext
+import com.android.tools.lint.detector.api.Scope
+import com.android.tools.lint.detector.api.Severity
+import com.android.tools.lint.detector.api.SourceCodeScanner
+import com.intellij.psi.PsiMethod
+import org.jetbrains.uast.UCallExpression
+
+/**
+ * Checks for slow calls to ActivityManager.getCurrentUser() or UserManager.getUserInfo() and
+ * suggests using UserTracker instead. For more info, see: http://go/multi-user-in-systemui-slides.
+ */
+@Suppress("UnstableApiUsage")
+class SlowUserQueryDetector : Detector(), SourceCodeScanner {
+
+ override fun getApplicableMethodNames(): List<String> {
+ return listOf("getCurrentUser", "getUserInfo")
+ }
+
+ override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) {
+ val evaluator = context.evaluator
+ if (
+ evaluator.isStatic(method) &&
+ method.name == "getCurrentUser" &&
+ method.containingClass?.qualifiedName == "android.app.ActivityManager"
+ ) {
+ context.report(
+ ISSUE_SLOW_USER_ID_QUERY,
+ method,
+ context.getNameLocation(node),
+ "ActivityManager.getCurrentUser() is slow. " +
+ "Use UserTracker.getUserId() instead."
+ )
+ }
+ if (
+ !evaluator.isStatic(method) &&
+ method.name == "getUserInfo" &&
+ method.containingClass?.qualifiedName == "android.os.UserManager"
+ ) {
+ context.report(
+ ISSUE_SLOW_USER_INFO_QUERY,
+ method,
+ context.getNameLocation(node),
+ "UserManager.getUserInfo() is slow. " + "Use UserTracker.getUserInfo() instead."
+ )
+ }
+ }
+
+ companion object {
+ @JvmField
+ val ISSUE_SLOW_USER_ID_QUERY: Issue =
+ Issue.create(
+ id = "SlowUserIdQuery",
+ briefDescription = "User ID queried using ActivityManager instead of UserTracker.",
+ explanation =
+ "ActivityManager.getCurrentUser() makes a binder call and is slow. " +
+ "Instead, inject a UserTracker and call UserTracker.getUserId(). For " +
+ "more info, see: http://go/multi-user-in-systemui-slides",
+ category = Category.PERFORMANCE,
+ priority = 8,
+ severity = Severity.WARNING,
+ implementation =
+ Implementation(SlowUserQueryDetector::class.java, Scope.JAVA_FILE_SCOPE)
+ )
+
+ @JvmField
+ val ISSUE_SLOW_USER_INFO_QUERY: Issue =
+ Issue.create(
+ id = "SlowUserInfoQuery",
+ briefDescription = "User info queried using UserManager instead of UserTracker.",
+ explanation =
+ "UserManager.getUserInfo() makes a binder call and is slow. " +
+ "Instead, inject a UserTracker and call UserTracker.getUserInfo(). For " +
+ "more info, see: http://go/multi-user-in-systemui-slides",
+ category = Category.PERFORMANCE,
+ priority = 8,
+ severity = Severity.WARNING,
+ implementation =
+ Implementation(SlowUserQueryDetector::class.java, Scope.JAVA_FILE_SCOPE)
+ )
+ }
+}
diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt
index c7c73d3..4879883 100644
--- a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt
+++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt
@@ -30,6 +30,8 @@
get() = listOf(
BindServiceViaContextDetector.ISSUE,
BroadcastSentViaContextDetector.ISSUE,
+ SlowUserQueryDetector.ISSUE_SLOW_USER_ID_QUERY,
+ SlowUserQueryDetector.ISSUE_SLOW_USER_INFO_QUERY,
GetMainLooperViaContextDetector.ISSUE,
RegisterReceiverViaContextDetector.ISSUE,
SoftwareBitmapDetector.ISSUE,
diff --git a/packages/SystemUI/checks/tests/com/android/systemui/lint/SlowUserQueryDetectorTest.kt b/packages/SystemUI/checks/tests/com/android/systemui/lint/SlowUserQueryDetectorTest.kt
new file mode 100644
index 0000000..2738f04
--- /dev/null
+++ b/packages/SystemUI/checks/tests/com/android/systemui/lint/SlowUserQueryDetectorTest.kt
@@ -0,0 +1,194 @@
+package com.android.internal.systemui.lint
+
+import com.android.tools.lint.checks.infrastructure.LintDetectorTest
+import com.android.tools.lint.checks.infrastructure.TestFile
+import com.android.tools.lint.checks.infrastructure.TestFiles
+import com.android.tools.lint.checks.infrastructure.TestLintTask
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Issue
+import org.junit.Test
+
+class SlowUserQueryDetectorTest : LintDetectorTest() {
+
+ override fun getDetector(): Detector = SlowUserQueryDetector()
+ override fun lint(): TestLintTask = super.lint().allowMissingSdk(true)
+
+ override fun getIssues(): List<Issue> =
+ listOf(
+ SlowUserQueryDetector.ISSUE_SLOW_USER_ID_QUERY,
+ SlowUserQueryDetector.ISSUE_SLOW_USER_INFO_QUERY
+ )
+
+ @Test
+ fun testGetCurrentUser() {
+ lint()
+ .files(
+ TestFiles.java(
+ """
+ package test.pkg;
+ import android.app.ActivityManager;
+
+ public class TestClass1 {
+ public void slewlyGetCurrentUser() {
+ ActivityManager.getCurrentUser();
+ }
+ }
+ """
+ )
+ .indented(),
+ *stubs
+ )
+ .issues(
+ SlowUserQueryDetector.ISSUE_SLOW_USER_ID_QUERY,
+ SlowUserQueryDetector.ISSUE_SLOW_USER_INFO_QUERY
+ )
+ .run()
+ .expectWarningCount(1)
+ .expectContains(
+ "ActivityManager.getCurrentUser() is slow. " +
+ "Use UserTracker.getUserId() instead."
+ )
+ }
+
+ @Test
+ fun testGetUserInfo() {
+ lint()
+ .files(
+ TestFiles.java(
+ """
+ package test.pkg;
+ import android.os.UserManager;
+
+ public class TestClass2 {
+ public void slewlyGetUserInfo(UserManager userManager) {
+ userManager.getUserInfo();
+ }
+ }
+ """
+ )
+ .indented(),
+ *stubs
+ )
+ .issues(
+ SlowUserQueryDetector.ISSUE_SLOW_USER_ID_QUERY,
+ SlowUserQueryDetector.ISSUE_SLOW_USER_INFO_QUERY
+ )
+ .run()
+ .expectWarningCount(1)
+ .expectContains(
+ "UserManager.getUserInfo() is slow. " + "Use UserTracker.getUserInfo() instead."
+ )
+ }
+
+ @Test
+ fun testUserTrackerGetUserId() {
+ lint()
+ .files(
+ TestFiles.java(
+ """
+ package test.pkg;
+ import com.android.systemui.settings.UserTracker;
+
+ public class TestClass3 {
+ public void quicklyGetUserId(UserTracker userTracker) {
+ userTracker.getUserId();
+ }
+ }
+ """
+ )
+ .indented(),
+ *stubs
+ )
+ .issues(
+ SlowUserQueryDetector.ISSUE_SLOW_USER_ID_QUERY,
+ SlowUserQueryDetector.ISSUE_SLOW_USER_INFO_QUERY
+ )
+ .run()
+ .expectClean()
+ }
+
+ @Test
+ fun testUserTrackerGetUserInfo() {
+ lint()
+ .files(
+ TestFiles.java(
+ """
+ package test.pkg;
+ import com.android.systemui.settings.UserTracker;
+
+ public class TestClass4 {
+ public void quicklyGetUserId(UserTracker userTracker) {
+ userTracker.getUserInfo();
+ }
+ }
+ """
+ )
+ .indented(),
+ *stubs
+ )
+ .issues(
+ SlowUserQueryDetector.ISSUE_SLOW_USER_ID_QUERY,
+ SlowUserQueryDetector.ISSUE_SLOW_USER_INFO_QUERY
+ )
+ .run()
+ .expectClean()
+ }
+
+ private val activityManagerStub: TestFile =
+ java(
+ """
+ package android.app;
+
+ public class ActivityManager {
+ public static int getCurrentUser() {};
+ }
+ """
+ )
+
+ private val userManagerStub: TestFile =
+ java(
+ """
+ package android.os;
+ import android.content.pm.UserInfo;
+ import android.annotation.UserIdInt;
+
+ public class UserManager {
+ public UserInfo getUserInfo(@UserIdInt int userId) {};
+ }
+ """
+ )
+
+ private val userIdIntStub: TestFile =
+ java(
+ """
+ package android.annotation;
+
+ public @interface UserIdInt {}
+ """
+ )
+
+ private val userInfoStub: TestFile =
+ java(
+ """
+ package android.content.pm;
+
+ public class UserInfo {}
+ """
+ )
+
+ private val userTrackerStub: TestFile =
+ java(
+ """
+ package com.android.systemui.settings;
+ import android.content.pm.UserInfo;
+
+ public interface UserTracker {
+ public int getUserId();
+ public UserInfo getUserInfo();
+ }
+ """
+ )
+
+ private val stubs =
+ arrayOf(activityManagerStub, userManagerStub, userIdIntStub, userInfoStub, userTrackerStub)
+}
diff --git a/packages/SystemUI/compose/gallery/src/com/android/systemui/user/Fakes.kt b/packages/SystemUI/compose/gallery/src/com/android/systemui/user/Fakes.kt
new file mode 100644
index 0000000..02d76f4
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/src/com/android/systemui/user/Fakes.kt
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.user
+
+import android.content.Context
+import androidx.appcompat.content.res.AppCompatResources
+import com.android.systemui.common.shared.model.Text
+import com.android.systemui.compose.gallery.R
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.power.data.repository.FakePowerRepository
+import com.android.systemui.power.domain.interactor.PowerInteractor
+import com.android.systemui.user.data.repository.FakeUserRepository
+import com.android.systemui.user.domain.interactor.UserInteractor
+import com.android.systemui.user.shared.model.UserActionModel
+import com.android.systemui.user.shared.model.UserModel
+import com.android.systemui.user.ui.viewmodel.UserSwitcherViewModel
+import com.android.systemui.util.mockito.mock
+
+object Fakes {
+ private val USER_TINT_COLORS =
+ arrayOf(
+ 0x000000,
+ 0x0000ff,
+ 0x00ff00,
+ 0x00ffff,
+ 0xff0000,
+ 0xff00ff,
+ 0xffff00,
+ 0xffffff,
+ )
+
+ fun fakeUserSwitcherViewModel(
+ context: Context,
+ userCount: Int,
+ ): UserSwitcherViewModel {
+ return UserSwitcherViewModel.Factory(
+ userInteractor =
+ UserInteractor(
+ repository =
+ FakeUserRepository().apply {
+ setUsers(
+ (0 until userCount).map { index ->
+ UserModel(
+ id = index,
+ name = Text.Loaded("user_$index"),
+ image =
+ checkNotNull(
+ AppCompatResources.getDrawable(
+ context,
+ R.drawable.ic_avatar_guest_user
+ )
+ ),
+ isSelected = index == 0,
+ isSelectable = true,
+ )
+ }
+ )
+ setActions(
+ UserActionModel.values().mapNotNull {
+ if (it == UserActionModel.NAVIGATE_TO_USER_MANAGEMENT) {
+ null
+ } else {
+ it
+ }
+ }
+ )
+ },
+ controller = mock(),
+ activityStarter = mock(),
+ keyguardInteractor =
+ KeyguardInteractor(
+ repository =
+ FakeKeyguardRepository().apply { setKeyguardShowing(false) },
+ ),
+ ),
+ powerInteractor =
+ PowerInteractor(
+ repository = FakePowerRepository(),
+ )
+ )
+ .create(UserSwitcherViewModel::class.java)
+ }
+}
diff --git a/packages/SystemUI/ktfmt_includes.txt b/packages/SystemUI/ktfmt_includes.txt
index 7275712..bfbccb8 100644
--- a/packages/SystemUI/ktfmt_includes.txt
+++ b/packages/SystemUI/ktfmt_includes.txt
@@ -240,8 +240,6 @@
-packages/SystemUI/src/com/android/systemui/media/nearby/NearbyMediaDevicesManager.kt
-packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt
-packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttFlags.kt
--packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/ChipInfoCommon.kt
--packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
-packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttLogger.kt
-packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ChipStateReceiver.kt
-packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
@@ -529,6 +527,8 @@
-packages/SystemUI/src/com/android/systemui/statusbar/tv/VpnStatusObserver.kt
-packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowModule.kt
-packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowStateController.kt
+-packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewInfo.kt
+-packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt
-packages/SystemUI/src/com/android/systemui/toast/ToastDefaultAnimation.kt
-packages/SystemUI/src/com/android/systemui/toast/ToastLogger.kt
-packages/SystemUI/src/com/android/systemui/tv/TVSystemUICoreStartableModule.kt
@@ -677,7 +677,6 @@
-packages/SystemUI/tests/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManagerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/media/nearby/NearbyMediaDevicesManagerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt
--packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt
-packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt
-packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt
@@ -834,6 +833,7 @@
-packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/VariableDateViewControllerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/WalletControllerImplTest.kt
-packages/SystemUI/tests/src/com/android/systemui/statusbar/window/StatusBarWindowStateControllerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/unfold/FoldStateLoggingProviderTest.kt
-packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldLatencyTrackerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldTransitionWallpaperControllerTest.kt
diff --git a/packages/SystemUI/res/drawable/media_seekbar_thumb.xml b/packages/SystemUI/res/drawable/media_seekbar_thumb.xml
new file mode 100644
index 0000000..5eb2bfd
--- /dev/null
+++ b/packages/SystemUI/res/drawable/media_seekbar_thumb.xml
@@ -0,0 +1,50 @@
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector android:height="16dp"
+ android:width="4dp"
+ android:viewportHeight="16"
+ android:viewportWidth="4">
+ <group android:name="_R_G">
+ <group android:name="_R_G_L_0_G"
+ android:translateX="2"
+ android:translateY="8">
+ <path android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillColor="#ffffff"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M2 -6 C2,-6 2,6 2,6 C2,7.1 1.1,8 0,8 C0,8 0,8 0,8 C-1.1,8 -2,7.1 -2,6 C-2,6 -2,-6 -2,-6 C-2,-7.1 -1.1,-8 0,-8 C0,-8 0,-8 0,-8 C1.1,-8 2,-7.1 2,-6c "/>
+ </group>
+ </group>
+ <group android:name="time_group"/>
+ </vector>
+ </aapt:attr>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="translateX"
+ android:duration="1017"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector>
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index 0ca19d9..8df8c49 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -83,48 +83,6 @@
android:layout_marginBottom="@dimen/keyguard_affordance_vertical_offset"
android:visibility="gone" />
- <ImageView
- android:id="@+id/wallet_button"
- android:layout_height="@dimen/keyguard_affordance_fixed_height"
- android:layout_width="@dimen/keyguard_affordance_fixed_width"
- android:layout_gravity="bottom|end"
- android:scaleType="center"
- android:tint="?android:attr/textColorPrimary"
- android:src="@drawable/ic_wallet_lockscreen"
- android:background="@drawable/keyguard_bottom_affordance_bg"
- android:layout_marginEnd="@dimen/keyguard_affordance_horizontal_offset"
- android:layout_marginBottom="@dimen/keyguard_affordance_vertical_offset"
- android:contentDescription="@string/accessibility_wallet_button"
- android:visibility="gone" />
-
- <ImageView
- android:id="@+id/qr_code_scanner_button"
- android:layout_height="@dimen/keyguard_affordance_fixed_height"
- android:layout_width="@dimen/keyguard_affordance_fixed_width"
- android:layout_gravity="bottom|end"
- android:scaleType="center"
- android:tint="?android:attr/textColorPrimary"
- android:src="@drawable/ic_qr_code_scanner"
- android:background="@drawable/keyguard_bottom_affordance_bg"
- android:layout_marginEnd="@dimen/keyguard_affordance_horizontal_offset"
- android:layout_marginBottom="@dimen/keyguard_affordance_vertical_offset"
- android:contentDescription="@string/accessibility_qr_code_scanner_button"
- android:visibility="gone" />
-
- <ImageView
- android:id="@+id/controls_button"
- android:layout_height="@dimen/keyguard_affordance_fixed_height"
- android:layout_width="@dimen/keyguard_affordance_fixed_width"
- android:layout_gravity="bottom|start"
- android:scaleType="center"
- android:tint="?android:attr/textColorPrimary"
- android:src="@drawable/controls_icon"
- android:background="@drawable/keyguard_bottom_affordance_bg"
- android:layout_marginStart="@dimen/keyguard_affordance_horizontal_offset"
- android:layout_marginBottom="@dimen/keyguard_affordance_vertical_offset"
- android:contentDescription="@string/quick_controls_title"
- android:visibility="gone" />
-
<FrameLayout
android:id="@+id/overlay_container"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 8af432a..a734fa7 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -580,6 +580,7 @@
</style>
<style name="MediaPlayer.ProgressBar" parent="@android:style/Widget.ProgressBar.Horizontal">
+ <item name="android:thumb">@drawable/media_seekbar_thumb</item>
<item name="android:thumbTint">?android:attr/textColorPrimary</item>
<item name="android:progressDrawable">@drawable/media_squiggly_progress</item>
<item name="android:progressTint">?android:attr/textColorPrimary</item>
diff --git a/packages/SystemUI/shared/Android.bp b/packages/SystemUI/shared/Android.bp
index f59a320..9040ea1 100644
--- a/packages/SystemUI/shared/Android.bp
+++ b/packages/SystemUI/shared/Android.bp
@@ -52,7 +52,7 @@
"SystemUIUnfoldLib",
"androidx.dynamicanimation_dynamicanimation",
"androidx.concurrent_concurrent-futures",
- "gson-prebuilt-jar",
+ "gson",
"dagger2",
"jsr330",
],
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt
index acbea1b..7d6f377 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt
@@ -50,12 +50,10 @@
viewsIdToTranslate =
setOf(
ViewIdToTranslate(R.id.keyguard_status_area, LEFT, filterNever),
- ViewIdToTranslate(R.id.controls_button, LEFT, filterNever),
ViewIdToTranslate(R.id.lockscreen_clock_view_large, LEFT, filterSplitShadeOnly),
ViewIdToTranslate(R.id.lockscreen_clock_view, LEFT, filterNever),
ViewIdToTranslate(
R.id.notification_stack_scroller, RIGHT, filterSplitShadeOnly),
- ViewIdToTranslate(R.id.wallet_button, RIGHT, filterNever),
ViewIdToTranslate(R.id.start_button, LEFT, filterNever),
ViewIdToTranslate(R.id.end_button, RIGHT, filterNever)),
progressProvider = unfoldProgressProvider)
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 094c4a7..1068c26 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -451,6 +451,7 @@
FACE_AUTH_TRIGGERED_TRUST_DISABLED);
}
+ mLogger.logTrustChanged(wasTrusted, enabled, userId);
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
@@ -466,12 +467,16 @@
final boolean userHasTrust = getUserHasTrust(userId);
if (userHasTrust && trustGrantedMessages != null) {
for (String msg : trustGrantedMessages) {
- if (!TextUtils.isEmpty(msg)) {
- message = msg;
+ message = msg;
+ if (!TextUtils.isEmpty(message)) {
break;
}
}
}
+
+ if (message != null) {
+ mLogger.logShowTrustGrantedMessage(message.toString());
+ }
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
@@ -728,6 +733,7 @@
mFingerprintCancelSignal = null;
updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
FACE_AUTH_UPDATED_FP_AUTHENTICATED);
+ mLogger.d("onFingerprintAuthenticated");
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
@@ -971,6 +977,7 @@
mFaceCancelSignal = null;
updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
FACE_AUTH_UPDATED_ON_FACE_AUTHENTICATED);
+ mLogger.d("onFaceAuthenticated");
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
@@ -3431,6 +3438,7 @@
mUserFaceAuthenticated.clear();
mTrustManager.clearAllBiometricRecognized(BiometricSourceType.FINGERPRINT, unlockedUser);
mTrustManager.clearAllBiometricRecognized(BiometricSourceType.FACE, unlockedUser);
+ mLogger.d("clearBiometricRecognized");
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
@@ -3680,6 +3688,9 @@
@Override
public void dump(PrintWriter pw, String[] args) {
pw.println("KeyguardUpdateMonitor state:");
+ pw.println(" getUserHasTrust()=" + getUserHasTrust(getCurrentUser()));
+ pw.println(" getUserUnlockedWithBiometric()="
+ + getUserUnlockedWithBiometric(getCurrentUser()));
pw.println(" SIM States:");
for (SimData data : mSimDatas.values()) {
pw.println(" " + data.toString());
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
index 2bc98f1..7a00cd9 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
@@ -340,4 +340,40 @@
bool1 = dismissKeyguard
}, { "reportUserRequestedUnlock origin=$str1 reason=$str2 dismissKeyguard=$bool1" })
}
+
+ fun logShowTrustGrantedMessage(
+ message: String
+ ) {
+ logBuffer.log(TAG, DEBUG, {
+ str1 = message
+ }, { "showTrustGrantedMessage message$str1" })
+ }
+
+ fun logTrustChanged(
+ wasTrusted: Boolean,
+ isNowTrusted: Boolean,
+ userId: Int
+ ) {
+ logBuffer.log(TAG, DEBUG, {
+ bool1 = wasTrusted
+ bool2 = isNowTrusted
+ int1 = userId
+ }, { "onTrustChanged[user=$int1] wasTrusted=$bool1 isNowTrusted=$bool2" })
+ }
+
+ fun logKeyguardStateUpdate(
+ secure: Boolean,
+ canDismissLockScreen: Boolean,
+ trusted: Boolean,
+ trustManaged: Boolean
+
+ ) {
+ logBuffer.log("KeyguardState", DEBUG, {
+ bool1 = secure
+ bool2 = canDismissLockScreen
+ bool3 = trusted
+ bool4 = trustManaged
+ }, { "#update secure=$bool1 canDismissKeyguard=$bool2" +
+ " trusted=$bool3 trustManaged=$bool4" })
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
index de7242c..78099d1f 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
@@ -92,12 +92,6 @@
public static final ResourceBooleanFlag FACE_SCANNING_ANIM =
new ResourceBooleanFlag(205, R.bool.config_enableFaceScanningAnimation);
- /**
- * Whether the KeyguardBottomArea(View|Controller) should use the modern architecture or the old
- * one.
- */
- public static final ReleasedFlag MODERN_BOTTOM_AREA = new ReleasedFlag(206, true);
-
public static final UnreleasedFlag LOCKSCREEN_CUSTOM_CLOCKS = new UnreleasedFlag(207);
/**
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index 898959e..ee5ef99 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -29,6 +29,7 @@
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY;
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_OCCLUDE;
+import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM;
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
import static android.view.WindowManager.TRANSIT_OLD_NONE;
import static android.view.WindowManager.TRANSIT_OPEN;
@@ -160,6 +161,9 @@
return apps.length == 0 ? TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER
: TRANSIT_OLD_KEYGUARD_GOING_AWAY;
} else if (type == TRANSIT_KEYGUARD_OCCLUDE) {
+ boolean isOccludeByDream = apps.length > 0 && apps[0].taskInfo.topActivityType
+ == WindowConfiguration.ACTIVITY_TYPE_DREAM;
+ if (isOccludeByDream) return TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM;
return TRANSIT_OLD_KEYGUARD_OCCLUDE;
} else if (type == TRANSIT_KEYGUARD_UNOCCLUDE) {
return TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
@@ -271,6 +275,12 @@
definition.addRemoteAnimation(TRANSIT_OLD_KEYGUARD_OCCLUDE,
occludeAnimationAdapter);
+ final RemoteAnimationAdapter occludeByDreamAnimationAdapter =
+ new RemoteAnimationAdapter(
+ mKeyguardViewMediator.getOccludeByDreamAnimationRunner(), 0, 0);
+ definition.addRemoteAnimation(TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM,
+ occludeByDreamAnimationAdapter);
+
final RemoteAnimationAdapter unoccludeAnimationAdapter =
new RemoteAnimationAdapter(
mKeyguardViewMediator.getUnoccludeAnimationRunner(), 0, 0);
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 2c60d5d..dc03436 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -887,6 +887,86 @@
private IRemoteAnimationRunner mOccludeAnimationRunner =
new OccludeActivityLaunchRemoteAnimationRunner(mOccludeAnimationController);
+ private final IRemoteAnimationRunner mOccludeByDreamAnimationRunner =
+ new IRemoteAnimationRunner.Stub() {
+ @Nullable private ValueAnimator mOccludeByDreamAnimator;
+
+ @Override
+ public void onAnimationCancelled(boolean isKeyguardOccluded) {
+ if (mOccludeByDreamAnimator != null) {
+ mOccludeByDreamAnimator.cancel();
+ }
+ setOccluded(isKeyguardOccluded /* isOccluded */, false /* animate */);
+ if (DEBUG) {
+ Log.d(TAG, "Occlude by Dream animation cancelled. Occluded state is now: "
+ + mOccluded);
+ }
+ }
+
+ @Override
+ public void onAnimationStart(int transit, RemoteAnimationTarget[] apps,
+ RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps,
+ IRemoteAnimationFinishedCallback finishedCallback) throws RemoteException {
+ setOccluded(true /* isOccluded */, true /* animate */);
+
+ if (apps == null || apps.length == 0 || apps[0] == null) {
+ if (DEBUG) {
+ Log.d(TAG, "No apps provided to the OccludeByDream runner; "
+ + "skipping occluding animation.");
+ }
+ finishedCallback.onAnimationFinished();
+ return;
+ }
+
+ final RemoteAnimationTarget primary = apps[0];
+ final boolean isDream = (apps[0].taskInfo.topActivityType
+ == WindowConfiguration.ACTIVITY_TYPE_DREAM);
+ if (!isDream) {
+ Log.w(TAG, "The occluding app isn't Dream; "
+ + "finishing up. Please check that the config is correct.");
+ finishedCallback.onAnimationFinished();
+ return;
+ }
+
+ final SyncRtSurfaceTransactionApplier applier =
+ new SyncRtSurfaceTransactionApplier(
+ mKeyguardViewControllerLazy.get().getViewRootImpl().getView());
+
+ mContext.getMainExecutor().execute(() -> {
+ if (mOccludeByDreamAnimator != null) {
+ mOccludeByDreamAnimator.cancel();
+ }
+
+ mOccludeByDreamAnimator = ValueAnimator.ofFloat(0f, 1f);
+ // Use the same duration as for the UNOCCLUDE.
+ mOccludeByDreamAnimator.setDuration(UNOCCLUDE_ANIMATION_DURATION);
+ mOccludeByDreamAnimator.setInterpolator(Interpolators.LINEAR);
+ mOccludeByDreamAnimator.addUpdateListener(
+ animation -> {
+ SyncRtSurfaceTransactionApplier.SurfaceParams.Builder
+ paramsBuilder =
+ new SyncRtSurfaceTransactionApplier.SurfaceParams
+ .Builder(primary.leash)
+ .withAlpha(animation.getAnimatedFraction());
+ applier.scheduleApply(paramsBuilder.build());
+ });
+ mOccludeByDreamAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ try {
+ finishedCallback.onAnimationFinished();
+ mOccludeByDreamAnimator = null;
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
+ });
+
+ mOccludeByDreamAnimator.start();
+ });
+ }
+ };
+
/**
* Animation controller for activities that unocclude the keyguard. This does not use the
* ActivityLaunchAnimator since we're just translating down, rather than emerging from a view
@@ -1682,6 +1762,10 @@
return mOccludeAnimationRunner;
}
+ public IRemoteAnimationRunner getOccludeByDreamAnimationRunner() {
+ return mOccludeByDreamAnimationRunner;
+ }
+
public IRemoteAnimationRunner getUnoccludeAnimationRunner() {
return mUnoccludeAnimationRunner;
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt
index 8f32ff9..ac2c9b1 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt
@@ -94,6 +94,7 @@
hasFavorites = favorites?.isNotEmpty() == true,
hasServiceInfos = serviceInfos.isNotEmpty(),
iconResourceId = component.getTileImageId(),
+ visibility = component.getVisibility(),
),
TAG,
)
@@ -110,9 +111,16 @@
isFeatureEnabled: Boolean,
hasFavorites: Boolean,
hasServiceInfos: Boolean,
+ visibility: ControlsComponent.Visibility,
@DrawableRes iconResourceId: Int?,
): KeyguardQuickAffordanceConfig.State {
- return if (isFeatureEnabled && hasFavorites && hasServiceInfos && iconResourceId != null) {
+ return if (
+ isFeatureEnabled &&
+ hasFavorites &&
+ hasServiceInfos &&
+ iconResourceId != null &&
+ visibility == ControlsComponent.Visibility.AVAILABLE
+ ) {
KeyguardQuickAffordanceConfig.State.Visible(
icon = ContainedDrawable.WithResource(iconResourceId),
contentDescriptionResourceId = component.getTileTitleId(),
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
index 35a6c74..5d6d683 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
@@ -34,15 +34,14 @@
import com.android.systemui.R
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.media.taptotransfer.common.ChipInfoCommon
-import com.android.systemui.media.taptotransfer.common.DEFAULT_TIMEOUT_MILLIS
-import com.android.systemui.media.taptotransfer.common.MediaTttChipControllerCommon
import com.android.systemui.media.taptotransfer.common.MediaTttLogger
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.temporarydisplay.DEFAULT_TIMEOUT_MILLIS
+import com.android.systemui.temporarydisplay.TemporaryViewDisplayController
+import com.android.systemui.temporarydisplay.TemporaryViewInfo
import com.android.systemui.util.animation.AnimationUtil.Companion.frames
import com.android.systemui.util.concurrency.DelayableExecutor
-import com.android.systemui.util.view.ViewUtil
import javax.inject.Inject
/**
@@ -56,18 +55,16 @@
context: Context,
@MediaTttReceiverLogger logger: MediaTttLogger,
windowManager: WindowManager,
- viewUtil: ViewUtil,
mainExecutor: DelayableExecutor,
accessibilityManager: AccessibilityManager,
configurationController: ConfigurationController,
powerManager: PowerManager,
@Main private val mainHandler: Handler,
private val uiEventLogger: MediaTttReceiverUiEventLogger,
-) : MediaTttChipControllerCommon<ChipReceiverInfo>(
+) : TemporaryViewDisplayController<ChipReceiverInfo>(
context,
logger,
windowManager,
- viewUtil,
mainExecutor,
accessibilityManager,
configurationController,
@@ -119,18 +116,18 @@
uiEventLogger.logReceiverStateChange(chipState)
if (chipState == ChipStateReceiver.FAR_FROM_SENDER) {
- removeChip(removalReason = ChipStateReceiver.FAR_FROM_SENDER::class.simpleName!!)
+ removeView(removalReason = ChipStateReceiver.FAR_FROM_SENDER::class.simpleName!!)
return
}
if (appIcon == null) {
- displayChip(ChipReceiverInfo(routeInfo, appIconDrawableOverride = null, appName))
+ displayView(ChipReceiverInfo(routeInfo, appIconDrawableOverride = null, appName))
return
}
appIcon.loadDrawableAsync(
context,
Icon.OnDrawableLoadedListener { drawable ->
- displayChip(ChipReceiverInfo(routeInfo, drawable, appName))
+ displayView(ChipReceiverInfo(routeInfo, drawable, appName))
},
// Notify the listener on the main handler since the listener will update
// the UI.
@@ -138,19 +135,19 @@
)
}
- override fun updateChipView(newChipInfo: ChipReceiverInfo, currentChipView: ViewGroup) {
- super.updateChipView(newChipInfo, currentChipView)
+ override fun updateView(newInfo: ChipReceiverInfo, currentView: ViewGroup) {
+ super.updateView(newInfo, currentView)
val iconName = setIcon(
- currentChipView,
- newChipInfo.routeInfo.clientPackageName,
- newChipInfo.appIconDrawableOverride,
- newChipInfo.appNameOverride
+ currentView,
+ newInfo.routeInfo.clientPackageName,
+ newInfo.appIconDrawableOverride,
+ newInfo.appNameOverride
)
- currentChipView.contentDescription = iconName
+ currentView.contentDescription = iconName
}
- override fun animateChipIn(chipView: ViewGroup) {
- val appIconView = chipView.requireViewById<View>(R.id.app_icon)
+ override fun animateViewIn(view: ViewGroup) {
+ val appIconView = view.requireViewById<View>(R.id.app_icon)
appIconView.animate()
.translationYBy(-1 * getTranslationAmount().toFloat())
.setDuration(30.frames)
@@ -160,8 +157,8 @@
.setDuration(5.frames)
.start()
// Using withEndAction{} doesn't apply a11y focus when screen is unlocked.
- appIconView.postOnAnimation { chipView.requestAccessibilityFocus() }
- startRipple(chipView.requireViewById(R.id.ripple))
+ appIconView.postOnAnimation { view.requestAccessibilityFocus() }
+ startRipple(view.requireViewById(R.id.ripple))
}
override fun getIconSize(isAppIcon: Boolean): Int? =
@@ -216,7 +213,7 @@
val routeInfo: MediaRoute2Info,
val appIconDrawableOverride: Drawable?,
val appNameOverride: CharSequence?
-) : ChipInfoCommon {
+) : TemporaryViewInfo {
override fun getTimeoutMs() = DEFAULT_TIMEOUT_MILLIS
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt
index a153cb6..bde588c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt
@@ -25,7 +25,7 @@
import com.android.internal.logging.UiEventLogger
import com.android.internal.statusbar.IUndoMediaTransferCallback
import com.android.systemui.R
-import com.android.systemui.media.taptotransfer.common.DEFAULT_TIMEOUT_MILLIS
+import com.android.systemui.temporarydisplay.DEFAULT_TIMEOUT_MILLIS
/**
* A class enumerating all the possible states of the media tap-to-transfer chip on the sender
@@ -120,7 +120,7 @@
// state, but that may take too long to go through the binder and the user may be
// confused ast o why the UI hasn't changed yet. So, we immediately change the UI
// here.
- controllerSender.displayChip(
+ controllerSender.displayView(
ChipSenderInfo(
TRANSFER_TO_THIS_DEVICE_TRIGGERED, routeInfo, undoCallback
)
@@ -155,7 +155,7 @@
// state, but that may take too long to go through the binder and the user may be
// confused as to why the UI hasn't changed yet. So, we immediately change the UI
// here.
- controllerSender.displayChip(
+ controllerSender.displayView(
ChipSenderInfo(
TRANSFER_TO_RECEIVER_TRIGGERED, routeInfo, undoCallback
)
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt
index 9335489..0c1ebd7 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt
@@ -33,14 +33,13 @@
import com.android.systemui.animation.ViewHierarchyAnimator
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.media.taptotransfer.common.ChipInfoCommon
-import com.android.systemui.media.taptotransfer.common.MediaTttChipControllerCommon
import com.android.systemui.media.taptotransfer.common.MediaTttLogger
-import com.android.systemui.media.taptotransfer.common.MediaTttRemovalReason
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.temporarydisplay.TemporaryDisplayRemovalReason
+import com.android.systemui.temporarydisplay.TemporaryViewDisplayController
+import com.android.systemui.temporarydisplay.TemporaryViewInfo
import com.android.systemui.util.concurrency.DelayableExecutor
-import com.android.systemui.util.view.ViewUtil
import javax.inject.Inject
/**
@@ -53,17 +52,15 @@
context: Context,
@MediaTttSenderLogger logger: MediaTttLogger,
windowManager: WindowManager,
- viewUtil: ViewUtil,
@Main mainExecutor: DelayableExecutor,
accessibilityManager: AccessibilityManager,
configurationController: ConfigurationController,
powerManager: PowerManager,
private val uiEventLogger: MediaTttSenderUiEventLogger
-) : MediaTttChipControllerCommon<ChipSenderInfo>(
+) : TemporaryViewDisplayController<ChipSenderInfo>(
context,
logger,
windowManager,
- viewUtil,
mainExecutor,
accessibilityManager,
configurationController,
@@ -106,53 +103,52 @@
uiEventLogger.logSenderStateChange(chipState)
if (chipState == ChipStateSender.FAR_FROM_RECEIVER) {
- removeChip(removalReason = ChipStateSender.FAR_FROM_RECEIVER::class.simpleName!!)
+ removeView(removalReason = ChipStateSender.FAR_FROM_RECEIVER::class.simpleName!!)
} else {
- displayChip(ChipSenderInfo(chipState, routeInfo, undoCallback))
+ displayView(ChipSenderInfo(chipState, routeInfo, undoCallback))
}
}
- /** Displays the chip view for the given state. */
- override fun updateChipView(
- newChipInfo: ChipSenderInfo,
- currentChipView: ViewGroup
+ override fun updateView(
+ newInfo: ChipSenderInfo,
+ currentView: ViewGroup
) {
- super.updateChipView(newChipInfo, currentChipView)
+ super.updateView(newInfo, currentView)
- val chipState = newChipInfo.state
+ val chipState = newInfo.state
// App icon
- val iconName = setIcon(currentChipView, newChipInfo.routeInfo.clientPackageName)
+ val iconName = setIcon(currentView, newInfo.routeInfo.clientPackageName)
// Text
- val otherDeviceName = newChipInfo.routeInfo.name.toString()
+ val otherDeviceName = newInfo.routeInfo.name.toString()
val chipText = chipState.getChipTextString(context, otherDeviceName)
- currentChipView.requireViewById<TextView>(R.id.text).text = chipText
+ currentView.requireViewById<TextView>(R.id.text).text = chipText
// Loading
- currentChipView.requireViewById<View>(R.id.loading).visibility =
+ currentView.requireViewById<View>(R.id.loading).visibility =
chipState.isMidTransfer.visibleIfTrue()
// Undo
- val undoView = currentChipView.requireViewById<View>(R.id.undo)
+ val undoView = currentView.requireViewById<View>(R.id.undo)
val undoClickListener = chipState.undoClickListener(
- this, newChipInfo.routeInfo, newChipInfo.undoCallback, uiEventLogger
+ this, newInfo.routeInfo, newInfo.undoCallback, uiEventLogger
)
undoView.setOnClickListener(undoClickListener)
undoView.visibility = (undoClickListener != null).visibleIfTrue()
// Failure
- currentChipView.requireViewById<View>(R.id.failure_icon).visibility =
+ currentView.requireViewById<View>(R.id.failure_icon).visibility =
chipState.isTransferFailure.visibleIfTrue()
// For accessibility
- currentChipView.requireViewById<ViewGroup>(
+ currentView.requireViewById<ViewGroup>(
R.id.media_ttt_sender_chip_inner
).contentDescription = "$iconName $chipText"
}
- override fun animateChipIn(chipView: ViewGroup) {
- val chipInnerView = chipView.requireViewById<ViewGroup>(R.id.media_ttt_sender_chip_inner)
+ override fun animateViewIn(view: ViewGroup) {
+ val chipInnerView = view.requireViewById<ViewGroup>(R.id.media_ttt_sender_chip_inner)
ViewHierarchyAnimator.animateAddition(
chipInnerView,
ViewHierarchyAnimator.Hotspot.TOP,
@@ -165,14 +161,14 @@
)
}
- override fun removeChip(removalReason: String) {
+ override fun removeView(removalReason: String) {
// Don't remove the chip if we're mid-transfer since the user should still be able to
// see the status of the transfer. (But do remove it if it's finally timed out.)
- if (chipInfo?.state?.isMidTransfer == true &&
- removalReason != MediaTttRemovalReason.REASON_TIMEOUT) {
+ if (info?.state?.isMidTransfer == true &&
+ removalReason != TemporaryDisplayRemovalReason.REASON_TIMEOUT) {
return
}
- super.removeChip(removalReason)
+ super.removeView(removalReason)
}
private fun Boolean.visibleIfTrue(): Int {
@@ -188,7 +184,7 @@
val state: ChipStateSender,
val routeInfo: MediaRoute2Info,
val undoCallback: IUndoMediaTransferCallback? = null
-) : ChipInfoCommon {
+) : TemporaryViewInfo {
override fun getTimeoutMs() = state.timeout
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 91c6a9c..c3b265f 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -117,7 +117,6 @@
import com.android.systemui.camera.CameraGestureHelper;
import com.android.systemui.classifier.Classifier;
import com.android.systemui.classifier.FalsingCollector;
-import com.android.systemui.controls.dagger.ControlsComponent;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.DisplayId;
import com.android.systemui.dagger.qualifiers.Main;
@@ -140,7 +139,6 @@
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
-import com.android.systemui.qrcodescanner.controller.QRCodeScannerController;
import com.android.systemui.screenrecord.RecordingController;
import com.android.systemui.shade.transition.ShadeTransitionController;
import com.android.systemui.shared.system.QuickStepContract;
@@ -217,7 +215,6 @@
import com.android.systemui.util.ListenerSet;
import com.android.systemui.util.Utils;
import com.android.systemui.util.time.SystemClock;
-import com.android.systemui.wallet.controller.QuickAccessWalletController;
import com.android.wm.shell.animation.FlingAnimationUtils;
import java.io.PrintWriter;
@@ -325,9 +322,6 @@
private final FragmentService mFragmentService;
private final ScrimController mScrimController;
private final PrivacyDotViewController mPrivacyDotViewController;
- private final QuickAccessWalletController mQuickAccessWalletController;
- private final QRCodeScannerController mQRCodeScannerController;
- private final ControlsComponent mControlsComponent;
private final NotificationRemoteInputManager mRemoteInputManager;
private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
@@ -696,8 +690,8 @@
};
private final CameraGestureHelper mCameraGestureHelper;
- private final Provider<KeyguardBottomAreaViewModel> mKeyguardBottomAreaViewModelProvider;
- private final Provider<KeyguardBottomAreaInteractor> mKeyguardBottomAreaInteractorProvider;
+ private final KeyguardBottomAreaViewModel mKeyguardBottomAreaViewModel;
+ private final KeyguardBottomAreaInteractor mKeyguardBottomAreaInteractor;
@Inject
public NotificationPanelViewController(NotificationPanelView view,
@@ -746,8 +740,6 @@
NavigationModeController navigationModeController,
FragmentService fragmentService,
ContentResolver contentResolver,
- QuickAccessWalletController quickAccessWalletController,
- QRCodeScannerController qrCodeScannerController,
RecordingController recordingController,
LargeScreenShadeHeaderController largeScreenShadeHeaderController,
ScreenOffAnimationController screenOffAnimationController,
@@ -755,7 +747,6 @@
PanelExpansionStateManager panelExpansionStateManager,
NotificationRemoteInputManager remoteInputManager,
Optional<SysUIUnfoldComponent> unfoldComponent,
- ControlsComponent controlsComponent,
InteractionJankMonitor interactionJankMonitor,
QsFrameTranslateController qsFrameTranslateController,
SysUiState sysUiState,
@@ -768,8 +759,8 @@
ShadeTransitionController shadeTransitionController,
SystemClock systemClock,
CameraGestureHelper cameraGestureHelper,
- Provider<KeyguardBottomAreaViewModel> keyguardBottomAreaViewModelProvider,
- Provider<KeyguardBottomAreaInteractor> keyguardBottomAreaInteractorProvider) {
+ KeyguardBottomAreaViewModel keyguardBottomAreaViewModel,
+ KeyguardBottomAreaInteractor keyguardBottomAreaInteractor) {
super(view,
falsingManager,
dozeLog,
@@ -791,9 +782,6 @@
mVibratorHelper = vibratorHelper;
mKeyguardMediaController = keyguardMediaController;
mPrivacyDotViewController = privacyDotViewController;
- mQuickAccessWalletController = quickAccessWalletController;
- mQRCodeScannerController = qrCodeScannerController;
- mControlsComponent = controlsComponent;
mMetricsLogger = metricsLogger;
mConfigurationController = configurationController;
mFlingAnimationUtilsBuilder = flingAnimationUtilsBuilder;
@@ -897,7 +885,7 @@
mQsFrameTranslateController = qsFrameTranslateController;
updateUserSwitcherFlags();
- mKeyguardBottomAreaViewModelProvider = keyguardBottomAreaViewModelProvider;
+ mKeyguardBottomAreaViewModel = keyguardBottomAreaViewModel;
onFinishInflate();
keyguardUnlockAnimationController.addKeyguardUnlockAnimationListener(
new KeyguardUnlockAnimationController.KeyguardUnlockAnimationListener() {
@@ -951,7 +939,7 @@
}
});
mCameraGestureHelper = cameraGestureHelper;
- mKeyguardBottomAreaInteractorProvider = keyguardBottomAreaInteractorProvider;
+ mKeyguardBottomAreaInteractor = keyguardBottomAreaInteractor;
}
@VisibleForTesting
@@ -1276,17 +1264,7 @@
}
private void initBottomArea() {
- if (mFeatureFlags.isEnabled(Flags.MODERN_BOTTOM_AREA)) {
- mKeyguardBottomArea.init(mKeyguardBottomAreaViewModelProvider.get(), mFalsingManager);
- } else {
- // TODO(b/235403546): remove this method call when the new implementation is complete
- // and these are not needed.
- mKeyguardBottomArea.init(
- mFalsingManager,
- mQuickAccessWalletController,
- mControlsComponent,
- mQRCodeScannerController);
- }
+ mKeyguardBottomArea.init(mKeyguardBottomAreaViewModel, mFalsingManager);
}
@VisibleForTesting
@@ -1403,7 +1381,6 @@
}
mNotificationStackScrollLayoutController.setIntrinsicPadding(stackScrollerPadding);
- mKeyguardBottomArea.setAntiBurnInOffsetX(mClockPositionResult.clockX);
mStackScrollerMeasuringPass++;
requestScrollerTopPaddingUpdate(animate);
@@ -1453,7 +1430,7 @@
mKeyguardStatusViewController.getClockBottom(mStatusBarHeaderHeightKeyguard),
mKeyguardStatusViewController.isClockTopAligned());
mClockPositionAlgorithm.run(mClockPositionResult);
- mKeyguardBottomAreaInteractorProvider.get().setClockPosition(
+ mKeyguardBottomAreaInteractor.setClockPosition(
mClockPositionResult.clockX, mClockPositionResult.clockY);
boolean animate = mNotificationStackScrollLayoutController.isAddOrRemoveAnimationPending();
boolean animateClock = (animate || mAnimateNextPositionUpdate) && shouldAnimateClockChange;
@@ -3296,8 +3273,7 @@
getExpandedFraction());
float alpha = Math.min(expansionAlpha, 1 - computeQsExpansionFraction());
alpha *= mBottomAreaShadeAlpha;
- mKeyguardBottomArea.setComponentAlphas(alpha);
- mKeyguardBottomAreaInteractorProvider.get().setAlpha(alpha);
+ mKeyguardBottomAreaInteractor.setAlpha(alpha);
mLockIconViewController.setAlpha(alpha);
}
@@ -3496,8 +3472,7 @@
}
private void updateDozingVisibilities(boolean animate) {
- mKeyguardBottomArea.setDozing(mDozing, animate);
- mKeyguardBottomAreaInteractorProvider.get().setAnimateDozingTransitions(animate);
+ mKeyguardBottomAreaInteractor.setAnimateDozingTransitions(animate);
if (!mDozing && animate) {
mKeyguardStatusBarViewController.animateKeyguardStatusBarIn();
}
@@ -3799,8 +3774,7 @@
mView.setDozing(dozing);
mDozing = dozing;
mNotificationStackScrollLayoutController.setDozing(mDozing, animate);
- mKeyguardBottomArea.setDozing(mDozing, animate);
- mKeyguardBottomAreaInteractorProvider.get().setAnimateDozingTransitions(animate);
+ mKeyguardBottomAreaInteractor.setAnimateDozingTransitions(animate);
mKeyguardStatusBarViewController.setDozing(mDozing);
if (dozing) {
@@ -3849,7 +3823,6 @@
public void dozeTimeTick() {
mLockIconViewController.dozeTimeTick();
- mKeyguardBottomArea.dozeTimeTick();
mKeyguardStatusViewController.dozeTimeTick();
if (mInterpolatedDarkAmount > 0) {
positionClockAndNotifications();
@@ -4672,7 +4645,6 @@
public void onDozeAmountChanged(float linearAmount, float amount) {
mInterpolatedDarkAmount = amount;
mLinearDarkAmount = linearAmount;
- mKeyguardBottomArea.setDarkAmount(mInterpolatedDarkAmount);
positionClockAndNotifications();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/PulsingGestureListener.kt b/packages/SystemUI/src/com/android/systemui/shade/PulsingGestureListener.kt
index 621a609..9b3fe92 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/PulsingGestureListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/PulsingGestureListener.kt
@@ -26,6 +26,7 @@
import com.android.systemui.dock.DockManager
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.phone.CentralSurfaces
import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent
import com.android.systemui.tuner.TunerService
@@ -49,6 +50,7 @@
private val dockManager: DockManager,
private val centralSurfaces: CentralSurfaces,
private val ambientDisplayConfiguration: AmbientDisplayConfiguration,
+ private val statusBarStateController: StatusBarStateController,
tunerService: TunerService,
dumpManager: DumpManager
) : GestureDetector.SimpleOnGestureListener(), Dumpable {
@@ -74,7 +76,8 @@
}
override fun onSingleTapConfirmed(e: MotionEvent): Boolean {
- if (singleTapEnabled &&
+ if (statusBarStateController.isPulsing &&
+ singleTapEnabled &&
!dockManager.isDocked &&
!falsingManager.isProximityNear &&
!falsingManager.isFalseTap(FalsingManager.MODERATE_PENALTY)
@@ -89,7 +92,8 @@
}
override fun onDoubleTap(e: MotionEvent): Boolean {
- if ((doubleTapEnabled || singleTapEnabled) &&
+ if (statusBarStateController.isPulsing &&
+ (doubleTapEnabled || singleTapEnabled) &&
!falsingManager.isProximityNear &&
!falsingManager.isFalseDoubleTap
) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index cf5b2d1..408c61f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -692,11 +692,11 @@
/**
* Returns the indication text indicating that trust has been granted.
*
- * @return {@code null} or an empty string if a trust indication text should not be shown.
+ * @return an empty string if a trust indication text should not be shown.
*/
@VisibleForTesting
String getTrustGrantedIndication() {
- return TextUtils.isEmpty(mTrustGrantedIndication)
+ return mTrustGrantedIndication == null
? mContext.getString(R.string.keyguard_indication_trust_unlocked)
: mTrustGrantedIndication.toString();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index 456d4cf..4cc67a0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -3306,14 +3306,12 @@
// show the bouncer/lockscreen.
if (!mKeyguardViewMediator.isHiding()
&& !mKeyguardUnlockAnimationController.isPlayingCannedUnlockAnimation()) {
- if (mState == StatusBarState.SHADE_LOCKED
- && mKeyguardUpdateMonitor.isUdfpsEnrolled()) {
+ if (mState == StatusBarState.SHADE_LOCKED) {
// shade is showing while locked on the keyguard, so go back to showing the
// lock screen where users can use the UDFPS affordance to enter the device
mStatusBarKeyguardViewManager.reset(true);
- } else if ((mState == StatusBarState.KEYGUARD
- && !mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing())
- || mState == StatusBarState.SHADE_LOCKED) {
+ } else if (mState == StatusBarState.KEYGUARD
+ && !mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing()) {
mStatusBarKeyguardViewManager.showGenericBouncer(true /* scrimmed */);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
deleted file mode 100644
index cc451d9..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ /dev/null
@@ -1,682 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.statusbar.phone;
-
-import static com.android.internal.util.Preconditions.checkNotNull;
-import static com.android.systemui.controls.dagger.ControlsComponent.Visibility.AVAILABLE;
-import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
-import static com.android.systemui.wallet.controller.QuickAccessWalletController.WalletChangeEvent.DEFAULT_PAYMENT_APP_CHANGE;
-import static com.android.systemui.wallet.controller.QuickAccessWalletController.WalletChangeEvent.WALLET_PREFERENCE_CHANGE;
-
-import android.app.ActivityTaskManager;
-import android.app.admin.DevicePolicyManager;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.res.ColorStateList;
-import android.content.res.Configuration;
-import android.graphics.drawable.Drawable;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.service.quickaccesswallet.GetWalletCardsError;
-import android.service.quickaccesswallet.GetWalletCardsResponse;
-import android.service.quickaccesswallet.QuickAccessWalletClient;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.util.TypedValue;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewPropertyAnimator;
-import android.view.WindowInsets;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.android.settingslib.Utils;
-import com.android.systemui.Dependency;
-import com.android.systemui.R;
-import com.android.systemui.animation.ActivityLaunchAnimator;
-import com.android.systemui.animation.Interpolators;
-import com.android.systemui.controls.dagger.ControlsComponent;
-import com.android.systemui.controls.management.ControlsListingController;
-import com.android.systemui.controls.ui.ControlsActivity;
-import com.android.systemui.controls.ui.ControlsUiController;
-import com.android.systemui.keyguard.ui.binder.KeyguardBottomAreaViewBinder;
-import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel;
-import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.plugins.FalsingManager;
-import com.android.systemui.qrcodescanner.controller.QRCodeScannerController;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
-import com.android.systemui.wallet.controller.QuickAccessWalletController;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Implementation for the bottom area of the Keyguard, including camera/phone affordance and status
- * text.
- */
-public class KeyguardBottomAreaView extends FrameLayout {
-
- private static final String TAG = "CentralSurfaces/KeyguardBottomAreaView";
- private static final int DOZE_ANIMATION_ELEMENT_DURATION = 250;
-
- private ImageView mWalletButton;
- private ImageView mQRCodeScannerButton;
- private ImageView mControlsButton;
- private boolean mHasCard = false;
- private final WalletCardRetriever mCardRetriever = new WalletCardRetriever();
- private QuickAccessWalletController mQuickAccessWalletController;
- private QRCodeScannerController mQRCodeScannerController;
- private ControlsComponent mControlsComponent;
- private boolean mControlServicesAvailable = false;
-
- @Nullable private View mAmbientIndicationArea;
- private ViewGroup mIndicationArea;
- private TextView mIndicationText;
- private TextView mIndicationTextBottom;
- private ViewGroup mOverlayContainer;
-
- private ActivityStarter mActivityStarter;
- private KeyguardStateController mKeyguardStateController;
- private FalsingManager mFalsingManager;
-
- private boolean mDozing;
- private int mIndicationBottomMargin;
- private int mIndicationPadding;
- private float mDarkAmount;
- private int mBurnInXOffset;
- private int mBurnInYOffset;
-
- private final ControlsListingController.ControlsListingCallback mListingCallback =
- serviceInfos -> post(() -> {
- boolean available = !serviceInfos.isEmpty();
-
- if (available != mControlServicesAvailable) {
- mControlServicesAvailable = available;
- updateControlsVisibility();
- updateAffordanceColors();
- }
- });
-
- private final KeyguardStateController.Callback mKeyguardStateCallback =
- new KeyguardStateController.Callback() {
- @Override
- public void onKeyguardShowingChanged() {
- if (mKeyguardStateController.isShowing()) {
- if (mQuickAccessWalletController != null) {
- mQuickAccessWalletController.queryWalletCards(mCardRetriever);
- }
- }
- }
- };
-
- @Nullable private KeyguardBottomAreaViewBinder.Binding mBinding;
- private boolean mUsesBinder;
-
- public KeyguardBottomAreaView(Context context) {
- this(context, null);
- }
-
- public KeyguardBottomAreaView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public KeyguardBottomAreaView(Context context, AttributeSet attrs, int defStyleAttr) {
- this(context, attrs, defStyleAttr, 0);
- }
-
- public KeyguardBottomAreaView(Context context, AttributeSet attrs, int defStyleAttr,
- int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
- }
-
- /**
- * Initializes the view.
- */
- public void init(
- final KeyguardBottomAreaViewModel viewModel,
- final FalsingManager falsingManager) {
- Log.i(TAG, System.identityHashCode(this) + " initialized with a binder");
- mUsesBinder = true;
- mBinding = KeyguardBottomAreaViewBinder.bind(this, viewModel, falsingManager);
- }
-
- /**
- * Initializes the {@link KeyguardBottomAreaView} with the given dependencies
- *
- * @deprecated Use
- * {@link #init(KeyguardBottomAreaViewModel, FalsingManager)} instead
- */
- @Deprecated
- public void init(
- FalsingManager falsingManager,
- QuickAccessWalletController controller,
- ControlsComponent controlsComponent,
- QRCodeScannerController qrCodeScannerController) {
- if (mUsesBinder) {
- return;
- }
-
- Log.i(TAG, "initialized without a binder");
- mFalsingManager = falsingManager;
-
- mQuickAccessWalletController = controller;
- mQuickAccessWalletController.setupWalletChangeObservers(
- mCardRetriever, WALLET_PREFERENCE_CHANGE, DEFAULT_PAYMENT_APP_CHANGE);
- mQuickAccessWalletController.updateWalletPreference();
- mQuickAccessWalletController.queryWalletCards(mCardRetriever);
- updateWalletVisibility();
-
- mControlsComponent = controlsComponent;
- mControlsComponent.getControlsListingController().ifPresent(
- c -> c.addCallback(mListingCallback));
-
- mQRCodeScannerController = qrCodeScannerController;
- mQRCodeScannerController.registerQRCodeScannerChangeObservers(
- QRCodeScannerController.DEFAULT_QR_CODE_SCANNER_CHANGE,
- QRCodeScannerController.QR_CODE_SCANNER_PREFERENCE_CHANGE);
- updateQRCodeButtonVisibility();
-
- updateAffordanceColors();
- }
-
- /**
- * Initializes this instance of {@link KeyguardBottomAreaView} based on the given instance of
- * another {@link KeyguardBottomAreaView}
- */
- public void initFrom(KeyguardBottomAreaView oldBottomArea) {
- if (mUsesBinder) {
- return;
- }
-
- // if it exists, continue to use the original ambient indication container
- // instead of the newly inflated one
- if (mAmbientIndicationArea != null) {
- // remove old ambient indication from its parent
- View originalAmbientIndicationView =
- oldBottomArea.findViewById(R.id.ambient_indication_container);
- ((ViewGroup) originalAmbientIndicationView.getParent())
- .removeView(originalAmbientIndicationView);
-
- // remove current ambient indication from its parent (discard)
- ViewGroup ambientIndicationParent = (ViewGroup) mAmbientIndicationArea.getParent();
- int ambientIndicationIndex =
- ambientIndicationParent.indexOfChild(mAmbientIndicationArea);
- ambientIndicationParent.removeView(mAmbientIndicationArea);
-
- // add the old ambient indication to this view
- ambientIndicationParent.addView(originalAmbientIndicationView, ambientIndicationIndex);
- mAmbientIndicationArea = originalAmbientIndicationView;
-
- // update burn-in offsets
- dozeTimeTick();
- }
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- if (mUsesBinder) {
- return;
- }
-
- mOverlayContainer = findViewById(R.id.overlay_container);
- mWalletButton = findViewById(R.id.wallet_button);
- mQRCodeScannerButton = findViewById(R.id.qr_code_scanner_button);
- mControlsButton = findViewById(R.id.controls_button);
- mIndicationArea = findViewById(R.id.keyguard_indication_area);
- mAmbientIndicationArea = findViewById(R.id.ambient_indication_container);
- mIndicationText = findViewById(R.id.keyguard_indication_text);
- mIndicationTextBottom = findViewById(R.id.keyguard_indication_text_bottom);
- mIndicationBottomMargin = getResources().getDimensionPixelSize(
- R.dimen.keyguard_indication_margin_bottom);
- mBurnInYOffset = getResources().getDimensionPixelSize(
- R.dimen.default_burn_in_prevention_offset);
- mKeyguardStateController = Dependency.get(KeyguardStateController.class);
- mKeyguardStateController.addCallback(mKeyguardStateCallback);
- setClipChildren(false);
- setClipToPadding(false);
- mActivityStarter = Dependency.get(ActivityStarter.class);
-
- mIndicationPadding = getResources().getDimensionPixelSize(
- R.dimen.keyguard_indication_area_padding);
- updateWalletVisibility();
- updateQRCodeButtonVisibility();
- updateControlsVisibility();
- }
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- if (mUsesBinder) {
- return;
- }
-
- final IntentFilter filter = new IntentFilter();
- filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
- mKeyguardStateController.addCallback(mKeyguardStateCallback);
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- if (mUsesBinder) {
- return;
- }
-
- mKeyguardStateController.removeCallback(mKeyguardStateCallback);
-
- if (mQuickAccessWalletController != null) {
- mQuickAccessWalletController.unregisterWalletChangeObservers(
- WALLET_PREFERENCE_CHANGE, DEFAULT_PAYMENT_APP_CHANGE);
- }
-
- if (mQRCodeScannerController != null) {
- mQRCodeScannerController.unregisterQRCodeScannerChangeObservers(
- QRCodeScannerController.DEFAULT_QR_CODE_SCANNER_CHANGE,
- QRCodeScannerController.QR_CODE_SCANNER_PREFERENCE_CHANGE);
- }
-
- if (mControlsComponent != null) {
- mControlsComponent.getControlsListingController().ifPresent(
- c -> c.removeCallback(mListingCallback));
- }
- }
-
- @Override
- protected void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- if (mUsesBinder) {
- if (mBinding != null) {
- mBinding.onConfigurationChanged();
- }
- return;
- }
-
- mIndicationBottomMargin = getResources().getDimensionPixelSize(
- R.dimen.keyguard_indication_margin_bottom);
- mBurnInYOffset = getResources().getDimensionPixelSize(
- R.dimen.default_burn_in_prevention_offset);
- MarginLayoutParams mlp = (MarginLayoutParams) mIndicationArea.getLayoutParams();
- if (mlp.bottomMargin != mIndicationBottomMargin) {
- mlp.bottomMargin = mIndicationBottomMargin;
- mIndicationArea.setLayoutParams(mlp);
- }
-
- // Respect font size setting.
- mIndicationTextBottom.setTextSize(TypedValue.COMPLEX_UNIT_PX,
- getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.text_size_small_material));
- mIndicationText.setTextSize(TypedValue.COMPLEX_UNIT_PX,
- getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.text_size_small_material));
-
- ViewGroup.LayoutParams lp = mWalletButton.getLayoutParams();
- lp.width = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_width);
- lp.height = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_height);
- mWalletButton.setLayoutParams(lp);
-
- lp = mQRCodeScannerButton.getLayoutParams();
- lp.width = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_width);
- lp.height = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_height);
- mQRCodeScannerButton.setLayoutParams(lp);
-
- lp = mControlsButton.getLayoutParams();
- lp.width = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_width);
- lp.height = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_height);
- mControlsButton.setLayoutParams(lp);
-
- mIndicationPadding = getResources().getDimensionPixelSize(
- R.dimen.keyguard_indication_area_padding);
-
- updateWalletVisibility();
- updateQRCodeButtonVisibility();
- updateAffordanceColors();
- }
-
- private void updateWalletVisibility() {
- if (mUsesBinder) {
- return;
- }
-
- if (mDozing
- || mQuickAccessWalletController == null
- || !mQuickAccessWalletController.isWalletEnabled()
- || !mHasCard) {
- mWalletButton.setVisibility(GONE);
-
- if (mControlsButton.getVisibility() == GONE) {
- mIndicationArea.setPadding(0, 0, 0, 0);
- }
- } else {
- mWalletButton.setVisibility(VISIBLE);
- mWalletButton.setOnClickListener(this::onWalletClick);
- mIndicationArea.setPadding(mIndicationPadding, 0, mIndicationPadding, 0);
- }
- }
-
- private void updateControlsVisibility() {
- if (mUsesBinder) {
- return;
- }
-
- if (mControlsComponent == null) return;
-
- mControlsButton.setImageResource(mControlsComponent.getTileImageId());
- mControlsButton.setContentDescription(getContext()
- .getString(mControlsComponent.getTileTitleId()));
- updateAffordanceColors();
-
- boolean hasFavorites = mControlsComponent.getControlsController()
- .map(c -> c.getFavorites().size() > 0)
- .orElse(false);
- if (mDozing
- || !hasFavorites
- || !mControlServicesAvailable
- || mControlsComponent.getVisibility() != AVAILABLE) {
- mControlsButton.setVisibility(GONE);
- if (mWalletButton.getVisibility() == GONE) {
- mIndicationArea.setPadding(0, 0, 0, 0);
- }
- } else {
- mControlsButton.setVisibility(VISIBLE);
- mControlsButton.setOnClickListener(this::onControlsClick);
- mIndicationArea.setPadding(mIndicationPadding, 0, mIndicationPadding, 0);
- }
- }
-
- public void setDarkAmount(float darkAmount) {
- if (mUsesBinder) {
- return;
- }
-
- if (darkAmount == mDarkAmount) {
- return;
- }
- mDarkAmount = darkAmount;
- dozeTimeTick();
- }
-
- /**
- * Returns a list of animators to use to animate the indication areas.
- */
- public List<ViewPropertyAnimator> getIndicationAreaAnimators() {
- if (mUsesBinder) {
- return checkNotNull(mBinding).getIndicationAreaAnimators();
- }
-
- List<ViewPropertyAnimator> animators =
- new ArrayList<>(mAmbientIndicationArea != null ? 2 : 1);
- animators.add(mIndicationArea.animate());
- if (mAmbientIndicationArea != null) {
- animators.add(mAmbientIndicationArea.animate());
- }
- return animators;
- }
-
- @Override
- public boolean hasOverlappingRendering() {
- return false;
- }
-
- private void startFinishDozeAnimation() {
- long delay = 0;
- if (mWalletButton.getVisibility() == View.VISIBLE) {
- startFinishDozeAnimationElement(mWalletButton, delay);
- }
- if (mQRCodeScannerButton.getVisibility() == View.VISIBLE) {
- startFinishDozeAnimationElement(mQRCodeScannerButton, delay);
- }
- if (mControlsButton.getVisibility() == View.VISIBLE) {
- startFinishDozeAnimationElement(mControlsButton, delay);
- }
- }
-
- private void startFinishDozeAnimationElement(View element, long delay) {
- element.setAlpha(0f);
- element.setTranslationY(element.getHeight() / 2);
- element.animate()
- .alpha(1f)
- .translationY(0f)
- .setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN)
- .setStartDelay(delay)
- .setDuration(DOZE_ANIMATION_ELEMENT_DURATION);
- }
-
- public void setDozing(boolean dozing, boolean animate) {
- if (mUsesBinder) {
- return;
- }
-
- mDozing = dozing;
-
- updateWalletVisibility();
- updateControlsVisibility();
- updateQRCodeButtonVisibility();
-
- if (dozing) {
- mOverlayContainer.setVisibility(INVISIBLE);
- } else {
- mOverlayContainer.setVisibility(VISIBLE);
- if (animate) {
- startFinishDozeAnimation();
- }
- }
- }
-
- public void dozeTimeTick() {
- if (mUsesBinder) {
- return;
- }
-
- int burnInYOffset = getBurnInOffset(mBurnInYOffset * 2, false /* xAxis */)
- - mBurnInYOffset;
- mIndicationArea.setTranslationY(burnInYOffset * mDarkAmount);
- if (mAmbientIndicationArea != null) {
- mAmbientIndicationArea.setTranslationY(burnInYOffset * mDarkAmount);
- }
- }
-
- public void setAntiBurnInOffsetX(int burnInXOffset) {
- if (mUsesBinder) {
- return;
- }
-
- if (mBurnInXOffset == burnInXOffset) {
- return;
- }
- mBurnInXOffset = burnInXOffset;
- mIndicationArea.setTranslationX(burnInXOffset);
- if (mAmbientIndicationArea != null) {
- mAmbientIndicationArea.setTranslationX(burnInXOffset);
- }
- }
-
- /**
- * Sets the alpha of various sub-components, for example the indication areas and bottom quick
- * action buttons. Does not set the alpha of the lock icon.
- */
- public void setComponentAlphas(float alpha) {
- if (mUsesBinder) {
- return;
- }
-
- setImportantForAccessibility(
- alpha == 0f
- ? View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
- : View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
- if (mAmbientIndicationArea != null) {
- mAmbientIndicationArea.setAlpha(alpha);
- }
- mIndicationArea.setAlpha(alpha);
- mWalletButton.setAlpha(alpha);
- mQRCodeScannerButton.setAlpha(alpha);
- mControlsButton.setAlpha(alpha);
- }
-
- @Override
- public WindowInsets onApplyWindowInsets(WindowInsets insets) {
- int bottom = insets.getDisplayCutout() != null
- ? insets.getDisplayCutout().getSafeInsetBottom() : 0;
- if (isPaddingRelative()) {
- setPaddingRelative(getPaddingStart(), getPaddingTop(), getPaddingEnd(), bottom);
- } else {
- setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), bottom);
- }
- return insets;
- }
-
- private void updateQRCodeButtonVisibility() {
- if (mUsesBinder) {
- return;
- }
-
- if (mQuickAccessWalletController != null
- && mQuickAccessWalletController.isWalletEnabled()) {
- // Don't enable if quick access wallet is enabled
- return;
- }
-
- if (mQRCodeScannerController != null
- && mQRCodeScannerController.isEnabledForLockScreenButton()) {
- mQRCodeScannerButton.setVisibility(VISIBLE);
- mQRCodeScannerButton.setOnClickListener(this::onQRCodeScannerClicked);
- mIndicationArea.setPadding(mIndicationPadding, 0, mIndicationPadding, 0);
- } else {
- mQRCodeScannerButton.setVisibility(GONE);
- if (mControlsButton.getVisibility() == GONE) {
- mIndicationArea.setPadding(0, 0, 0, 0);
- }
- }
- }
-
- private void onQRCodeScannerClicked(View view) {
- if (mUsesBinder) {
- return;
- }
-
- Intent intent = mQRCodeScannerController.getIntent();
- if (intent != null) {
- try {
- ActivityTaskManager.getService().startActivityAsUser(
- null, getContext().getBasePackageName(),
- getContext().getAttributionTag(), intent,
- intent.resolveTypeIfNeeded(getContext().getContentResolver()),
- null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, null,
- UserHandle.CURRENT.getIdentifier());
- } catch (RemoteException e) {
- // This is unexpected. Nonetheless, just log the error and prevent the UI from
- // crashing
- Log.e(TAG, "Unexpected intent: " + intent
- + " when the QR code scanner button was clicked");
- }
- }
- }
-
- private void updateAffordanceColors() {
- if (mUsesBinder) {
- return;
- }
-
- int iconColor = Utils.getColorAttrDefaultColor(
- mContext,
- com.android.internal.R.attr.textColorPrimary);
- mWalletButton.getDrawable().setTint(iconColor);
- mControlsButton.getDrawable().setTint(iconColor);
- mQRCodeScannerButton.getDrawable().setTint(iconColor);
-
- ColorStateList bgColor = Utils.getColorAttr(
- mContext,
- com.android.internal.R.attr.colorSurface);
- mWalletButton.setBackgroundTintList(bgColor);
- mControlsButton.setBackgroundTintList(bgColor);
- mQRCodeScannerButton.setBackgroundTintList(bgColor);
- }
-
- private void onWalletClick(View v) {
- if (mUsesBinder) {
- return;
- }
-
- // More coming here; need to inform the user about how to proceed
- if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
- return;
- }
-
- ActivityLaunchAnimator.Controller animationController = createLaunchAnimationController(v);
- mQuickAccessWalletController.startQuickAccessUiIntent(
- mActivityStarter, animationController, mHasCard);
- }
-
- protected ActivityLaunchAnimator.Controller createLaunchAnimationController(View view) {
- return ActivityLaunchAnimator.Controller.fromView(view, null);
- }
-
- private void onControlsClick(View v) {
- if (mUsesBinder) {
- return;
- }
-
- if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
- return;
- }
-
- Intent intent = new Intent(mContext, ControlsActivity.class)
- .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK)
- .putExtra(ControlsUiController.EXTRA_ANIMATE, true);
-
- ActivityLaunchAnimator.Controller controller =
- v != null ? ActivityLaunchAnimator.Controller.fromView(v, null /* cujType */)
- : null;
- if (mControlsComponent.getVisibility() == AVAILABLE) {
- mActivityStarter.startActivity(intent, true /* dismissShade */, controller,
- true /* showOverLockscreenWhenLocked */);
- } else {
- mActivityStarter.postStartActivityDismissingKeyguard(intent, 0 /* delay */, controller);
- }
- }
-
- private class WalletCardRetriever implements
- QuickAccessWalletClient.OnWalletCardsRetrievedCallback {
-
- @Override
- public void onWalletCardsRetrieved(@NonNull GetWalletCardsResponse response) {
- mHasCard = !response.getWalletCards().isEmpty();
- Drawable tileIcon = mQuickAccessWalletController.getWalletClient().getTileIcon();
- post(() -> {
- if (tileIcon != null) {
- mWalletButton.setImageDrawable(tileIcon);
- }
- updateWalletVisibility();
- updateAffordanceColors();
- });
- }
-
- @Override
- public void onWalletCardRetrievalError(@NonNull GetWalletCardsError error) {
- mHasCard = false;
- post(() -> {
- updateWalletVisibility();
- updateAffordanceColors();
- });
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.kt
new file mode 100644
index 0000000..4897c52
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.kt
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package com.android.systemui.statusbar.phone
+
+import android.content.Context
+import android.content.res.Configuration
+import android.util.AttributeSet
+import android.view.View
+import android.view.ViewGroup
+import android.view.ViewPropertyAnimator
+import android.view.WindowInsets
+import android.widget.FrameLayout
+import com.android.systemui.R
+import com.android.systemui.keyguard.ui.binder.KeyguardBottomAreaViewBinder
+import com.android.systemui.keyguard.ui.binder.KeyguardBottomAreaViewBinder.bind
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel
+import com.android.systemui.plugins.FalsingManager
+
+/**
+ * Renders the bottom area of the lock-screen. Concerned primarily with the quick affordance UI
+ * elements. A secondary concern is the interaction of the quick affordance elements with the
+ * indication area between them, though the indication area is primarily controlled elsewhere.
+ */
+class KeyguardBottomAreaView
+@JvmOverloads
+constructor(
+ context: Context,
+ attrs: AttributeSet? = null,
+ defStyleAttr: Int = 0,
+ defStyleRes: Int = 0,
+) :
+ FrameLayout(
+ context,
+ attrs,
+ defStyleAttr,
+ defStyleRes,
+ ) {
+
+ private var ambientIndicationArea: View? = null
+ private lateinit var binding: KeyguardBottomAreaViewBinder.Binding
+
+ /** Initializes the view. */
+ fun init(
+ viewModel: KeyguardBottomAreaViewModel,
+ falsingManager: FalsingManager,
+ ) {
+ binding = bind(this, viewModel, falsingManager)
+ }
+
+ /**
+ * Initializes this instance of [KeyguardBottomAreaView] based on the given instance of another
+ * [KeyguardBottomAreaView]
+ */
+ fun initFrom(oldBottomArea: KeyguardBottomAreaView) {
+ // if it exists, continue to use the original ambient indication container
+ // instead of the newly inflated one
+ ambientIndicationArea?.let { nonNullAmbientIndicationArea ->
+ // remove old ambient indication from its parent
+ val originalAmbientIndicationView =
+ oldBottomArea.findViewById<View>(R.id.ambient_indication_container)
+ (originalAmbientIndicationView.parent as ViewGroup).removeView(
+ originalAmbientIndicationView
+ )
+
+ // remove current ambient indication from its parent (discard)
+ val ambientIndicationParent = nonNullAmbientIndicationArea.parent as ViewGroup
+ val ambientIndicationIndex =
+ ambientIndicationParent.indexOfChild(nonNullAmbientIndicationArea)
+ ambientIndicationParent.removeView(nonNullAmbientIndicationArea)
+
+ // add the old ambient indication to this view
+ ambientIndicationParent.addView(originalAmbientIndicationView, ambientIndicationIndex)
+ ambientIndicationArea = originalAmbientIndicationView
+ }
+ }
+
+ override fun onFinishInflate() {
+ super.onFinishInflate()
+ ambientIndicationArea = findViewById(R.id.ambient_indication_container)
+ }
+
+ override fun onConfigurationChanged(newConfig: Configuration) {
+ super.onConfigurationChanged(newConfig)
+ binding.onConfigurationChanged()
+ }
+
+ /** Returns a list of animators to use to animate the indication areas. */
+ val indicationAreaAnimators: List<ViewPropertyAnimator>
+ get() = binding.getIndicationAreaAnimators()
+
+ override fun hasOverlappingRendering(): Boolean {
+ return false
+ }
+
+ override fun onApplyWindowInsets(insets: WindowInsets): WindowInsets {
+ val bottom = insets.displayCutout?.safeInsetBottom ?: 0
+ if (isPaddingRelative) {
+ setPaddingRelative(paddingStart, paddingTop, paddingEnd, bottom)
+ } else {
+ setPadding(paddingLeft, paddingTop, paddingRight, bottom)
+ }
+ return insets
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 75e2c53..e106f81 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -378,11 +378,9 @@
return;
} else if (mNotificationPanelViewController.isUnlockHintRunning()) {
mBouncer.setExpansion(KeyguardBouncer.EXPANSION_HIDDEN);
- } else if (mStatusBarStateController.getState() == StatusBarState.SHADE_LOCKED
- && mKeyguardUpdateManager.isUdfpsEnrolled()) {
+ } else if (mStatusBarStateController.getState() == StatusBarState.SHADE_LOCKED) {
// Don't expand to the bouncer. Instead transition back to the lock screen (see
- // CentralSurfaces#showBouncerOrLockScreenIfKeyguard) where the user can use the UDFPS
- // affordance to enter the device (or swipe up to the input bouncer)
+ // CentralSurfaces#showBouncerOrLockScreenIfKeyguard)
return;
} else if (bouncerNeedsScrimming()) {
mBouncer.setExpansion(KeyguardBouncer.EXPANSION_VISIBLE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
index bdac888..f4d08e0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
@@ -31,6 +31,7 @@
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.keyguard.logging.KeyguardUpdateMonitorLogger;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
@@ -60,6 +61,7 @@
private final KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback =
new UpdateMonitorCallback();
private final Lazy<KeyguardUnlockAnimationController> mUnlockAnimationControllerLazy;
+ private final KeyguardUpdateMonitorLogger mLogger;
private boolean mCanDismissLockScreen;
private boolean mShowing;
@@ -107,8 +109,10 @@
KeyguardUpdateMonitor keyguardUpdateMonitor,
LockPatternUtils lockPatternUtils,
Lazy<KeyguardUnlockAnimationController> keyguardUnlockAnimationController,
+ KeyguardUpdateMonitorLogger logger,
DumpManager dumpManager) {
mContext = context;
+ mLogger = logger;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mLockPatternUtils = lockPatternUtils;
mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
@@ -245,6 +249,8 @@
mTrusted = trusted;
mTrustManaged = trustManaged;
mFaceAuthEnabled = faceAuthEnabled;
+ mLogger.logKeyguardStateUpdate(
+ mSecure, mCanDismissLockScreen, mTrusted, mTrustManaged);
notifyUnlockedChanged();
}
Trace.endSection();
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt
similarity index 64%
rename from packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
rename to packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt
index 3a0ac1b..734eeec 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.media.taptotransfer.common
+package com.android.systemui.temporarydisplay
import android.annotation.LayoutRes
import android.annotation.SuppressLint
@@ -37,30 +37,30 @@
import com.android.settingslib.Utils
import com.android.systemui.R
import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.media.taptotransfer.common.MediaTttLogger
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.util.concurrency.DelayableExecutor
-import com.android.systemui.util.view.ViewUtil
/**
- * A superclass controller that provides common functionality for showing chips on the sender device
- * and the receiver device.
+ * A generic controller that can temporarily display a new view in a new window.
*
- * Subclasses need to override and implement [updateChipView], which is where they can control what
+ * Subclasses need to override and implement [updateView], which is where they can control what
* gets displayed to the user.
*
* The generic type T is expected to contain all the information necessary for the subclasses to
- * display the chip in a certain state, since they receive <T> in [updateChipView].
+ * display the view in a certain state, since they receive <T> in [updateView].
+ *
+ * TODO(b/245610654): Remove all the media-specific logic from this class.
*/
-abstract class MediaTttChipControllerCommon<T : ChipInfoCommon>(
- internal val context: Context,
- internal val logger: MediaTttLogger,
- internal val windowManager: WindowManager,
- private val viewUtil: ViewUtil,
- @Main private val mainExecutor: DelayableExecutor,
- private val accessibilityManager: AccessibilityManager,
- private val configurationController: ConfigurationController,
- private val powerManager: PowerManager,
- @LayoutRes private val chipLayoutRes: Int,
+abstract class TemporaryViewDisplayController<T : TemporaryViewInfo>(
+ internal val context: Context,
+ internal val logger: MediaTttLogger,
+ internal val windowManager: WindowManager,
+ @Main private val mainExecutor: DelayableExecutor,
+ private val accessibilityManager: AccessibilityManager,
+ private val configurationController: ConfigurationController,
+ private val powerManager: PowerManager,
+ @LayoutRes private val viewLayoutRes: Int,
) {
/**
* Window layout params that will be used as a starting point for the [windowLayoutParams] of
@@ -85,31 +85,31 @@
*/
internal abstract val windowLayoutParams: WindowManager.LayoutParams
- /** The chip view currently being displayed. Null if the chip is not being displayed. */
- private var chipView: ViewGroup? = null
+ /** The view currently being displayed. Null if the view is not being displayed. */
+ private var view: ViewGroup? = null
- /** The chip info currently being displayed. Null if the chip is not being displayed. */
- internal var chipInfo: T? = null
+ /** The info currently being displayed. Null if the view is not being displayed. */
+ internal var info: T? = null
- /** A [Runnable] that, when run, will cancel the pending timeout of the chip. */
- private var cancelChipViewTimeout: Runnable? = null
+ /** A [Runnable] that, when run, will cancel the pending timeout of the view. */
+ private var cancelViewTimeout: Runnable? = null
/**
- * Displays the chip with the provided [newChipInfo].
+ * Displays the view with the provided [newInfo].
*
- * This method handles inflating and attaching the view, then delegates to [updateChipView] to
- * display the correct information in the chip.
+ * This method handles inflating and attaching the view, then delegates to [updateView] to
+ * display the correct information in the view.
*/
- fun displayChip(newChipInfo: T) {
- val currentChipView = chipView
+ fun displayView(newInfo: T) {
+ val currentView = view
- if (currentChipView != null) {
- updateChipView(newChipInfo, currentChipView)
+ if (currentView != null) {
+ updateView(newInfo, currentView)
} else {
- // The chip is new, so set up all our callbacks and inflate the view
+ // The view is new, so set up all our callbacks and inflate the view
configurationController.addCallback(displayScaleListener)
- // Wake the screen if necessary so the user will see the chip. (Per b/239426653, we want
- // the chip to show over the dream state, so we should only wake up if the screen is
+ // Wake the screen if necessary so the user will see the view. (Per b/239426653, we want
+ // the view to show over the dream state, so we should only wake up if the screen is
// completely off.)
if (!powerManager.isScreenOn) {
powerManager.wakeUp(
@@ -119,79 +119,79 @@
)
}
- inflateAndUpdateChip(newChipInfo)
+ inflateAndUpdateView(newInfo)
}
- // Cancel and re-set the chip timeout each time we get a new state.
+ // Cancel and re-set the view timeout each time we get a new state.
val timeout = accessibilityManager.getRecommendedTimeoutMillis(
- newChipInfo.getTimeoutMs().toInt(),
- // Not all chips have controls so FLAG_CONTENT_CONTROLS might be superfluous, but
+ newInfo.getTimeoutMs().toInt(),
+ // Not all views have controls so FLAG_CONTENT_CONTROLS might be superfluous, but
// include it just to be safe.
FLAG_CONTENT_ICONS or FLAG_CONTENT_TEXT or FLAG_CONTENT_CONTROLS
)
- cancelChipViewTimeout?.run()
- cancelChipViewTimeout = mainExecutor.executeDelayed(
- { removeChip(MediaTttRemovalReason.REASON_TIMEOUT) },
+ cancelViewTimeout?.run()
+ cancelViewTimeout = mainExecutor.executeDelayed(
+ { removeView(TemporaryDisplayRemovalReason.REASON_TIMEOUT) },
timeout.toLong()
)
}
- /** Inflates a new chip view, updates it with [newChipInfo], and adds the view to the window. */
- private fun inflateAndUpdateChip(newChipInfo: T) {
- val newChipView = LayoutInflater
+ /** Inflates a new view, updates it with [newInfo], and adds the view to the window. */
+ private fun inflateAndUpdateView(newInfo: T) {
+ val newView = LayoutInflater
.from(context)
- .inflate(chipLayoutRes, null) as ViewGroup
- chipView = newChipView
- updateChipView(newChipInfo, newChipView)
- windowManager.addView(newChipView, windowLayoutParams)
- animateChipIn(newChipView)
+ .inflate(viewLayoutRes, null) as ViewGroup
+ view = newView
+ updateView(newInfo, newView)
+ windowManager.addView(newView, windowLayoutParams)
+ animateViewIn(newView)
}
- /** Removes then re-inflates the chip. */
- private fun reinflateChip() {
- val currentChipInfo = chipInfo
- if (chipView == null || currentChipInfo == null) { return }
+ /** Removes then re-inflates the view. */
+ private fun reinflateView() {
+ val currentInfo = info
+ if (view == null || currentInfo == null) { return }
- windowManager.removeView(chipView)
- inflateAndUpdateChip(currentChipInfo)
+ windowManager.removeView(view)
+ inflateAndUpdateView(currentInfo)
}
private val displayScaleListener = object : ConfigurationController.ConfigurationListener {
override fun onDensityOrFontScaleChanged() {
- reinflateChip()
+ reinflateView()
}
}
/**
- * Hides the chip.
+ * Hides the view.
*
- * @param removalReason a short string describing why the chip was removed (timeout, state
+ * @param removalReason a short string describing why the view was removed (timeout, state
* change, etc.)
*/
- open fun removeChip(removalReason: String) {
- if (chipView == null) { return }
+ open fun removeView(removalReason: String) {
+ if (view == null) { return }
logger.logChipRemoval(removalReason)
configurationController.removeCallback(displayScaleListener)
- windowManager.removeView(chipView)
- chipView = null
- chipInfo = null
- // No need to time the chip out since it's already gone
- cancelChipViewTimeout?.run()
+ windowManager.removeView(view)
+ view = null
+ info = null
+ // No need to time the view out since it's already gone
+ cancelViewTimeout?.run()
}
/**
- * A method implemented by subclasses to update [currentChipView] based on [newChipInfo].
+ * A method implemented by subclasses to update [currentView] based on [newInfo].
*/
@CallSuper
- open fun updateChipView(newChipInfo: T, currentChipView: ViewGroup) {
- chipInfo = newChipInfo
+ open fun updateView(newInfo: T, currentView: ViewGroup) {
+ info = newInfo
}
/**
- * A method that can be implemented by subclcasses to do custom animations for when the chip
+ * A method that can be implemented by subclasses to do custom animations for when the view
* appears.
*/
- open fun animateChipIn(chipView: ViewGroup) {}
+ open fun animateViewIn(view: ViewGroup) {}
/**
* Returns the size that the icon should be, or null if no size override is needed.
@@ -209,12 +209,12 @@
* @return the content description of the icon.
*/
internal fun setIcon(
- currentChipView: ViewGroup,
+ currentView: ViewGroup,
appPackageName: String?,
appIconDrawableOverride: Drawable? = null,
appNameOverride: CharSequence? = null,
): CharSequence {
- val appIconView = currentChipView.requireViewById<CachingIconView>(R.id.app_icon)
+ val appIconView = currentView.requireViewById<CachingIconView>(R.id.app_icon)
val iconInfo = getIconInfo(appPackageName)
getIconSize(iconInfo.isAppIcon)?.let { size ->
@@ -264,9 +264,9 @@
// Used in CTS tests UpdateMediaTapToTransferSenderDisplayTest and
// UpdateMediaTapToTransferReceiverDisplayTest
private const val WINDOW_TITLE = "Media Transfer Chip View"
-private val TAG = MediaTttChipControllerCommon::class.simpleName!!
+private val TAG = TemporaryViewDisplayController::class.simpleName!!
-object MediaTttRemovalReason {
+object TemporaryDisplayRemovalReason {
const val REASON_TIMEOUT = "TIMEOUT"
const val REASON_SCREEN_TAP = "SCREEN_TAP"
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/ChipInfoCommon.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewInfo.kt
similarity index 73%
rename from packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/ChipInfoCommon.kt
rename to packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewInfo.kt
index a29c588..4fe753a 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/ChipInfoCommon.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewInfo.kt
@@ -14,17 +14,17 @@
* limitations under the License.
*/
-package com.android.systemui.media.taptotransfer.common
+package com.android.systemui.temporarydisplay
/**
- * A superclass chip state that will be subclassed by the sender chip and receiver chip.
+ * A superclass view state used with [TemporaryViewDisplayController].
*/
-interface ChipInfoCommon {
+interface TemporaryViewInfo {
/**
- * Returns the amount of time the given chip state should display on the screen before it times
+ * Returns the amount of time the given view state should display on the screen before it times
* out and disappears.
*/
- fun getTimeoutMs(): Long
+ fun getTimeoutMs(): Long = DEFAULT_TIMEOUT_MILLIS
}
const val DEFAULT_TIMEOUT_MILLIS = 10000L
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt
index 9acd21c..9a91ea91 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt
@@ -51,18 +51,19 @@
@Parameters(
name =
"feature enabled = {0}, has favorites = {1}, has service infos = {2}, can show" +
- " while locked = {3} - expected visible = {4}"
+ " while locked = {3}, visibility is AVAILABLE {4} - expected visible = {5}"
)
@JvmStatic
fun data() =
- (0 until 16)
+ (0 until 32)
.map { combination ->
arrayOf(
- /* isFeatureEnabled= */ combination and 0b1000 != 0,
- /* hasFavorites= */ combination and 0b0100 != 0,
- /* hasServiceInfos= */ combination and 0b0010 != 0,
- /* canShowWhileLocked= */ combination and 0b0001 != 0,
- /* isVisible= */ combination == 0b1111,
+ /* isFeatureEnabled= */ combination and 0b10000 != 0,
+ /* hasFavorites= */ combination and 0b01000 != 0,
+ /* hasServiceInfos= */ combination and 0b00100 != 0,
+ /* canShowWhileLocked= */ combination and 0b00010 != 0,
+ /* visibilityAvailable= */ combination and 0b00001 != 0,
+ /* isVisible= */ combination == 0b11111,
)
}
.toList()
@@ -81,7 +82,8 @@
@JvmField @Parameter(1) var hasFavorites: Boolean = false
@JvmField @Parameter(2) var hasServiceInfos: Boolean = false
@JvmField @Parameter(3) var canShowWhileLocked: Boolean = false
- @JvmField @Parameter(4) var isVisible: Boolean = false
+ @JvmField @Parameter(4) var isVisibilityAvailable: Boolean = false
+ @JvmField @Parameter(5) var isVisibleExpected: Boolean = false
@Before
fun setUp() {
@@ -93,6 +95,14 @@
.thenReturn(Optional.of(controlsListingController))
whenever(component.canShowWhileLockedSetting)
.thenReturn(MutableStateFlow(canShowWhileLocked))
+ whenever(component.getVisibility())
+ .thenReturn(
+ if (isVisibilityAvailable) {
+ ControlsComponent.Visibility.AVAILABLE
+ } else {
+ ControlsComponent.Visibility.UNAVAILABLE
+ }
+ )
underTest =
HomeControlsKeyguardQuickAffordanceConfig(
@@ -128,7 +138,7 @@
assertThat(values.last())
.isInstanceOf(
- if (isVisible) {
+ if (isVisibleExpected) {
KeyguardQuickAffordanceConfig.State.Visible::class.java
} else {
KeyguardQuickAffordanceConfig.State.Hidden::class.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt
index 059487d..dede4ec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt
@@ -69,6 +69,7 @@
val controlsController = mock<ControlsController>()
whenever(component.getControlsController()).thenReturn(Optional.of(controlsController))
whenever(component.getControlsListingController()).thenReturn(Optional.empty())
+ whenever(component.getVisibility()).thenReturn(ControlsComponent.Visibility.AVAILABLE)
whenever(controlsController.getFavorites()).thenReturn(listOf(mock()))
val values = mutableListOf<KeyguardQuickAffordanceConfig.State>()
@@ -87,6 +88,7 @@
val controlsController = mock<ControlsController>()
whenever(component.getControlsController()).thenReturn(Optional.of(controlsController))
whenever(component.getControlsListingController()).thenReturn(Optional.empty())
+ whenever(component.getVisibility()).thenReturn(ControlsComponent.Visibility.AVAILABLE)
whenever(controlsController.getFavorites()).thenReturn(listOf(mock()))
val values = mutableListOf<KeyguardQuickAffordanceConfig.State>()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt
index 171d893..e7b4593 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt
@@ -41,7 +41,6 @@
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.time.FakeSystemClock
-import com.android.systemui.util.view.ViewUtil
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
@@ -74,8 +73,6 @@
@Mock
private lateinit var windowManager: WindowManager
@Mock
- private lateinit var viewUtil: ViewUtil
- @Mock
private lateinit var commandQueue: CommandQueue
private lateinit var commandQueueCallback: CommandQueue.Callbacks
private lateinit var fakeAppIconDrawable: Drawable
@@ -102,7 +99,6 @@
context,
logger,
windowManager,
- viewUtil,
FakeExecutor(FakeSystemClock()),
accessibilityManager,
configurationController,
@@ -182,7 +178,7 @@
@Test
fun setIcon_isAppIcon_usesAppIconSize() {
- controllerReceiver.displayChip(getChipReceiverInfo())
+ controllerReceiver.displayView(getChipReceiverInfo())
val chipView = getChipView()
controllerReceiver.setIcon(chipView, PACKAGE_NAME)
@@ -198,7 +194,7 @@
@Test
fun setIcon_notAppIcon_usesGenericIconSize() {
- controllerReceiver.displayChip(getChipReceiverInfo())
+ controllerReceiver.displayView(getChipReceiverInfo())
val chipView = getChipView()
controllerReceiver.setIcon(chipView, appPackageName = null)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt
index 1061e3c..52b6eed 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt
@@ -42,7 +42,6 @@
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.time.FakeSystemClock
-import com.android.systemui.util.view.ViewUtil
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
@@ -51,8 +50,8 @@
import org.mockito.Mock
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
@SmallTest
@RunWith(AndroidTestingRunner::class)
@@ -75,8 +74,6 @@
@Mock
private lateinit var windowManager: WindowManager
@Mock
- private lateinit var viewUtil: ViewUtil
- @Mock
private lateinit var commandQueue: CommandQueue
private lateinit var commandQueueCallback: CommandQueue.Callbacks
private lateinit var fakeAppIconDrawable: Drawable
@@ -110,7 +107,6 @@
context,
logger,
windowManager,
- viewUtil,
fakeExecutor,
accessibilityManager,
configurationController,
@@ -309,7 +305,7 @@
@Test
fun almostCloseToStartCast_appIcon_deviceName_noLoadingIcon_noUndo_noFailureIcon() {
val state = almostCloseToStartCast()
- controllerSender.displayChip(state)
+ controllerSender.displayView(state)
val chipView = getChipView()
assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
@@ -325,7 +321,7 @@
@Test
fun almostCloseToEndCast_appIcon_deviceName_noLoadingIcon_noUndo_noFailureIcon() {
val state = almostCloseToEndCast()
- controllerSender.displayChip(state)
+ controllerSender.displayView(state)
val chipView = getChipView()
assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
@@ -341,7 +337,7 @@
@Test
fun transferToReceiverTriggered_appIcon_loadingIcon_noUndo_noFailureIcon() {
val state = transferToReceiverTriggered()
- controllerSender.displayChip(state)
+ controllerSender.displayView(state)
val chipView = getChipView()
assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
@@ -357,7 +353,7 @@
@Test
fun transferToThisDeviceTriggered_appIcon_loadingIcon_noUndo_noFailureIcon() {
val state = transferToThisDeviceTriggered()
- controllerSender.displayChip(state)
+ controllerSender.displayView(state)
val chipView = getChipView()
assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
@@ -373,7 +369,7 @@
@Test
fun transferToReceiverSucceeded_appIcon_deviceName_noLoadingIcon_noFailureIcon() {
val state = transferToReceiverSucceeded()
- controllerSender.displayChip(state)
+ controllerSender.displayView(state)
val chipView = getChipView()
assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
@@ -387,7 +383,7 @@
@Test
fun transferToReceiverSucceeded_nullUndoRunnable_noUndo() {
- controllerSender.displayChip(transferToReceiverSucceeded(undoCallback = null))
+ controllerSender.displayView(transferToReceiverSucceeded(undoCallback = null))
val chipView = getChipView()
assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE)
@@ -398,7 +394,7 @@
val undoCallback = object : IUndoMediaTransferCallback.Stub() {
override fun onUndoTriggered() {}
}
- controllerSender.displayChip(transferToReceiverSucceeded(undoCallback))
+ controllerSender.displayView(transferToReceiverSucceeded(undoCallback))
val chipView = getChipView()
assertThat(chipView.getUndoButton().visibility).isEqualTo(View.VISIBLE)
@@ -414,7 +410,7 @@
}
}
- controllerSender.displayChip(transferToReceiverSucceeded(undoCallback))
+ controllerSender.displayView(transferToReceiverSucceeded(undoCallback))
getChipView().getUndoButton().performClick()
assertThat(undoCallbackCalled).isTrue()
@@ -425,7 +421,7 @@
val undoCallback = object : IUndoMediaTransferCallback.Stub() {
override fun onUndoTriggered() {}
}
- controllerSender.displayChip(transferToReceiverSucceeded(undoCallback))
+ controllerSender.displayView(transferToReceiverSucceeded(undoCallback))
getChipView().getUndoButton().performClick()
@@ -440,7 +436,7 @@
@Test
fun transferToThisDeviceSucceeded_appIcon_deviceName_noLoadingIcon_noFailureIcon() {
val state = transferToThisDeviceSucceeded()
- controllerSender.displayChip(state)
+ controllerSender.displayView(state)
val chipView = getChipView()
assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
@@ -454,7 +450,7 @@
@Test
fun transferToThisDeviceSucceeded_nullUndoRunnable_noUndo() {
- controllerSender.displayChip(transferToThisDeviceSucceeded(undoCallback = null))
+ controllerSender.displayView(transferToThisDeviceSucceeded(undoCallback = null))
val chipView = getChipView()
assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE)
@@ -465,7 +461,7 @@
val undoCallback = object : IUndoMediaTransferCallback.Stub() {
override fun onUndoTriggered() {}
}
- controllerSender.displayChip(transferToThisDeviceSucceeded(undoCallback))
+ controllerSender.displayView(transferToThisDeviceSucceeded(undoCallback))
val chipView = getChipView()
assertThat(chipView.getUndoButton().visibility).isEqualTo(View.VISIBLE)
@@ -481,7 +477,7 @@
}
}
- controllerSender.displayChip(transferToThisDeviceSucceeded(undoCallback))
+ controllerSender.displayView(transferToThisDeviceSucceeded(undoCallback))
getChipView().getUndoButton().performClick()
assertThat(undoCallbackCalled).isTrue()
@@ -492,7 +488,7 @@
val undoCallback = object : IUndoMediaTransferCallback.Stub() {
override fun onUndoTriggered() {}
}
- controllerSender.displayChip(transferToThisDeviceSucceeded(undoCallback))
+ controllerSender.displayView(transferToThisDeviceSucceeded(undoCallback))
getChipView().getUndoButton().performClick()
@@ -507,7 +503,7 @@
@Test
fun transferToReceiverFailed_appIcon_noDeviceName_noLoadingIcon_noUndo_failureIcon() {
val state = transferToReceiverFailed()
- controllerSender.displayChip(state)
+ controllerSender.displayView(state)
val chipView = getChipView()
assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
@@ -523,7 +519,7 @@
@Test
fun transferToThisDeviceFailed_appIcon_noDeviceName_noLoadingIcon_noUndo_failureIcon() {
val state = transferToThisDeviceFailed()
- controllerSender.displayChip(state)
+ controllerSender.displayView(state)
val chipView = getChipView()
assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
@@ -538,24 +534,24 @@
@Test
fun changeFromAlmostCloseToStartToTransferTriggered_loadingIconAppears() {
- controllerSender.displayChip(almostCloseToStartCast())
- controllerSender.displayChip(transferToReceiverTriggered())
+ controllerSender.displayView(almostCloseToStartCast())
+ controllerSender.displayView(transferToReceiverTriggered())
assertThat(getChipView().getLoadingIconVisibility()).isEqualTo(View.VISIBLE)
}
@Test
fun changeFromTransferTriggeredToTransferSucceeded_loadingIconDisappears() {
- controllerSender.displayChip(transferToReceiverTriggered())
- controllerSender.displayChip(transferToReceiverSucceeded())
+ controllerSender.displayView(transferToReceiverTriggered())
+ controllerSender.displayView(transferToReceiverSucceeded())
assertThat(getChipView().getLoadingIconVisibility()).isEqualTo(View.GONE)
}
@Test
fun changeFromTransferTriggeredToTransferSucceeded_undoButtonAppears() {
- controllerSender.displayChip(transferToReceiverTriggered())
- controllerSender.displayChip(
+ controllerSender.displayView(transferToReceiverTriggered())
+ controllerSender.displayView(
transferToReceiverSucceeded(
object : IUndoMediaTransferCallback.Stub() {
override fun onUndoTriggered() {}
@@ -568,26 +564,26 @@
@Test
fun changeFromTransferSucceededToAlmostCloseToStart_undoButtonDisappears() {
- controllerSender.displayChip(transferToReceiverSucceeded())
- controllerSender.displayChip(almostCloseToStartCast())
+ controllerSender.displayView(transferToReceiverSucceeded())
+ controllerSender.displayView(almostCloseToStartCast())
assertThat(getChipView().getUndoButton().visibility).isEqualTo(View.GONE)
}
@Test
fun changeFromTransferTriggeredToTransferFailed_failureIconAppears() {
- controllerSender.displayChip(transferToReceiverTriggered())
- controllerSender.displayChip(transferToReceiverFailed())
+ controllerSender.displayView(transferToReceiverTriggered())
+ controllerSender.displayView(transferToReceiverFailed())
assertThat(getChipView().getFailureIcon().visibility).isEqualTo(View.VISIBLE)
}
@Test
- fun transferToReceiverTriggeredThenRemoveChip_chipStillDisplayed() {
- controllerSender.displayChip(transferToReceiverTriggered())
+ fun transferToReceiverTriggeredThenRemoveView_viewStillDisplayed() {
+ controllerSender.displayView(transferToReceiverTriggered())
fakeClock.advanceTime(1000L)
- controllerSender.removeChip("fakeRemovalReason")
+ controllerSender.removeView("fakeRemovalReason")
fakeExecutor.runAllReady()
verify(windowManager, never()).removeView(any())
@@ -596,9 +592,9 @@
@Test
fun transferToReceiverTriggeredThenFarFromReceiver_eventuallyTimesOut() {
val state = transferToReceiverTriggered()
- controllerSender.displayChip(state)
+ controllerSender.displayView(state)
fakeClock.advanceTime(1000L)
- controllerSender.removeChip("fakeRemovalReason")
+ controllerSender.removeView("fakeRemovalReason")
fakeClock.advanceTime(TIMEOUT + 1L)
@@ -606,11 +602,11 @@
}
@Test
- fun transferToThisDeviceTriggeredThenRemoveChip_chipStillDisplayed() {
- controllerSender.displayChip(transferToThisDeviceTriggered())
+ fun transferToThisDeviceTriggeredThenRemoveView_viewStillDisplayed() {
+ controllerSender.displayView(transferToThisDeviceTriggered())
fakeClock.advanceTime(1000L)
- controllerSender.removeChip("fakeRemovalReason")
+ controllerSender.removeView("fakeRemovalReason")
fakeExecutor.runAllReady()
verify(windowManager, never()).removeView(any())
@@ -619,9 +615,9 @@
@Test
fun transferToThisDeviceTriggeredThenFarFromReceiver_eventuallyTimesOut() {
val state = transferToThisDeviceTriggered()
- controllerSender.displayChip(state)
+ controllerSender.displayView(state)
fakeClock.advanceTime(1000L)
- controllerSender.removeChip("fakeRemovalReason")
+ controllerSender.removeView("fakeRemovalReason")
fakeClock.advanceTime(TIMEOUT + 1L)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
index f267013..3224a6f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
@@ -547,8 +547,6 @@
mNavigationModeController,
mFragmentService,
mContentResolver,
- mQuickAccessWalletController,
- mQrCodeScannerController,
mRecordingController,
mLargeScreenShadeHeaderController,
mScreenOffAnimationController,
@@ -556,7 +554,6 @@
mPanelExpansionStateManager,
mNotificationRemoteInputManager,
mSysUIUnfoldComponent,
- mControlsComponent,
mInteractionJankMonitor,
mQsFrameTranslateController,
mSysUiState,
@@ -569,8 +566,8 @@
mShadeTransitionController,
mSystemClock,
mock(CameraGestureHelper.class),
- () -> mKeyguardBottomAreaViewModel,
- () -> mKeyguardBottomAreaInteractor);
+ mKeyguardBottomAreaViewModel,
+ mKeyguardBottomAreaInteractor);
mNotificationPanelViewController.initDependencies(
mCentralSurfaces,
() -> {},
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt
index d2970a6..97c0bb2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt
@@ -27,6 +27,7 @@
import com.android.systemui.dock.DockManager
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.phone.CentralSurfaces
import com.android.systemui.tuner.TunerService
import com.android.systemui.tuner.TunerService.Tunable
@@ -63,6 +64,8 @@
private lateinit var tunerService: TunerService
@Mock
private lateinit var dumpManager: DumpManager
+ @Mock
+ private lateinit var statusBarStateController: StatusBarStateController
private lateinit var tunableCaptor: ArgumentCaptor<Tunable>
private lateinit var underTest: PulsingGestureListener
@@ -77,6 +80,7 @@
dockManager,
centralSurfaces,
ambientDisplayConfiguration,
+ statusBarStateController,
tunerService,
dumpManager
)
@@ -85,6 +89,8 @@
@Test
fun testGestureDetector_singleTapEnabled() {
+ whenever(statusBarStateController.isPulsing).thenReturn(true)
+
// GIVEN tap is enabled, prox not covered
whenever(ambientDisplayConfiguration.tapGestureEnabled(anyInt())).thenReturn(true)
updateSettings()
@@ -102,6 +108,8 @@
@Test
fun testGestureDetector_doubleTapEnabled() {
+ whenever(statusBarStateController.isPulsing).thenReturn(true)
+
// GIVEN double tap is enabled, prox not covered
whenever(ambientDisplayConfiguration.doubleTapGestureEnabled(anyInt())).thenReturn(true)
updateSettings()
@@ -119,6 +127,8 @@
@Test
fun testGestureDetector_singleTapEnabled_falsing() {
+ whenever(statusBarStateController.isPulsing).thenReturn(true)
+
// GIVEN tap is enabled, prox not covered
whenever(ambientDisplayConfiguration.tapGestureEnabled(anyInt())).thenReturn(true)
updateSettings()
@@ -135,7 +145,23 @@
}
@Test
+ fun testGestureDetector_notPulsing_noFalsingCheck() {
+ whenever(statusBarStateController.isPulsing).thenReturn(false)
+
+ // GIVEN tap is enabled, prox not covered
+ whenever(ambientDisplayConfiguration.tapGestureEnabled(anyInt())).thenReturn(true)
+ // WHEN there's a tap
+ underTest.onSingleTapConfirmed(downEv)
+
+ // THEN the falsing manager never gets a call (because the device wasn't pulsing
+ // during the tap)
+ verify(falsingManager, never()).isFalseTap(anyInt())
+ }
+
+ @Test
fun testGestureDetector_doubleTapEnabled_falsing() {
+ whenever(statusBarStateController.isPulsing).thenReturn(true)
+
// GIVEN double tap is enabled, prox not covered
whenever(ambientDisplayConfiguration.doubleTapGestureEnabled(anyInt())).thenReturn(true)
updateSettings()
@@ -153,6 +179,8 @@
@Test
fun testGestureDetector_singleTapEnabled_proxCovered() {
+ whenever(statusBarStateController.isPulsing).thenReturn(true)
+
// GIVEN tap is enabled, not a false tap based on classifiers
whenever(ambientDisplayConfiguration.tapGestureEnabled(anyInt())).thenReturn(true)
updateSettings()
@@ -170,6 +198,8 @@
@Test
fun testGestureDetector_doubleTapEnabled_proxCovered() {
+ whenever(statusBarStateController.isPulsing).thenReturn(true)
+
// GIVEN double tap is enabled, not a false tap based on classifiers
whenever(ambientDisplayConfiguration.doubleTapGestureEnabled(anyInt())).thenReturn(true)
updateSettings()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
index 8e95a8e..74e2747 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -1053,14 +1053,14 @@
}
@Test
- public void onTrustGrantedMessageDoesShowsOnTrustGranted() {
+ public void onTrustGrantedMessageShowsOnTrustGranted() {
createController();
mController.setVisible(true);
// GIVEN trust is granted
when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(true);
- // WHEN the showTrustGranted message is called
+ // WHEN the showTrustGranted method is called
final String trustGrantedMsg = "testing trust granted message";
mController.getKeyguardCallback().showTrustGrantedMessage(trustGrantedMsg);
@@ -1071,6 +1071,38 @@
}
@Test
+ public void onTrustGrantedMessage_nullMessage_showsDefaultMessage() {
+ createController();
+ mController.setVisible(true);
+
+ // GIVEN trust is granted
+ when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(true);
+
+ // WHEN the showTrustGranted method is called with a null message
+ mController.getKeyguardCallback().showTrustGrantedMessage(null);
+
+ // THEN verify the default trust granted message shows
+ verifyIndicationMessage(
+ INDICATION_TYPE_TRUST,
+ getContext().getString(R.string.keyguard_indication_trust_unlocked));
+ }
+
+ @Test
+ public void onTrustGrantedMessage_emptyString_showsNoMessage() {
+ createController();
+ mController.setVisible(true);
+
+ // GIVEN trust is granted
+ when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(true);
+
+ // WHEN the showTrustGranted method is called with an EMPTY string
+ mController.getKeyguardCallback().showTrustGrantedMessage("");
+
+ // THEN verify NO trust message is shown
+ verifyNoMessage(INDICATION_TYPE_TRUST);
+ }
+
+ @Test
public void coEx_faceSuccess_showsPressToOpen() {
// GIVEN bouncer isn't showing, can skip bouncer, udfps is supported, no a11y enabled
when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaTest.kt
deleted file mode 100644
index 3440fa5..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaTest.kt
+++ /dev/null
@@ -1,54 +0,0 @@
-package com.android.systemui.statusbar.phone
-
-import android.testing.AndroidTestingRunner
-import android.testing.TestableLooper
-import android.view.LayoutInflater
-import androidx.test.filters.SmallTest
-import com.android.systemui.R
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.assist.AssistManager
-import com.android.systemui.plugins.ActivityStarter
-import com.android.systemui.statusbar.policy.AccessibilityController
-import com.android.systemui.statusbar.policy.FlashlightController
-import com.android.systemui.statusbar.policy.KeyguardStateController
-import com.android.systemui.tuner.TunerService
-import java.util.concurrent.Executor
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.MockitoAnnotations
-
-@SmallTest
-@RunWith(AndroidTestingRunner::class)
-@TestableLooper.RunWithLooper(setAsMainLooper = true)
-class KeyguardBottomAreaTest : SysuiTestCase() {
-
- @Mock
- private lateinit var mCentralSurfaces: CentralSurfaces
- private lateinit var mKeyguardBottomArea: KeyguardBottomAreaView
-
- @Before
- fun setup() {
- MockitoAnnotations.initMocks(this)
- // Mocked dependencies
- mDependency.injectMockDependency(AccessibilityController::class.java)
- mDependency.injectMockDependency(ActivityStarter::class.java)
- mDependency.injectMockDependency(AssistManager::class.java)
- mDependency.injectTestDependency(Executor::class.java, Executor { it.run() })
- mDependency.injectMockDependency(FlashlightController::class.java)
- mDependency.injectMockDependency(KeyguardStateController::class.java)
- mDependency.injectMockDependency(TunerService::class.java)
-
- mKeyguardBottomArea = LayoutInflater.from(mContext).inflate(
- R.layout.keyguard_bottom_area, null, false) as KeyguardBottomAreaView
- }
-
- @Test
- fun initFrom_doesntCrash() {
- val other = LayoutInflater.from(mContext).inflate(R.layout.keyguard_bottom_area,
- null, false) as KeyguardBottomAreaView
-
- other.initFrom(mKeyguardBottomArea)
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index 2dcdcfc..e790d85 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -51,6 +51,7 @@
import com.android.systemui.shade.ShadeController;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationShadeWindowController;
+import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.phone.panelstate.PanelExpansionChangeEvent;
import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
@@ -277,6 +278,17 @@
}
@Test
+ public void onPanelExpansionChanged_neverTranslatesBouncerWhenShadeLocked() {
+ when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE_LOCKED);
+ mStatusBarKeyguardViewManager.onPanelExpansionChanged(
+ expansionEvent(
+ /* fraction= */ KeyguardBouncer.EXPANSION_VISIBLE,
+ /* expanded= */ true,
+ /* tracking= */ false));
+ verify(mBouncer, never()).setExpansion(anyFloat());
+ }
+
+ @Test
public void setOccluded_animatesPanelExpansion_onlyIfBouncerHidden() {
mStatusBarKeyguardViewManager.setOccluded(false /* occluded */, true /* animated */);
verify(mCentralSurfaces).animateKeyguardUnoccluding();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java
index 4a8170f..8f363ef 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java
@@ -31,6 +31,7 @@
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.logging.KeyguardUpdateMonitorLogger;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
@@ -57,6 +58,8 @@
private DumpManager mDumpManager;
@Mock
private Lazy<KeyguardUnlockAnimationController> mKeyguardUnlockAnimationControllerLazy;
+ @Mock
+ private KeyguardUpdateMonitorLogger mLogger;
@Before
public void setup() {
@@ -66,6 +69,7 @@
mKeyguardUpdateMonitor,
mLockPatternUtils,
mKeyguardUnlockAnimationControllerLazy,
+ mLogger,
mDumpManager);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt
similarity index 61%
rename from packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt
index f133068..e616c26 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.media.taptotransfer.common
+package com.android.systemui.temporarydisplay
import android.content.Context
import android.content.pm.ApplicationInfo
@@ -30,6 +30,7 @@
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.media.taptotransfer.common.MediaTttLogger
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener
import com.android.systemui.util.concurrency.DelayableExecutor
@@ -38,7 +39,6 @@
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.capture
import com.android.systemui.util.time.FakeSystemClock
-import com.android.systemui.util.view.ViewUtil
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
@@ -52,8 +52,8 @@
import org.mockito.MockitoAnnotations
@SmallTest
-class MediaTttChipControllerCommonTest : SysuiTestCase() {
- private lateinit var controllerCommon: TestControllerCommon
+class TemporaryViewDisplayControllerTest : SysuiTestCase() {
+ private lateinit var underTest: TestController
private lateinit var fakeClock: FakeSystemClock
private lateinit var fakeExecutor: FakeExecutor
@@ -72,8 +72,6 @@
@Mock
private lateinit var windowManager: WindowManager
@Mock
- private lateinit var viewUtil: ViewUtil
- @Mock
private lateinit var powerManager: PowerManager
@Before
@@ -97,11 +95,10 @@
fakeClock = FakeSystemClock()
fakeExecutor = FakeExecutor(fakeClock)
- controllerCommon = TestControllerCommon(
+ underTest = TestController(
context,
logger,
windowManager,
- viewUtil,
fakeExecutor,
accessibilityManager,
configurationController,
@@ -110,43 +107,43 @@
}
@Test
- fun displayChip_chipAdded() {
- controllerCommon.displayChip(getState())
+ fun displayView_viewAdded() {
+ underTest.displayView(getState())
verify(windowManager).addView(any(), any())
}
@Test
- fun displayChip_screenOff_screenWakes() {
+ fun displayView_screenOff_screenWakes() {
whenever(powerManager.isScreenOn).thenReturn(false)
- controllerCommon.displayChip(getState())
+ underTest.displayView(getState())
verify(powerManager).wakeUp(any(), any(), any())
}
@Test
- fun displayChip_screenAlreadyOn_screenNotWoken() {
+ fun displayView_screenAlreadyOn_screenNotWoken() {
whenever(powerManager.isScreenOn).thenReturn(true)
- controllerCommon.displayChip(getState())
+ underTest.displayView(getState())
verify(powerManager, never()).wakeUp(any(), any(), any())
}
@Test
- fun displayChip_twice_chipNotAddedTwice() {
- controllerCommon.displayChip(getState())
+ fun displayView_twice_viewNotAddedTwice() {
+ underTest.displayView(getState())
reset(windowManager)
- controllerCommon.displayChip(getState())
+ underTest.displayView(getState())
verify(windowManager, never()).addView(any(), any())
}
@Test
- fun displayChip_chipDoesNotDisappearsBeforeTimeout() {
+ fun displayView_viewDoesNotDisappearsBeforeTimeout() {
val state = getState()
- controllerCommon.displayChip(state)
+ underTest.displayView(state)
reset(windowManager)
fakeClock.advanceTime(TIMEOUT_MS - 1)
@@ -155,9 +152,9 @@
}
@Test
- fun displayChip_chipDisappearsAfterTimeout() {
+ fun displayView_viewDisappearsAfterTimeout() {
val state = getState()
- controllerCommon.displayChip(state)
+ underTest.displayView(state)
reset(windowManager)
fakeClock.advanceTime(TIMEOUT_MS + 1)
@@ -166,176 +163,176 @@
}
@Test
- fun displayChip_calledAgainBeforeTimeout_timeoutReset() {
- // First, display the chip
+ fun displayView_calledAgainBeforeTimeout_timeoutReset() {
+ // First, display the view
val state = getState()
- controllerCommon.displayChip(state)
+ underTest.displayView(state)
- // After some time, re-display the chip
+ // After some time, re-display the view
val waitTime = 1000L
fakeClock.advanceTime(waitTime)
- controllerCommon.displayChip(getState())
+ underTest.displayView(getState())
// Wait until the timeout for the first display would've happened
fakeClock.advanceTime(TIMEOUT_MS - waitTime + 1)
- // Verify we didn't hide the chip
+ // Verify we didn't hide the view
verify(windowManager, never()).removeView(any())
}
@Test
- fun displayChip_calledAgainBeforeTimeout_eventuallyTimesOut() {
- // First, display the chip
+ fun displayView_calledAgainBeforeTimeout_eventuallyTimesOut() {
+ // First, display the view
val state = getState()
- controllerCommon.displayChip(state)
+ underTest.displayView(state)
- // After some time, re-display the chip
+ // After some time, re-display the view
fakeClock.advanceTime(1000L)
- controllerCommon.displayChip(getState())
+ underTest.displayView(getState())
- // Ensure we still hide the chip eventually
+ // Ensure we still hide the view eventually
fakeClock.advanceTime(TIMEOUT_MS + 1)
verify(windowManager).removeView(any())
}
@Test
- fun displayScaleChange_chipReinflatedWithMostRecentState() {
- controllerCommon.displayChip(getState(name = "First name"))
- controllerCommon.displayChip(getState(name = "Second name"))
+ fun displayScaleChange_viewReinflatedWithMostRecentState() {
+ underTest.displayView(getState(name = "First name"))
+ underTest.displayView(getState(name = "Second name"))
reset(windowManager)
getConfigurationListener().onDensityOrFontScaleChanged()
verify(windowManager).removeView(any())
verify(windowManager).addView(any(), any())
- assertThat(controllerCommon.mostRecentChipInfo?.name).isEqualTo("Second name")
+ assertThat(underTest.mostRecentViewInfo?.name).isEqualTo("Second name")
}
@Test
- fun removeChip_chipRemovedAndRemovalLogged() {
- // First, add the chip
- controllerCommon.displayChip(getState())
+ fun removeView_viewRemovedAndRemovalLogged() {
+ // First, add the view
+ underTest.displayView(getState())
// Then, remove it
val reason = "test reason"
- controllerCommon.removeChip(reason)
+ underTest.removeView(reason)
verify(windowManager).removeView(any())
verify(logger).logChipRemoval(reason)
}
@Test
- fun removeChip_noAdd_viewNotRemoved() {
- controllerCommon.removeChip("reason")
+ fun removeView_noAdd_viewNotRemoved() {
+ underTest.removeView("reason")
verify(windowManager, never()).removeView(any())
}
@Test
fun setIcon_nullAppIconDrawableAndNullPackageName_stillHasIcon() {
- controllerCommon.displayChip(getState())
- val chipView = getChipView()
+ underTest.displayView(getState())
+ val view = getView()
- controllerCommon.setIcon(chipView, appPackageName = null, appIconDrawableOverride = null)
+ underTest.setIcon(view, appPackageName = null, appIconDrawableOverride = null)
- assertThat(chipView.getAppIconView().drawable).isNotNull()
+ assertThat(view.getAppIconView().drawable).isNotNull()
}
@Test
fun setIcon_nullAppIconDrawableAndInvalidPackageName_stillHasIcon() {
- controllerCommon.displayChip(getState())
- val chipView = getChipView()
+ underTest.displayView(getState())
+ val view = getView()
- controllerCommon.setIcon(
- chipView, appPackageName = "fakePackageName", appIconDrawableOverride = null
+ underTest.setIcon(
+ view, appPackageName = "fakePackageName", appIconDrawableOverride = null
)
- assertThat(chipView.getAppIconView().drawable).isNotNull()
+ assertThat(view.getAppIconView().drawable).isNotNull()
}
@Test
fun setIcon_nullAppIconDrawable_iconIsFromPackageName() {
- controllerCommon.displayChip(getState())
- val chipView = getChipView()
+ underTest.displayView(getState())
+ val view = getView()
- controllerCommon.setIcon(chipView, PACKAGE_NAME, appIconDrawableOverride = null, null)
+ underTest.setIcon(view, PACKAGE_NAME, appIconDrawableOverride = null, null)
- assertThat(chipView.getAppIconView().drawable).isEqualTo(appIconFromPackageName)
+ assertThat(view.getAppIconView().drawable).isEqualTo(appIconFromPackageName)
}
@Test
fun setIcon_hasAppIconDrawable_iconIsDrawable() {
- controllerCommon.displayChip(getState())
- val chipView = getChipView()
+ underTest.displayView(getState())
+ val view = getView()
val drawable = context.getDrawable(R.drawable.ic_alarm)!!
- controllerCommon.setIcon(chipView, PACKAGE_NAME, drawable, null)
+ underTest.setIcon(view, PACKAGE_NAME, drawable, null)
- assertThat(chipView.getAppIconView().drawable).isEqualTo(drawable)
+ assertThat(view.getAppIconView().drawable).isEqualTo(drawable)
}
@Test
fun setIcon_nullAppNameAndNullPackageName_stillHasContentDescription() {
- controllerCommon.displayChip(getState())
- val chipView = getChipView()
+ underTest.displayView(getState())
+ val view = getView()
- controllerCommon.setIcon(chipView, appPackageName = null, appNameOverride = null)
+ underTest.setIcon(view, appPackageName = null, appNameOverride = null)
- assertThat(chipView.getAppIconView().contentDescription.toString()).isNotEmpty()
+ assertThat(view.getAppIconView().contentDescription.toString()).isNotEmpty()
}
@Test
fun setIcon_nullAppNameAndInvalidPackageName_stillHasContentDescription() {
- controllerCommon.displayChip(getState())
- val chipView = getChipView()
+ underTest.displayView(getState())
+ val view = getView()
- controllerCommon.setIcon(
- chipView, appPackageName = "fakePackageName", appNameOverride = null
+ underTest.setIcon(
+ view, appPackageName = "fakePackageName", appNameOverride = null
)
- assertThat(chipView.getAppIconView().contentDescription.toString()).isNotEmpty()
+ assertThat(view.getAppIconView().contentDescription.toString()).isNotEmpty()
}
@Test
fun setIcon_nullAppName_iconContentDescriptionIsFromPackageName() {
- controllerCommon.displayChip(getState())
- val chipView = getChipView()
+ underTest.displayView(getState())
+ val view = getView()
- controllerCommon.setIcon(chipView, PACKAGE_NAME, null, appNameOverride = null)
+ underTest.setIcon(view, PACKAGE_NAME, null, appNameOverride = null)
- assertThat(chipView.getAppIconView().contentDescription).isEqualTo(APP_NAME)
+ assertThat(view.getAppIconView().contentDescription).isEqualTo(APP_NAME)
}
@Test
fun setIcon_hasAppName_iconContentDescriptionIsAppNameOverride() {
- controllerCommon.displayChip(getState())
- val chipView = getChipView()
+ underTest.displayView(getState())
+ val view = getView()
val appName = "Override App Name"
- controllerCommon.setIcon(chipView, PACKAGE_NAME, null, appName)
+ underTest.setIcon(view, PACKAGE_NAME, null, appName)
- assertThat(chipView.getAppIconView().contentDescription).isEqualTo(appName)
+ assertThat(view.getAppIconView().contentDescription).isEqualTo(appName)
}
@Test
fun setIcon_iconSizeMatchesGetIconSize() {
- controllerCommon.displayChip(getState())
- val chipView = getChipView()
+ underTest.displayView(getState())
+ val view = getView()
- controllerCommon.setIcon(chipView, PACKAGE_NAME)
- chipView.measure(
+ underTest.setIcon(view, PACKAGE_NAME)
+ view.measure(
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
)
- assertThat(chipView.getAppIconView().measuredWidth).isEqualTo(ICON_SIZE)
- assertThat(chipView.getAppIconView().measuredHeight).isEqualTo(ICON_SIZE)
+ assertThat(view.getAppIconView().measuredWidth).isEqualTo(ICON_SIZE)
+ assertThat(view.getAppIconView().measuredHeight).isEqualTo(ICON_SIZE)
}
- private fun getState(name: String = "name") = ChipInfo(name)
+ private fun getState(name: String = "name") = ViewInfo(name)
- private fun getChipView(): ViewGroup {
+ private fun getView(): ViewGroup {
val viewCaptor = ArgumentCaptor.forClass(View::class.java)
verify(windowManager).addView(viewCaptor.capture(), any())
return viewCaptor.value as ViewGroup
@@ -349,37 +346,35 @@
return callbackCaptor.value
}
- inner class TestControllerCommon(
+ inner class TestController(
context: Context,
logger: MediaTttLogger,
windowManager: WindowManager,
- viewUtil: ViewUtil,
@Main mainExecutor: DelayableExecutor,
accessibilityManager: AccessibilityManager,
configurationController: ConfigurationController,
powerManager: PowerManager,
- ) : MediaTttChipControllerCommon<ChipInfo>(
+ ) : TemporaryViewDisplayController<ViewInfo>(
context,
logger,
windowManager,
- viewUtil,
mainExecutor,
accessibilityManager,
configurationController,
powerManager,
R.layout.media_ttt_chip,
) {
- var mostRecentChipInfo: ChipInfo? = null
+ var mostRecentViewInfo: ViewInfo? = null
override val windowLayoutParams = commonWindowLayoutParams
- override fun updateChipView(newChipInfo: ChipInfo, currentChipView: ViewGroup) {
- super.updateChipView(newChipInfo, currentChipView)
- mostRecentChipInfo = newChipInfo
+ override fun updateView(newInfo: ViewInfo, currentView: ViewGroup) {
+ super.updateView(newInfo, currentView)
+ mostRecentViewInfo = newInfo
}
override fun getIconSize(isAppIcon: Boolean): Int = ICON_SIZE
}
- inner class ChipInfo(val name: String) : ChipInfoCommon {
+ inner class ViewInfo(val name: String) : TemporaryViewInfo {
override fun getTimeoutMs() = 1L
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
similarity index 99%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
rename to packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
index 11eb4e3..42b434a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
@@ -12,6 +12,7 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
+ *
*/
package com.android.systemui.keyguard.data.repository
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/data/repository/FakePowerRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/power/data/repository/FakePowerRepository.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/power/data/repository/FakePowerRepository.kt
rename to packages/SystemUI/tests/utils/src/com/android/systemui/power/data/repository/FakePowerRepository.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/FakeUserRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/user/data/repository/FakeUserRepository.kt
rename to packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt
diff --git a/services/core/java/com/android/server/IntentResolver.java b/services/core/java/com/android/server/IntentResolver.java
index c375c73..a1adc6f4 100644
--- a/services/core/java/com/android/server/IntentResolver.java
+++ b/services/core/java/com/android/server/IntentResolver.java
@@ -35,7 +35,6 @@
import com.android.internal.util.FastPrintWriter;
import com.android.server.pm.Computer;
-import com.android.server.pm.pkg.PackageStateInternal;
import com.android.server.pm.snapshot.PackageDataSnapshot;
import java.io.PrintWriter;
@@ -566,7 +565,7 @@
* "stopped", that is whether it should not be included in the result
* if the intent requests to excluded stopped objects.
*/
- protected boolean isFilterStopped(PackageStateInternal packageState, @UserIdInt int userId) {
+ protected boolean isFilterStopped(@NonNull Computer computer, F filter, @UserIdInt int userId) {
return false;
}
@@ -805,8 +804,7 @@
int match;
if (debug) Slog.v(TAG, "Matching against filter " + filter);
- if (excludingStopped && isFilterStopped(computer.getPackageStateInternal(packageName),
- userId)) {
+ if (excludingStopped && isFilterStopped(computer, filter, userId)) {
if (debug) {
Slog.v(TAG, " Filter's target is stopped; skipping");
}
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 80dd266..dbe80c8 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -2534,7 +2534,7 @@
capability |= capabilityFromFGS;
}
- capability |= getDefaultCapability(psr, procState);
+ capability |= getDefaultCapability(app, procState);
// Do final modification to adj. Everything we do between here and applying
// the final setAdj must be done in this function, because we will also use
@@ -2556,7 +2556,7 @@
|| state.getCurCapability() != prevCapability;
}
- private int getDefaultCapability(ProcessServiceRecord psr, int procState) {
+ private int getDefaultCapability(ProcessRecord app, int procState) {
switch (procState) {
case PROCESS_STATE_PERSISTENT:
case PROCESS_STATE_PERSISTENT_UI:
@@ -2565,15 +2565,13 @@
case PROCESS_STATE_BOUND_TOP:
return PROCESS_CAPABILITY_NETWORK;
case PROCESS_STATE_FOREGROUND_SERVICE:
- if (psr.hasForegroundServices()) {
- // Capability from FGS are conditional depending on foreground service type in
- // manifest file and the mAllowWhileInUsePermissionInFgs flag.
- return PROCESS_CAPABILITY_NETWORK;
+ if (app.getActiveInstrumentation() != null) {
+ return PROCESS_CAPABILITY_ALL_IMPLICIT | PROCESS_CAPABILITY_NETWORK ;
} else {
- // process has no FGS, the PROCESS_STATE_FOREGROUND_SERVICE is from client.
- // the implicit capability could be removed in the future, client should use
- // BIND_INCLUDE_CAPABILITY flag.
- return PROCESS_CAPABILITY_ALL_IMPLICIT | PROCESS_CAPABILITY_NETWORK;
+ // Capability from foreground service is conditional depending on
+ // foregroundServiceType in the manifest file and the
+ // mAllowWhileInUsePermissionInFgs flag.
+ return PROCESS_CAPABILITY_NETWORK;
}
case PROCESS_STATE_BOUND_FOREGROUND_SERVICE:
return PROCESS_CAPABILITY_NETWORK;
diff --git a/services/core/java/com/android/server/app/TEST_MAPPING b/services/core/java/com/android/server/app/TEST_MAPPING
new file mode 100644
index 0000000..0ba4d8c
--- /dev/null
+++ b/services/core/java/com/android/server/app/TEST_MAPPING
@@ -0,0 +1,23 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsGameManagerTestCases",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ },
+ {
+ "name": "FrameworksMockingServicesTests",
+ "options": [
+ {
+ "include-filter": "com.android.server.app"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricServiceRegistry.java b/services/core/java/com/android/server/biometrics/sensors/BiometricServiceRegistry.java
index 4779f6f..6a2731d 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricServiceRegistry.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricServiceRegistry.java
@@ -216,19 +216,31 @@
return null;
}
- if (mAllProps.size() > 1) {
- Slog.e(TAG, "getSingleProvider() called but multiple sensors present: "
- + mAllProps.size());
- }
+ // TODO(b/242837110): remove the try-catch once the bug is fixed.
+ try {
+ if (mAllProps.size() > 1) {
+ Slog.e(TAG, "getSingleProvider() called but multiple sensors present: "
+ + mAllProps.size());
+ }
- final int sensorId = mAllProps.get(0).sensorId;
- final T provider = getProviderForSensor(sensorId);
- if (provider != null) {
- return new Pair<>(sensorId, provider);
- }
+ final int sensorId = mAllProps.get(0).sensorId;
+ final T provider = getProviderForSensor(sensorId);
+ if (provider != null) {
+ return new Pair<>(sensorId, provider);
+ }
- Slog.e(TAG, "Single sensor: " + sensorId + ", but provider not found");
- return null;
+ Slog.e(TAG, "Single sensor: " + sensorId + ", but provider not found");
+ return null;
+ } catch (NullPointerException e) {
+ final String extra;
+ if (mAllProps == null) {
+ extra = "mAllProps: null";
+ } else {
+ extra = "mAllProps.size(): " + mAllProps.size();
+ }
+ Slog.e(TAG, "This shouldn't happen. " + extra, e);
+ throw e;
+ }
}
/**
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index 9db9837..8024d41 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -23,7 +23,6 @@
import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE;
import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION;
import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION_GROUP;
-import static android.content.pm.PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
@@ -1420,9 +1419,7 @@
}
if (!isApex) {
- if (!doRenameLI(args, res.mReturnCode, parsedPackage)) {
- throw new PrepareFailure(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename");
- }
+ doRenameLI(args, res.mReturnCode, res.mReturnMsg, parsedPackage);
try {
setUpFsVerityIfPossible(parsedPackage);
@@ -1689,19 +1686,20 @@
* scanned package should be updated to reflect the rename.
*/
@GuardedBy("mPm.mInstallLock")
- private boolean doRenameLI(InstallArgs args, int status, ParsedPackage parsedPackage) {
+ private void doRenameLI(InstallArgs args, int status, String statusMsg,
+ ParsedPackage parsedPackage) throws PrepareFailure {
if (args.mMoveInfo != null) {
if (status != PackageManager.INSTALL_SUCCEEDED) {
mRemovePackageHelper.cleanUpForMoveInstall(args.mMoveInfo.mToUuid,
args.mMoveInfo.mPackageName, args.mMoveInfo.mFromCodePath);
- return false;
+ throw new PrepareFailure(status, statusMsg);
}
- return true;
+ return;
}
// For file installations
if (status != PackageManager.INSTALL_SUCCEEDED) {
mRemovePackageHelper.removeCodePath(args.mCodeFile);
- return false;
+ throw new PrepareFailure(status, statusMsg);
}
final File targetDir = resolveTargetDir(args);
@@ -1723,12 +1721,14 @@
}
} catch (IOException | ErrnoException e) {
Slog.w(TAG, "Failed to rename", e);
- return false;
+ throw new PrepareFailure(PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE,
+ "Failed to rename");
}
if (!onIncremental && !SELinux.restoreconRecursive(afterCodeFile)) {
Slog.w(TAG, "Failed to restorecon");
- return false;
+ throw new PrepareFailure(PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE,
+ "Failed to restorecon");
}
// Reflect the rename internally
@@ -1739,14 +1739,13 @@
parsedPackage.setPath(afterCodeFile.getCanonicalPath());
} catch (IOException e) {
Slog.e(TAG, "Failed to get path: " + afterCodeFile, e);
- return false;
+ throw new PrepareFailure(PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE,
+ "Failed to get path: " + afterCodeFile);
}
parsedPackage.setBaseApkPath(FileUtils.rewriteAfterRename(beforeCodeFile,
afterCodeFile, parsedPackage.getBaseApkPath()));
parsedPackage.setSplitCodePaths(FileUtils.rewriteAfterRename(beforeCodeFile,
afterCodeFile, parsedPackage.getSplitCodePaths()));
-
- return true;
}
// TODO(b/168126411): Once staged install flow starts using the same folder as non-staged
diff --git a/services/core/java/com/android/server/pm/UserManagerInternal.java b/services/core/java/com/android/server/pm/UserManagerInternal.java
index a1d5054..6265584 100644
--- a/services/core/java/com/android/server/pm/UserManagerInternal.java
+++ b/services/core/java/com/android/server/pm/UserManagerInternal.java
@@ -318,6 +318,10 @@
*
* <p>On most devices this call will be a no-op, but it will be used on devices that support
* multiple users on multiple displays (like automotives with passenger displays).
+ *
+ * <p><b>NOTE: </b>this method is meant to be used only by {@code UserController} when a user is
+ * started and it doesn't validate if the display exists.
+ *
*/
public abstract void assignUserToDisplay(@UserIdInt int userId, int displayId);
@@ -326,6 +330,9 @@
*
* <p>On most devices this call will be a no-op, but it will be used on devices that support
* multiple users on multiple displays (like automotives with passenger displays).
+ *
+ * <p><b>NOTE: </b>this method is meant to be used only by {@code UserController} when a user is
+ * stopped.
*/
public abstract void unassignUserFromDisplay(@UserIdInt int userId);
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 4bcda2c..1e30757 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -630,7 +630,7 @@
/**
* Set on on devices that support background users (key) running on secondary displays (value).
*/
- // TODO(b/239982558): move such logic to a different class (like UserDisplayAssigner)
+ // TODO(b/244644281): move such logic to a different class (like UserDisplayAssigner)
@Nullable
@GuardedBy("mUsersOnSecondaryDisplays")
private final SparseIntArray mUsersOnSecondaryDisplays;
@@ -710,7 +710,8 @@
@VisibleForTesting
UserManagerService(Context context) {
this(context, /* pm= */ null, /* userDataPreparer= */ null,
- /* packagesLock= */ new Object(), context.getCacheDir(), /* users= */ null);
+ /* packagesLock= */ new Object(), context.getCacheDir(), /* users= */ null,
+ /* usersOnSecondaryDisplays= */ null);
}
/**
@@ -721,13 +722,13 @@
UserManagerService(Context context, PackageManagerService pm, UserDataPreparer userDataPreparer,
Object packagesLock) {
this(context, pm, userDataPreparer, packagesLock, Environment.getDataDirectory(),
- /* users= */ null);
+ /* users= */ null, /* usersOnSecondaryDisplays= */ null);
}
@VisibleForTesting
UserManagerService(Context context, PackageManagerService pm,
UserDataPreparer userDataPreparer, Object packagesLock, File dataDir,
- SparseArray<UserData> users) {
+ SparseArray<UserData> users, @Nullable SparseIntArray usersOnSecondaryDisplays) {
mContext = context;
mPm = pm;
mPackagesLock = packagesLock;
@@ -758,7 +759,13 @@
mUser0Allocations = DBG_ALLOCATION ? new AtomicInteger() : null;
emulateSystemUserModeIfNeeded();
mUsersOnSecondaryDisplaysEnabled = UserManager.isUsersOnSecondaryDisplaysEnabled();
- mUsersOnSecondaryDisplays = mUsersOnSecondaryDisplaysEnabled ? new SparseIntArray() : null;
+ if (mUsersOnSecondaryDisplaysEnabled) {
+ mUsersOnSecondaryDisplays = usersOnSecondaryDisplays == null
+ ? new SparseIntArray() // default behavior
+ : usersOnSecondaryDisplays; // passed by unit test
+ } else {
+ mUsersOnSecondaryDisplays = null;
+ }
}
void systemReady() {
@@ -1720,6 +1727,11 @@
return userId == getCurrentUserId();
}
+ @VisibleForTesting
+ boolean isUsersOnSecondaryDisplaysEnabled() {
+ return mUsersOnSecondaryDisplaysEnabled;
+ }
+
@Override
public boolean isUserVisible(@UserIdInt int userId) {
int callingUserId = UserHandle.getCallingUserId();
@@ -1733,7 +1745,8 @@
return isUserVisibleUnchecked(userId);
}
- private boolean isUserVisibleUnchecked(@UserIdInt int userId) {
+ @VisibleForTesting
+ boolean isUserVisibleUnchecked(@UserIdInt int userId) {
// First check current foreground user and their profiles (on main display)
if (isCurrentUserOrRunningProfileOfCurrentUser(userId)) {
return true;
@@ -1750,8 +1763,8 @@
}
}
- // TODO(b/239982558): add unit test
- private int getDisplayAssignedToUser(@UserIdInt int userId) {
+ @VisibleForTesting
+ int getDisplayAssignedToUser(@UserIdInt int userId) {
if (isCurrentUserOrRunningProfileOfCurrentUser(userId)) {
return Display.DEFAULT_DISPLAY;
}
@@ -6719,10 +6732,24 @@
+ "users on multiple displays");
}
- Preconditions.checkArgument(userId != UserHandle.USER_SYSTEM, "Cannot start system user"
- + " on secondary display (%d)", displayId);
- // TODO(b/239982558): call DisplayManagerInternal to check if display is valid instead
- Preconditions.checkArgument(displayId > 0, "Invalid display id (%d)", displayId);
+ Preconditions.checkArgument(userId != UserHandle.USER_SYSTEM, "Cannot assign system "
+ + "user to secondary display (%d)", displayId);
+ Preconditions.checkArgument(displayId != Display.INVALID_DISPLAY,
+ "Cannot assign to INVALID_DISPLAY (%d)", displayId);
+
+ int currentUserId = getCurrentUserId();
+ Preconditions.checkArgument(userId != currentUserId,
+ "Cannot assign current user to other displays");
+
+ boolean isProfile = isProfileUnchecked(userId);
+
+ Preconditions.checkArgument(userId != currentUserId,
+ "Cannot assign current user to other displays");
+
+ Preconditions.checkArgument(
+ !isProfile || getProfileParentIdUnchecked(userId) != currentUserId,
+ "Cannot assign profile user %d to display %d when its parent is the current "
+ + "user (%d)", userId, displayId, currentUserId);
synchronized (mUsersOnSecondaryDisplays) {
if (DBG_MUMD) {
@@ -6730,7 +6757,7 @@
userId, displayId);
}
- if (isProfileUnchecked(userId)) {
+ if (isProfile) {
// Profile can only start in the same display as parent
int parentUserId = getProfileParentId(userId);
int parentDisplayId = mUsersOnSecondaryDisplays.get(parentUserId);
@@ -6749,7 +6776,7 @@
// is refactored, it should be atomic.
if (mUsersOnSecondaryDisplays.valueAt(i) == displayId) {
throw new IllegalStateException("Cannot assign " + userId + " to "
- + "display " + displayId + " as it's already assigned to "
+ + "display " + displayId + " as it's already assigned to "
+ "user " + mUsersOnSecondaryDisplays.keyAt(i));
}
// TODO(b/239982558) also check that user is not already assigned to other
diff --git a/services/core/java/com/android/server/pm/resolution/ComponentResolver.java b/services/core/java/com/android/server/pm/resolution/ComponentResolver.java
index 7baec62..1d95e87 100644
--- a/services/core/java/com/android/server/pm/resolution/ComponentResolver.java
+++ b/services/core/java/com/android/server/pm/resolution/ComponentResolver.java
@@ -930,12 +930,14 @@
}
@Override
- protected boolean isFilterStopped(@Nullable PackageStateInternal packageState,
+ protected boolean isFilterStopped(@NonNull Computer computer, F filter,
@UserIdInt int userId) {
if (!mUserManager.exists(userId)) {
return true;
}
+ final PackageStateInternal packageState = computer.getPackageStateInternal(
+ filter.first.getPackageName());
if (packageState == null || packageState.getPkg() == null) {
return false;
}
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index e00e029..e21feae 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -1211,7 +1211,7 @@
if (info.userId == userId
&& info.agent.isTrusted()
&& info.agent.shouldDisplayTrustGrantedMessage()
- && !TextUtils.isEmpty(info.agent.getMessage())) {
+ && info.agent.getMessage() != null) {
trustGrantedMessages.add(info.agent.getMessage().toString());
}
}
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index f25929c..d0b058b 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -2713,6 +2713,13 @@
checkPermission(android.Manifest.permission.SET_WALLPAPER_DIM_AMOUNT);
synchronized (mLock) {
WallpaperData data = mWallpaperMap.get(mCurrentUserId);
+ if (data == null) {
+ data = mWallpaperMap.get(UserHandle.USER_SYSTEM);
+ if (data == null) {
+ Slog.e(TAG, "getWallpaperDimAmount: wallpaperData is null");
+ return 0.0f;
+ }
+ }
return data.mWallpaperDimAmount;
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index be80118..16b5ee5 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -2120,7 +2120,7 @@
mActivityRecordInputSink = new ActivityRecordInputSink(this, sourceRecord);
- updateEnterpriseThumbnailDrawable(mAtmService.mUiContext);
+ updateEnterpriseThumbnailDrawable(mAtmService.getUiContext());
}
/**
@@ -7424,7 +7424,7 @@
}
final Rect frame = win.getRelativeFrame();
final Drawable thumbnailDrawable = task.mUserId == mWmService.mCurrentUserId
- ? mAtmService.mUiContext.getDrawable(R.drawable.ic_account_circle)
+ ? mAtmService.getUiContext().getDrawable(R.drawable.ic_account_circle)
: mEnterpriseThumbnailDrawable;
final HardwareBuffer thumbnail = getDisplayContent().mAppTransition
.createCrossProfileAppsThumbnail(thumbnailDrawable, frame);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index bdbe787..8f5d838 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -345,7 +345,7 @@
* This Context is themable and meant for UI display (AlertDialogs, etc.). The theme can
* change at runtime. Use mContext for non-UI purposes.
*/
- final Context mUiContext;
+ private final Context mUiContext;
final ActivityThread mSystemThread;
H mH;
UiHandler mUiHandler;
@@ -1040,6 +1040,10 @@
}
}
+ Context getUiContext() {
+ return mUiContext;
+ }
+
UserManagerService getUserManager() {
if (mUserManager == null) {
IBinder b = ServiceManager.getService(Context.USER_SERVICE);
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index c940a65..d2c098b 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -39,6 +39,7 @@
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY;
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_OCCLUDE;
+import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM;
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
import static android.view.WindowManager.TRANSIT_OLD_NONE;
import static android.view.WindowManager.TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE;
@@ -746,7 +747,8 @@
if (isKeyguardGoingAwayTransitOld(transit) && enter) {
a = mTransitionAnimation.loadKeyguardExitAnimation(mNextAppTransitionFlags,
transit == TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER);
- } else if (transit == TRANSIT_OLD_KEYGUARD_OCCLUDE) {
+ } else if (transit == TRANSIT_OLD_KEYGUARD_OCCLUDE
+ || transit == TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM) {
a = null;
} else if (transit == TRANSIT_OLD_KEYGUARD_UNOCCLUDE && !enter) {
a = mTransitionAnimation.loadKeyguardUnoccludeAnimation();
@@ -1158,6 +1160,9 @@
case TRANSIT_OLD_KEYGUARD_OCCLUDE: {
return "TRANSIT_OLD_KEYGUARD_OCCLUDE";
}
+ case TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM: {
+ return "TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM";
+ }
case TRANSIT_OLD_KEYGUARD_UNOCCLUDE: {
return "TRANSIT_OLD_KEYGUARD_UNOCCLUDE";
}
@@ -1413,6 +1418,7 @@
static boolean isKeyguardOccludeTransitOld(@TransitionOldType int transit) {
return transit == TRANSIT_OLD_KEYGUARD_OCCLUDE
+ || transit == TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM
|| transit == TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
}
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index 4b0005d..7e62c61 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -34,6 +34,7 @@
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY;
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_OCCLUDE;
+import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM;
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
import static android.view.WindowManager.TRANSIT_OLD_NONE;
import static android.view.WindowManager.TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE;
@@ -357,8 +358,14 @@
// When there is a closing app, the keyguard has already been occluded by an
// activity, and another activity has started on top of that activity, so normal
// app transition animation should be used.
- return closingApps.isEmpty() ? TRANSIT_OLD_KEYGUARD_OCCLUDE
- : TRANSIT_OLD_ACTIVITY_OPEN;
+ if (!closingApps.isEmpty()) {
+ return TRANSIT_OLD_ACTIVITY_OPEN;
+ }
+ if (!openingApps.isEmpty() && openingApps.valueAt(0).getActivityType()
+ == ACTIVITY_TYPE_DREAM) {
+ return TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM;
+ }
+ return TRANSIT_OLD_KEYGUARD_OCCLUDE;
case TRANSIT_KEYGUARD_UNOCCLUDE:
return TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
}
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 537b04d..e780606 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -421,7 +421,7 @@
mService = service;
mContext = displayContent.isDefaultDisplay ? service.mContext
: service.mContext.createDisplayContext(displayContent.getDisplay());
- mUiContext = displayContent.isDefaultDisplay ? service.mAtmService.mUiContext
+ mUiContext = displayContent.isDefaultDisplay ? service.mAtmService.getUiContext()
: service.mAtmService.mSystemThread
.getSystemUiContext(displayContent.getDisplayId());
mDisplayContent = displayContent;
diff --git a/services/tests/mockingservicestests/src/android/service/games/GameSessionTrampolineActivityTest.java b/services/tests/mockingservicestests/src/android/service/games/GameSessionTrampolineActivityTest.java
index d68b517..353341e 100644
--- a/services/tests/mockingservicestests/src/android/service/games/GameSessionTrampolineActivityTest.java
+++ b/services/tests/mockingservicestests/src/android/service/games/GameSessionTrampolineActivityTest.java
@@ -42,6 +42,7 @@
import android.widget.TextView;
import androidx.test.espresso.NoActivityResumedException;
+import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import com.android.internal.infra.AndroidFuture;
@@ -80,6 +81,7 @@
}
@Test
+ @FlakyTest(bugId = 245615459)
public void launch_targetActivityFinishesSuccessfully_futureCompletedWithSameResults() {
AndroidFuture<GameSessionActivityResult> resultFuture =
startTestActivityViaGameSessionTrampolineActivity();
@@ -96,6 +98,7 @@
}
@Test
+ @FlakyTest(bugId = 245616660)
public void launch_trampolineActivityProcessDeath_futureCompletedWithSameResults() {
setAlwaysFinishActivities(true);
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerInternalTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerInternalTest.java
new file mode 100644
index 0000000..1cff6855
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerInternalTest.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.pm;
+
+import static android.os.UserHandle.USER_SYSTEM;
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.INVALID_DISPLAY;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assert.assertThrows;
+
+import android.util.Log;
+
+import org.junit.Test;
+
+/**
+ * Run as {@code atest FrameworksMockingServicesTests:com.android.server.pm.UserManagerInternalTest}
+ */
+public final class UserManagerInternalTest extends UserManagerServiceOrInternalTestCase {
+
+ private static final String TAG = UserManagerInternalTest.class.getSimpleName();
+
+ // NOTE: most the tests below only apply to MUMD configurations, so we're not adding _mumd_
+ // in the test names, but _nonMumd_ instead
+
+ @Test
+ public void testAssignUserToDisplay_nonMumd_defaultDisplayIgnored() {
+ mUmi.assignUserToDisplay(USER_ID, DEFAULT_DISPLAY);
+
+ assertNoUserAssignedToDisplay();
+ }
+
+ @Test
+ public void testAssignUserToDisplay_nonMumd_otherDisplay_currentUser() {
+ mockCurrentUser(USER_ID);
+
+ assertThrows(UnsupportedOperationException.class,
+ () -> mUmi.assignUserToDisplay(USER_ID, SECONDARY_DISPLAY_ID));
+ }
+
+ @Test
+ public void testAssignUserToDisplay_nonMumd_otherDisplay_startProfileOfcurrentUser() {
+ mockCurrentUser(PARENT_USER_ID);
+ addDefaultProfileAndParent();
+ startDefaultProfile();
+
+ assertThrows(UnsupportedOperationException.class,
+ () -> mUmi.assignUserToDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID));
+ }
+
+ @Test
+ public void testAssignUserToDisplay_nonMumd_otherDisplay_stoppedProfileOfcurrentUser() {
+ mockCurrentUser(PARENT_USER_ID);
+ addDefaultProfileAndParent();
+ stopDefaultProfile();
+
+ assertThrows(UnsupportedOperationException.class,
+ () -> mUmi.assignUserToDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID));
+ }
+
+ @Test
+ public void testAssignUserToDisplay_defaultDisplayIgnored() {
+ enableUsersOnSecondaryDisplays();
+
+ mUmi.assignUserToDisplay(USER_ID, DEFAULT_DISPLAY);
+
+ assertNoUserAssignedToDisplay();
+ }
+
+ @Test
+ public void testAssignUserToDisplay_systemUser() {
+ enableUsersOnSecondaryDisplays();
+
+ assertThrows(IllegalArgumentException.class,
+ () -> mUmi.assignUserToDisplay(USER_SYSTEM, SECONDARY_DISPLAY_ID));
+ }
+
+ @Test
+ public void testAssignUserToDisplay_invalidDisplay() {
+ enableUsersOnSecondaryDisplays();
+
+ assertThrows(IllegalArgumentException.class,
+ () -> mUmi.assignUserToDisplay(USER_ID, INVALID_DISPLAY));
+ }
+
+ @Test
+ public void testAssignUserToDisplay_currentUser() {
+ enableUsersOnSecondaryDisplays();
+ mockCurrentUser(USER_ID);
+
+ assertThrows(IllegalArgumentException.class,
+ () -> mUmi.assignUserToDisplay(USER_ID, SECONDARY_DISPLAY_ID));
+
+ assertNoUserAssignedToDisplay();
+ }
+
+ @Test
+ public void testAssignUserToDisplay_startedProfileOfCurrentUser() {
+ enableUsersOnSecondaryDisplays();
+ mockCurrentUser(PARENT_USER_ID);
+ addDefaultProfileAndParent();
+ startDefaultProfile();
+
+ IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
+ () -> mUmi.assignUserToDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID));
+
+ Log.v(TAG, "Exception: " + e);
+ assertWithMessage("exception (%s) message", e).that(e).hasMessageThat()
+ .matches("Cannot.*" + PROFILE_USER_ID + ".*" + SECONDARY_DISPLAY_ID
+ + ".*parent.*current.*" + PARENT_USER_ID + ".*");
+ assertNoUserAssignedToDisplay();
+ }
+
+ @Test
+ public void testAssignUserToDisplay_stoppedProfileOfCurrentUser() {
+ enableUsersOnSecondaryDisplays();
+ mockCurrentUser(PARENT_USER_ID);
+ addDefaultProfileAndParent();
+ stopDefaultProfile();
+
+ IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
+ () -> mUmi.assignUserToDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID));
+
+ Log.v(TAG, "Exception: " + e);
+ assertWithMessage("exception (%s) message", e).that(e).hasMessageThat()
+ .matches("Cannot.*" + PROFILE_USER_ID + ".*" + SECONDARY_DISPLAY_ID
+ + ".*parent.*current.*" + PARENT_USER_ID + ".*");
+
+ assertNoUserAssignedToDisplay();
+ }
+
+ @Test
+ public void testAssignUserToDisplay_displayAvailable() {
+ enableUsersOnSecondaryDisplays();
+
+ mUmi.assignUserToDisplay(USER_ID, SECONDARY_DISPLAY_ID);
+
+ assertUserAssignedToDisplay(USER_ID, SECONDARY_DISPLAY_ID);
+ }
+
+ @Test
+ public void testAssignUserToDisplay_displayAlreadyAssigned() {
+ enableUsersOnSecondaryDisplays();
+
+ mUmi.assignUserToDisplay(USER_ID, SECONDARY_DISPLAY_ID);
+
+ IllegalStateException e = assertThrows(IllegalStateException.class,
+ () -> mUmi.assignUserToDisplay(OTHER_USER_ID, SECONDARY_DISPLAY_ID));
+
+ Log.v(TAG, "Exception: " + e);
+ assertWithMessage("exception (%s) message", e).that(e).hasMessageThat()
+ .matches("Cannot.*" + OTHER_USER_ID + ".*" + SECONDARY_DISPLAY_ID + ".*already.*"
+ + USER_ID + ".*");
+ }
+
+ @Test
+ public void testAssignUserToDisplay_profileOnSameDisplayAsParent() {
+ enableUsersOnSecondaryDisplays();
+ addDefaultProfileAndParent();
+
+ mUmi.assignUserToDisplay(PARENT_USER_ID, SECONDARY_DISPLAY_ID);
+ mUmi.assignUserToDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
+
+ assertUsersAssignedToDisplays(PARENT_USER_ID, SECONDARY_DISPLAY_ID,
+ pair(PROFILE_USER_ID, SECONDARY_DISPLAY_ID));
+ }
+
+ @Test
+ public void testAssignUserToDisplay_profileOnDifferentDisplayAsParent() {
+ enableUsersOnSecondaryDisplays();
+ addDefaultProfileAndParent();
+
+ mUmi.assignUserToDisplay(PARENT_USER_ID, SECONDARY_DISPLAY_ID);
+ IllegalStateException e = assertThrows(IllegalStateException.class,
+ () -> mUmi.assignUserToDisplay(PROFILE_USER_ID, OTHER_SECONDARY_DISPLAY_ID));
+
+ Log.v(TAG, "Exception: " + e);
+ assertWithMessage("exception (%s) message", e).that(e).hasMessageThat()
+ .matches("Cannot.*" + PROFILE_USER_ID + ".*" + OTHER_SECONDARY_DISPLAY_ID
+ + ".*parent.*" + PARENT_USER_ID + ".*" + SECONDARY_DISPLAY_ID + ".*");
+ assertUserAssignedToDisplay(PARENT_USER_ID, SECONDARY_DISPLAY_ID);
+ }
+
+ @Test
+ public void testUnassignUserFromDisplay_nonMumd_ignored() {
+ mockCurrentUser(USER_ID);
+
+ mUmi.unassignUserFromDisplay(USER_SYSTEM);
+ mUmi.unassignUserFromDisplay(USER_ID);
+ mUmi.unassignUserFromDisplay(OTHER_USER_ID);
+
+ assertNoUserAssignedToDisplay();
+ }
+
+ @Test
+ public void testUnassignUserFromDisplay() {
+ testAssignUserToDisplay_displayAvailable();
+
+ mUmi.unassignUserFromDisplay(USER_ID);
+
+ assertNoUserAssignedToDisplay();
+ }
+
+ @Override
+ protected boolean isUserVisible(int userId) {
+ return mUmi.isUserVisible(userId);
+ }
+
+ @Override
+ protected boolean isUserVisibleOnDisplay(int userId, int displayId) {
+ return mUmi.isUserVisible(userId, displayId);
+ }
+
+ @Override
+ protected int getDisplayAssignedToUser(int userId) {
+ return mUmi.getDisplayAssignedToUser(userId);
+ }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceOrInternalTestCase.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceOrInternalTestCase.java
new file mode 100644
index 0000000..4f61b8f
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceOrInternalTestCase.java
@@ -0,0 +1,570 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.pm;
+
+import static android.os.UserHandle.USER_NULL;
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.INVALID_DISPLAY;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.annotation.UserIdInt;
+import android.app.ActivityManagerInternal;
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.os.UserManager;
+import android.util.Log;
+import android.util.Pair;
+import android.util.SparseArray;
+import android.util.SparseIntArray;
+
+import androidx.test.annotation.UiThreadTest;
+
+import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder;
+import com.android.server.ExtendedMockitoTestCase;
+import com.android.server.LocalServices;
+import com.android.server.am.UserState;
+import com.android.server.pm.UserManagerService.UserData;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * Base class for {@link UserManagerInternalTest} and {@link UserManagerInternalTest}.
+ *
+ * <p>{@link UserManagerService} and its {@link UserManagerInternal} implementation have a
+ * "symbiotic relationship - some methods of the former simply call the latter and vice versa.
+ *
+ * <p>Ideally, only one of them should have the logic, but since that's not the case, this class
+ * provices the infra to make it easier to test both (which in turn would make it easier / safer to
+ * refactor their logic later).
+ */
+abstract class UserManagerServiceOrInternalTestCase extends ExtendedMockitoTestCase {
+
+ private static final String TAG = UserManagerServiceOrInternalTestCase.class.getSimpleName();
+
+ /**
+ * Id for a simple user (that doesn't have profiles).
+ */
+ protected static final int USER_ID = 600;
+
+ /**
+ * Id for another simple user.
+ */
+ protected static final int OTHER_USER_ID = 666;
+
+ /**
+ * Id for a user that has one profile (whose id is {@link #PROFILE_USER_ID}.
+ *
+ * <p>You can use {@link #addDefaultProfileAndParent()} to add both of this user to the service.
+ */
+ protected static final int PARENT_USER_ID = 642;
+
+ /**
+ * Id for a profile whose parent is {@link #PARENTUSER_ID}.
+ *
+ * <p>You can use {@link #addDefaultProfileAndParent()} to add both of this user to the service.
+ */
+ protected static final int PROFILE_USER_ID = 643;
+
+ /**
+ * Id of a secondary display (i.e, not {@link android.view.Display.DEFAULT_DISPLAY}).
+ */
+ protected static final int SECONDARY_DISPLAY_ID = 42;
+
+ /**
+ * Id of another secondary display (i.e, not {@link android.view.Display.DEFAULT_DISPLAY}).
+ */
+ protected static final int OTHER_SECONDARY_DISPLAY_ID = 108;
+
+ private final Object mPackagesLock = new Object();
+ private final Context mRealContext = androidx.test.InstrumentationRegistry.getInstrumentation()
+ .getTargetContext();
+ private final SparseArray<UserData> mUsers = new SparseArray<>();
+
+ // TODO(b/244644281): manipulating mUsersOnSecondaryDisplays directly leaks implementation
+ // details into the unit test, but it's fine for now - in the long term, this logic should be
+ // refactored into a proper UserDisplayAssignment class.
+ private final SparseIntArray mUsersOnSecondaryDisplays = new SparseIntArray();
+
+ private Context mSpiedContext;
+ private UserManagerService mStandardUms;
+ private UserManagerService mMumdUms;
+ private UserManagerInternal mStandardUmi;
+ private UserManagerInternal mMumdUmi;
+
+ private @Mock PackageManagerService mMockPms;
+ private @Mock UserDataPreparer mMockUserDataPreparer;
+ private @Mock ActivityManagerInternal mActivityManagerInternal;
+
+ /**
+ * Reference to the {@link UserManagerService} being tested.
+ *
+ * <p>By default, such service doesn't support {@code MUMD} (Multiple Users on Multiple
+ * Displays), but that can be changed by calling {@link #enableUsersOnSecondaryDisplays()}.
+ */
+ protected UserManagerService mUms;
+
+ /**
+ * Reference to the {@link UserManagerInternal} being tested.
+ *
+ * <p>By default, such service doesn't support {@code MUMD} (Multiple Users on Multiple
+ * Displays), but that can be changed by calling {@link #enableUsersOnSecondaryDisplays()}.
+ */
+ protected UserManagerInternal mUmi;
+
+ @Override
+ protected void initializeSession(StaticMockitoSessionBuilder builder) {
+ builder
+ .spyStatic(UserManager.class)
+ .spyStatic(LocalServices.class);
+ }
+
+ @Before
+ @UiThreadTest // Needed to initialize main handler
+ public final void setFixtures() {
+ mSpiedContext = spy(mRealContext);
+
+ // Called when WatchedUserStates is constructed
+ doNothing().when(() -> UserManager.invalidateIsUserUnlockedCache());
+
+ // Need to set both UserManagerService instances here, as they need to be run in the
+ // UiThread
+
+ // mMumdUms / mMumdUmi
+ mockIsUsersOnSecondaryDisplaysEnabled(/* usersOnSecondaryDisplaysEnabled= */ true);
+ mMumdUms = new UserManagerService(mSpiedContext, mMockPms, mMockUserDataPreparer,
+ mPackagesLock, mRealContext.getDataDir(), mUsers, mUsersOnSecondaryDisplays);
+ assertWithMessage("UserManagerService.isUsersOnSecondaryDisplaysEnabled()")
+ .that(mMumdUms.isUsersOnSecondaryDisplaysEnabled())
+ .isTrue();
+ mMumdUmi = LocalServices.getService(UserManagerInternal.class);
+ assertWithMessage("LocalServices.getService(UserManagerInternal.class)").that(mMumdUmi)
+ .isNotNull();
+ resetUserManagerInternal();
+
+ // mStandardUms / mStandardUmi
+ mockIsUsersOnSecondaryDisplaysEnabled(/* usersOnSecondaryDisplaysEnabled= */ false);
+ mStandardUms = new UserManagerService(mSpiedContext, mMockPms, mMockUserDataPreparer,
+ mPackagesLock, mRealContext.getDataDir(), mUsers, mUsersOnSecondaryDisplays);
+ assertWithMessage("UserManagerService.isUsersOnSecondaryDisplaysEnabled()")
+ .that(mStandardUms.isUsersOnSecondaryDisplaysEnabled())
+ .isFalse();
+ mStandardUmi = LocalServices.getService(UserManagerInternal.class);
+ assertWithMessage("LocalServices.getService(UserManagerInternal.class)").that(mStandardUmi)
+ .isNotNull();
+ setServiceFixtures(/*usersOnSecondaryDisplaysEnabled= */ false);
+ }
+
+ @After
+ public final void resetUserManagerInternal() {
+ // LocalServices follows the "Highlander rule" - There can be only one!
+ LocalServices.removeServiceForTest(UserManagerInternal.class);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ // Methods whose UMS implementation calls UMI or vice-versa - they're tested in this class, //
+ // but the subclass must provide the proper implementation //
+ //////////////////////////////////////////////////////////////////////////////////////////////
+
+ protected abstract boolean isUserVisible(int userId);
+ protected abstract boolean isUserVisibleOnDisplay(int userId, int displayId);
+ protected abstract int getDisplayAssignedToUser(int userId);
+
+ /////////////////////////////////
+ // Tests for the above methods //
+ /////////////////////////////////
+
+ @Test
+ public void testIsUserVisible_invalidUser() {
+ mockCurrentUser(USER_ID);
+
+ assertWithMessage("isUserVisible(%s)", USER_NULL).that(isUserVisible(USER_NULL)).isFalse();
+ }
+
+ @Test
+ public void testIsUserVisible_currentUser() {
+ mockCurrentUser(USER_ID);
+
+ assertWithMessage("isUserVisible(%s)", USER_ID).that(isUserVisible(USER_ID)).isTrue();
+ }
+
+ @Test
+ public void testIsUserVisible_nonCurrentUser() {
+ mockCurrentUser(OTHER_USER_ID);
+
+ assertWithMessage("isUserVisible(%s)", USER_ID).that(isUserVisible(USER_ID)).isFalse();
+ }
+
+ @Test
+ public void testIsUserVisible_startedProfileOfcurrentUser() {
+ addDefaultProfileAndParent();
+ mockCurrentUser(PARENT_USER_ID);
+ startDefaultProfile();
+ setUserState(PROFILE_USER_ID, UserState.STATE_RUNNING_UNLOCKED);
+
+ assertWithMessage("isUserVisible(%s)", PROFILE_USER_ID).that(isUserVisible(PROFILE_USER_ID))
+ .isTrue();
+ }
+
+ @Test
+ public void testIsUserVisible_stoppedProfileOfcurrentUser() {
+ addDefaultProfileAndParent();
+ mockCurrentUser(PARENT_USER_ID);
+ stopDefaultProfile();
+
+ assertWithMessage("isUserVisible(%s)", PROFILE_USER_ID).that(isUserVisible(PROFILE_USER_ID))
+ .isFalse();
+ }
+
+ @Test
+ public void testIsUserVisible_bgUserOnSecondaryDisplay() {
+ enableUsersOnSecondaryDisplays();
+ mockCurrentUser(OTHER_USER_ID);
+ assignUserToDisplay(USER_ID, SECONDARY_DISPLAY_ID);
+
+ assertWithMessage("isUserVisible(%s)", USER_ID).that(isUserVisible(USER_ID)).isTrue();
+ }
+
+ // NOTE: we don't need to add tests for profiles (started / stopped profiles of bg user), as
+ // isUserVisible() for bg users relies only on the user / display assignments
+
+ @Test
+ public void testIsUserVisibleOnDisplay_invalidUser() {
+ mockCurrentUser(USER_ID);
+
+ assertWithMessage("isUserVisibleOnDisplay(%s, %s)", USER_NULL, DEFAULT_DISPLAY)
+ .that(isUserVisibleOnDisplay(USER_NULL, DEFAULT_DISPLAY)).isFalse();
+ }
+
+ @Test
+ public void testIsUserVisibleOnDisplay_currentUserInvalidDisplay() {
+ mockCurrentUser(USER_ID);
+
+ assertWithMessage("isUserVisibleOnDisplay(%s, %s)", USER_ID, INVALID_DISPLAY)
+ .that(isUserVisibleOnDisplay(USER_ID, INVALID_DISPLAY)).isTrue();
+ }
+
+ @Test
+ public void testIsUserVisibleOnDisplay_currentUserDefaultDisplay() {
+ mockCurrentUser(USER_ID);
+
+ assertWithMessage("isUserVisibleOnDisplay(%s, %s)", USER_ID, DEFAULT_DISPLAY)
+ .that(isUserVisibleOnDisplay(USER_ID, DEFAULT_DISPLAY)).isTrue();
+ }
+
+ @Test
+ public void testIsUserVisibleOnDisplay_currentUserSecondaryDisplay() {
+ mockCurrentUser(USER_ID);
+
+ assertWithMessage("isUserVisibleOnDisplay(%s, %s)", USER_ID, SECONDARY_DISPLAY_ID)
+ .that(isUserVisibleOnDisplay(USER_ID, SECONDARY_DISPLAY_ID)).isTrue();
+ }
+
+ @Test
+ public void testIsUserVisibleOnDisplay_nonCurrentUserDefaultDisplay() {
+ mockCurrentUser(OTHER_USER_ID);
+
+ assertWithMessage("isUserVisibleOnDisplay(%s, %s)", USER_ID, DEFAULT_DISPLAY)
+ .that(isUserVisibleOnDisplay(USER_ID, DEFAULT_DISPLAY)).isFalse();
+ }
+
+ @Test
+ public void testIsUserVisibleOnDisplay_startedProfileOfcurrentUserInvalidDisplay() {
+ addDefaultProfileAndParent();
+ mockCurrentUser(PARENT_USER_ID);
+ startDefaultProfile();
+ setUserState(PROFILE_USER_ID, UserState.STATE_RUNNING_UNLOCKED);
+
+ assertWithMessage("isUserVisibleOnDisplay(%s, %s)", PROFILE_USER_ID, INVALID_DISPLAY)
+ .that(isUserVisibleOnDisplay(PROFILE_USER_ID, DEFAULT_DISPLAY)).isTrue();
+ }
+
+ @Test
+ public void testIsUserVisibleOnDisplay_stoppedProfileOfcurrentUserInvalidDisplay() {
+ addDefaultProfileAndParent();
+ mockCurrentUser(PARENT_USER_ID);
+ stopDefaultProfile();
+
+ assertWithMessage("isUserVisibleOnDisplay(%s, %s)", PROFILE_USER_ID, INVALID_DISPLAY)
+ .that(isUserVisibleOnDisplay(PROFILE_USER_ID, DEFAULT_DISPLAY)).isFalse();
+ }
+
+ @Test
+ public void testIsUserVisibleOnDisplay_startedProfileOfcurrentUserDefaultDisplay() {
+ addDefaultProfileAndParent();
+ mockCurrentUser(PARENT_USER_ID);
+ startDefaultProfile();
+ setUserState(PROFILE_USER_ID, UserState.STATE_RUNNING_UNLOCKED);
+
+ assertWithMessage("isUserVisibleOnDisplay(%s, %s)", PROFILE_USER_ID, DEFAULT_DISPLAY)
+ .that(isUserVisibleOnDisplay(PROFILE_USER_ID, DEFAULT_DISPLAY)).isTrue();
+ }
+
+ @Test
+ public void testIsUserVisibleOnDisplay_stoppedProfileOfcurrentUserDefaultDisplay() {
+ addDefaultProfileAndParent();
+ mockCurrentUser(PARENT_USER_ID);
+ stopDefaultProfile();
+
+ assertWithMessage("isUserVisibleOnDisplay(%s, %s)", PROFILE_USER_ID, DEFAULT_DISPLAY)
+ .that(isUserVisibleOnDisplay(PROFILE_USER_ID, DEFAULT_DISPLAY)).isFalse();
+ }
+
+ @Test
+ public void testIsUserVisibleOnDisplay_startedProfileOfcurrentUserSecondaryDisplay() {
+ addDefaultProfileAndParent();
+ mockCurrentUser(PARENT_USER_ID);
+ startDefaultProfile();
+ setUserState(PROFILE_USER_ID, UserState.STATE_RUNNING_UNLOCKED);
+
+ assertWithMessage("isUserVisibleOnDisplay(%s, %s)", PROFILE_USER_ID, SECONDARY_DISPLAY_ID)
+ .that(isUserVisibleOnDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID)).isTrue();
+ }
+
+ @Test
+ public void testIsUserVisibleOnDisplay_stoppedProfileOfcurrentUserSecondaryDisplay() {
+ addDefaultProfileAndParent();
+ mockCurrentUser(PARENT_USER_ID);
+ stopDefaultProfile();
+
+ assertWithMessage("isUserVisibleOnDisplay(%s, %s)", PROFILE_USER_ID, SECONDARY_DISPLAY_ID)
+ .that(isUserVisibleOnDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID)).isFalse();
+ }
+
+ @Test
+ public void testIsUserVisibleOnDisplay_bgUserOnSecondaryDisplay() {
+ enableUsersOnSecondaryDisplays();
+ mockCurrentUser(OTHER_USER_ID);
+ assignUserToDisplay(USER_ID, SECONDARY_DISPLAY_ID);
+
+ assertWithMessage("isUserVisibleOnDisplay(%s, %s)", USER_ID, SECONDARY_DISPLAY_ID)
+ .that(isUserVisibleOnDisplay(USER_ID, SECONDARY_DISPLAY_ID)).isTrue();
+ }
+
+ // NOTE: we don't need to add tests for profiles (started / stopped profiles of bg user), as
+ // isUserVisibleOnDisplay() for bg users relies only on the user / display assignments
+
+ @Test
+ public void testGetDisplayAssignedToUser_invalidUser() {
+ mockCurrentUser(USER_ID);
+
+ assertWithMessage("getDisplayAssignedToUser(%s)", USER_NULL)
+ .that(getDisplayAssignedToUser(USER_NULL)).isEqualTo(INVALID_DISPLAY);
+ }
+
+ @Test
+ public void testGetDisplayAssignedToUser_currentUser() {
+ mockCurrentUser(USER_ID);
+
+ assertWithMessage("getDisplayAssignedToUser(%s)", USER_ID)
+ .that(getDisplayAssignedToUser(USER_ID)).isEqualTo(DEFAULT_DISPLAY);
+ }
+
+ @Test
+ public void testGetDisplayAssignedToUser_nonCurrentUser() {
+ mockCurrentUser(OTHER_USER_ID);
+
+ assertWithMessage("getDisplayAssignedToUser(%s)", USER_ID)
+ .that(getDisplayAssignedToUser(USER_ID)).isEqualTo(INVALID_DISPLAY);
+ }
+
+ @Test
+ public void testGetDisplayAssignedToUser_startedProfileOfcurrentUser() {
+ addDefaultProfileAndParent();
+ mockCurrentUser(PARENT_USER_ID);
+ startDefaultProfile();
+ setUserState(PROFILE_USER_ID, UserState.STATE_RUNNING_UNLOCKED);
+
+ assertWithMessage("getDisplayAssignedToUser(%s)", PROFILE_USER_ID)
+ .that(getDisplayAssignedToUser(PROFILE_USER_ID)).isEqualTo(DEFAULT_DISPLAY);
+ }
+
+ @Test
+ public void testGetDisplayAssignedToUser_stoppedProfileOfcurrentUser() {
+ addDefaultProfileAndParent();
+ mockCurrentUser(PARENT_USER_ID);
+ stopDefaultProfile();
+
+ assertWithMessage("getDisplayAssignedToUser(%s)", PROFILE_USER_ID)
+ .that(getDisplayAssignedToUser(PROFILE_USER_ID)).isEqualTo(INVALID_DISPLAY);
+ }
+
+ @Test
+ public void testGetDisplayAssignedToUser_bgUserOnSecondaryDisplay() {
+ enableUsersOnSecondaryDisplays();
+ mockCurrentUser(OTHER_USER_ID);
+ assignUserToDisplay(USER_ID, SECONDARY_DISPLAY_ID);
+
+ assertWithMessage("getDisplayAssignedToUser(%s)", USER_ID)
+ .that(getDisplayAssignedToUser(USER_ID)).isEqualTo(SECONDARY_DISPLAY_ID);
+ }
+
+ // NOTE: we don't need to add tests for profiles (started / stopped profiles of bg user), as
+ // getDisplayAssignedToUser() for bg users relies only on the user / display assignments
+
+ ///////////////////////////////////////////
+ // Helper methods exposed to sub-classes //
+ ///////////////////////////////////////////
+
+ /**
+ * Change test fixtures to use a version that supports {@code MUMD} (Multiple Users on Multiple
+ * Displays).
+ */
+ protected final void enableUsersOnSecondaryDisplays() {
+ setServiceFixtures(/* usersOnSecondaryDisplaysEnabled= */ true);
+ }
+
+ protected final void mockCurrentUser(@UserIdInt int userId) {
+ mockGetLocalService(ActivityManagerInternal.class, mActivityManagerInternal);
+
+ when(mActivityManagerInternal.getCurrentUserId()).thenReturn(userId);
+ }
+
+ protected final <T> void mockGetLocalService(Class<T> serviceClass, T service) {
+ doReturn(service).when(() -> LocalServices.getService(serviceClass));
+ }
+
+ protected final void addDefaultProfileAndParent() {
+ addUser(PARENT_USER_ID);
+ addProfile(PROFILE_USER_ID, PARENT_USER_ID);
+ }
+
+ protected final void addProfile(@UserIdInt int profileId, @UserIdInt int parentId) {
+ TestUserData profileData = new TestUserData(profileId);
+ profileData.info.flags = UserInfo.FLAG_PROFILE;
+ profileData.info.profileGroupId = parentId;
+
+ addUserData(profileData);
+ }
+
+ protected final void addUser(@UserIdInt int userId) {
+ TestUserData userData = new TestUserData(userId);
+
+ addUserData(userData);
+ }
+
+ protected final void startDefaultProfile() {
+ setUserState(PROFILE_USER_ID, UserState.STATE_RUNNING_UNLOCKED);
+ }
+
+ protected final void stopDefaultProfile() {
+ // TODO(b/244798930): should set it to STATE_STOPPING or STATE_SHUTDOWN instead
+ removeUserState(PROFILE_USER_ID);
+ }
+
+ // NOTE: should only called by tests that indirectly needs to check user assignments (like
+ // isUserVisible), not by tests for the user assignment methods per se.
+ protected final void assignUserToDisplay(@UserIdInt int userId, int displayId) {
+ mUsersOnSecondaryDisplays.put(userId, displayId);
+ }
+
+ protected final void assertNoUserAssignedToDisplay() {
+ assertWithMessage("mUsersOnSecondaryDisplays()").that(usersOnSecondaryDisplaysAsMap())
+ .isEmpty();
+ }
+
+ protected final void assertUserAssignedToDisplay(@UserIdInt int userId, int displayId) {
+ assertWithMessage("mUsersOnSecondaryDisplays()").that(usersOnSecondaryDisplaysAsMap())
+ .containsExactly(userId, displayId);
+ }
+
+ @SafeVarargs
+ protected final void assertUsersAssignedToDisplays(@UserIdInt int userId, int displayId,
+ @SuppressWarnings("unchecked") Pair<Integer, Integer>... others) {
+ Object[] otherObjects = new Object[others.length * 2];
+ for (int i = 0; i < others.length; i++) {
+ Pair<Integer, Integer> other = others[i];
+ otherObjects[i * 2] = other.first;
+ otherObjects[i * 2 + 1] = other.second;
+
+ }
+ assertWithMessage("mUsersOnSecondaryDisplays()").that(usersOnSecondaryDisplaysAsMap())
+ .containsExactly(userId, displayId, otherObjects);
+ }
+
+ protected static Pair<Integer, Integer> pair(@UserIdInt int userId, int secondaryDisplayId) {
+ return new Pair<>(userId, secondaryDisplayId);
+ }
+
+ ///////////////////
+ // Private infra //
+ ///////////////////
+
+ private void setServiceFixtures(boolean usersOnSecondaryDisplaysEnabled) {
+ Log.d(TAG, "Setting fixtures for usersOnSecondaryDisplaysEnabled="
+ + usersOnSecondaryDisplaysEnabled);
+ if (usersOnSecondaryDisplaysEnabled) {
+ mUms = mMumdUms;
+ mUmi = mMumdUmi;
+ } else {
+ mUms = mStandardUms;
+ mUmi = mStandardUmi;
+ }
+ }
+
+ private void mockIsUsersOnSecondaryDisplaysEnabled(boolean enabled) {
+ Log.d(TAG, "Mocking UserManager.isUsersOnSecondaryDisplaysEnabled() to return " + enabled);
+ doReturn(enabled).when(() -> UserManager.isUsersOnSecondaryDisplaysEnabled());
+ }
+
+ private void addUserData(TestUserData userData) {
+ Log.d(TAG, "Adding " + userData);
+ mUsers.put(userData.info.id, userData);
+ }
+
+ private void setUserState(@UserIdInt int userId, int userState) {
+ mUmi.setUserState(userId, userState);
+ }
+
+ private void removeUserState(@UserIdInt int userId) {
+ mUmi.removeUserState(userId);
+ }
+
+ private Map<Integer, Integer> usersOnSecondaryDisplaysAsMap() {
+ int size = mUsersOnSecondaryDisplays.size();
+ Map<Integer, Integer> map = new LinkedHashMap<>(size);
+ for (int i = 0; i < size; i++) {
+ map.put(mUsersOnSecondaryDisplays.keyAt(i), mUsersOnSecondaryDisplays.valueAt(i));
+ }
+ return map;
+ }
+
+ private static final class TestUserData extends UserData {
+
+ @SuppressWarnings("deprecation")
+ TestUserData(@UserIdInt int userId) {
+ info = new UserInfo();
+ info.id = userId;
+ }
+
+ @Override
+ public String toString() {
+ return "TestUserData[" + info.toFullString() + "]";
+ }
+ }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java
index 6493111..b335a34 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java
@@ -15,87 +15,20 @@
*/
package com.android.server.pm;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
-
import static com.google.common.truth.Truth.assertWithMessage;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.when;
-
-import android.annotation.UserIdInt;
import android.app.ActivityManagerInternal;
-import android.content.Context;
-import android.content.pm.UserInfo;
import android.os.UserHandle;
-import android.os.UserManager;
-import android.util.Log;
-import android.util.SparseArray;
-import androidx.test.annotation.UiThreadTest;
-
-import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder;
-import com.android.server.ExtendedMockitoTestCase;
-import com.android.server.LocalServices;
-import com.android.server.am.UserState;
-import com.android.server.pm.UserManagerService.UserData;
-
-import org.junit.After;
-import org.junit.Before;
import org.junit.Test;
-import org.mockito.Mock;
/**
* Run as {@code atest FrameworksMockingServicesTests:com.android.server.pm.UserManagerServiceTest}
*/
-public final class UserManagerServiceTest extends ExtendedMockitoTestCase {
-
- private static final String TAG = UserManagerServiceTest.class.getSimpleName();
-
- private final Object mPackagesLock = new Object();
- private final Context mRealContext = androidx.test.InstrumentationRegistry.getInstrumentation()
- .getTargetContext();
- private Context mSpiedContext;
-
- private @Mock PackageManagerService mMockPms;
- private @Mock UserDataPreparer mMockUserDataPreparer;
- private @Mock ActivityManagerInternal mActivityManagerInternal;
-
- private final SparseArray<UserData> mUsers = new SparseArray<>();
- private UserManagerService mUms;
- private UserManagerInternal mUmi;
-
- @Override
- protected void initializeSession(StaticMockitoSessionBuilder builder) {
- builder
- .spyStatic(UserManager.class)
- .spyStatic(LocalServices.class);
- }
-
- @Before
- @UiThreadTest // Needed to initialize main handler
- public void setFixtures() {
- mSpiedContext = spy(mRealContext);
-
- // Called when WatchedUserStates is constructed
- doNothing().when(() -> UserManager.invalidateIsUserUnlockedCache());
-
- mUms = new UserManagerService(mSpiedContext, mMockPms, mMockUserDataPreparer,
- mPackagesLock, mRealContext.getDataDir(), mUsers);
- mUmi = LocalServices.getService(UserManagerInternal.class);
-
- assertWithMessage("LocalServices.getService(UserManagerInternal.class)").that(mUmi)
- .isNotNull();
- }
-
- @After
- public void resetLocalService() {
- // LocalServices follows the "Highlander rule" - There can be only one!
- LocalServices.removeServiceForTest(UserManagerInternal.class);
- }
+public final class UserManagerServiceTest extends UserManagerServiceOrInternalTestCase {
@Test
- public void testgetCurrentUserId_amInternalNotReady() {
+ public void testGetCurrentUserId_amInternalNotReady() {
mockGetLocalService(ActivityManagerInternal.class, null);
assertWithMessage("getCurrentUserId()").that(mUms.getCurrentUserId())
@@ -103,119 +36,70 @@
}
@Test
- public void testgetCurrentUserId() {
- mockCurrentUser(42);
+ public void testGetCurrentUserId() {
+ mockCurrentUser(USER_ID);
assertWithMessage("getCurrentUserId()").that(mUms.getCurrentUserId())
- .isEqualTo(42);
+ .isEqualTo(USER_ID);
}
@Test
public void testIsCurrentUserOrRunningProfileOfCurrentUser_currentUser() {
- int userId = 42;
- mockCurrentUser(userId);
+ mockCurrentUser(USER_ID);
- assertWithMessage("isCurrentUserOrRunningProfileOfCurrentUser(%s)", userId)
- .that(mUms.isCurrentUserOrRunningProfileOfCurrentUser(userId)).isTrue();
+ assertWithMessage("isCurrentUserOrRunningProfileOfCurrentUser(%s)", USER_ID)
+ .that(mUms.isCurrentUserOrRunningProfileOfCurrentUser(USER_ID)).isTrue();
}
@Test
public void testIsCurrentUserOrRunningProfileOfCurrentUser_notCurrentUser() {
- int userId = 42;
- mockCurrentUser(108);
+ mockCurrentUser(OTHER_USER_ID);
- assertWithMessage("isCurrentUserOrRunningProfileOfCurrentUser(%s)", userId)
- .that(mUms.isCurrentUserOrRunningProfileOfCurrentUser(userId)).isFalse();
+ assertWithMessage("isCurrentUserOrRunningProfileOfCurrentUser(%s)", USER_ID)
+ .that(mUms.isCurrentUserOrRunningProfileOfCurrentUser(USER_ID)).isFalse();
}
@Test
public void testIsCurrentUserOrRunningProfileOfCurrentUser_startedProfileOfCurrentUser() {
- int parentId = 108;
- int profileId = 42;
- addUser(parentId);
- addProfile(profileId, parentId);
- mockCurrentUser(parentId);
- setUserState(profileId, UserState.STATE_RUNNING_UNLOCKED);
+ addDefaultProfileAndParent();
+ startDefaultProfile();
+ mockCurrentUser(PARENT_USER_ID);
- assertWithMessage("isCurrentUserOrRunningProfileOfCurrentUser(%s)", profileId)
- .that(mUms.isCurrentUserOrRunningProfileOfCurrentUser(profileId)).isTrue();
+ assertWithMessage("isCurrentUserOrRunningProfileOfCurrentUser(%s)", PROFILE_USER_ID)
+ .that(mUms.isCurrentUserOrRunningProfileOfCurrentUser(PROFILE_USER_ID)).isTrue();
}
@Test
public void testIsCurrentUserOrRunningProfileOfCurrentUser_stoppedProfileOfCurrentUser() {
- int parentId = 108;
- int profileId = 42;
- addUser(parentId);
- addProfile(profileId, parentId);
- mockCurrentUser(parentId);
- // TODO(b/244798930): should set it to STATE_STOPPING or STATE_SHUTDOWN instead
- removeUserState(profileId);
+ addDefaultProfileAndParent();
+ stopDefaultProfile();
+ mockCurrentUser(PARENT_USER_ID);
- assertWithMessage("isCurrentUserOrRunningProfileOfCurrentUser(%s)", profileId)
- .that(mUms.isCurrentUserOrRunningProfileOfCurrentUser(profileId)).isFalse();
+ assertWithMessage("isCurrentUserOrRunningProfileOfCurrentUser(%s)", PROFILE_USER_ID)
+ .that(mUms.isCurrentUserOrRunningProfileOfCurrentUser(PROFILE_USER_ID)).isFalse();
}
@Test
public void testIsCurrentUserOrRunningProfileOfCurrentUser_profileOfNonCurrentUSer() {
- int parentId = 108;
- int profileId = 42;
- int currentUserId = 666;
- addUser(parentId);
- addProfile(profileId, parentId);
- mockCurrentUser(currentUserId);
+ addDefaultProfileAndParent();
+ mockCurrentUser(OTHER_USER_ID);
- assertWithMessage("isCurrentUserOrRunningProfileOfCurrentUser(%s)", profileId)
- .that(mUms.isCurrentUserOrRunningProfileOfCurrentUser(profileId)).isFalse();
+ assertWithMessage("isCurrentUserOrRunningProfileOfCurrentUser(%s)", PROFILE_USER_ID)
+ .that(mUms.isCurrentUserOrRunningProfileOfCurrentUser(PROFILE_USER_ID)).isFalse();
}
- private void mockCurrentUser(@UserIdInt int userId) {
- mockGetLocalService(ActivityManagerInternal.class, mActivityManagerInternal);
-
- when(mActivityManagerInternal.getCurrentUserId()).thenReturn(userId);
+ @Override
+ protected boolean isUserVisible(int userId) {
+ return mUms.isUserVisibleUnchecked(userId);
}
- private <T> void mockGetLocalService(Class<T> serviceClass, T service) {
- doReturn(service).when(() -> LocalServices.getService(serviceClass));
+ @Override
+ protected boolean isUserVisibleOnDisplay(int userId, int displayId) {
+ return mUms.isUserVisibleOnDisplay(userId, displayId);
}
- private void addProfile(@UserIdInt int profileId, @UserIdInt int parentId) {
- TestUserData profileData = new TestUserData(profileId);
- profileData.info.flags = UserInfo.FLAG_PROFILE;
- profileData.info.profileGroupId = parentId;
-
- addUserData(profileData);
- }
-
- private void addUser(@UserIdInt int userId) {
- TestUserData userData = new TestUserData(userId);
-
- addUserData(userData);
- }
-
- private void addUserData(TestUserData userData) {
- Log.d(TAG, "Adding " + userData);
- mUsers.put(userData.info.id, userData);
- }
-
- private void setUserState(@UserIdInt int userId, int userState) {
- mUmi.setUserState(userId, userState);
- }
-
- private void removeUserState(@UserIdInt int userId) {
- mUmi.removeUserState(userId);
- }
-
- private static final class TestUserData extends UserData {
-
- @SuppressWarnings("unused")
- TestUserData(@UserIdInt int userId) {
- info = new UserInfo();
- info.id = userId;
- }
-
- @Override
- public String toString() {
- return "TestUserData[" + info.toFullString() + "]";
- }
+ @Override
+ protected int getDisplayAssignedToUser(int userId) {
+ return mUms.getDisplayAssignedToUser(userId);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java b/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java
index 047fcd6..d5b923a 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java
@@ -26,6 +26,7 @@
import android.content.Context;
import android.os.BatteryManager;
import android.os.BatteryStats;
+import android.os.BatteryStats.HistoryItem;
import android.os.BatteryStats.MeasuredEnergyDetails;
import android.os.Parcel;
import android.util.Log;
@@ -40,7 +41,9 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.InOrder;
import org.mockito.Mock;
+import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.io.File;
@@ -63,6 +66,8 @@
private final Clock mClock = new MockClock();
private BatteryStatsHistory mHistory;
@Mock
+ private BatteryStatsHistory.TraceDelegate mTracer;
+ @Mock
private BatteryStatsHistory.HistoryStepDetailsCalculator mStepDetailsCalculator;
@Before
@@ -79,13 +84,70 @@
}
mHistoryDir.delete();
mHistory = new BatteryStatsHistory(mHistoryBuffer, mSystemDir, 32, 1024,
- mStepDetailsCalculator, mClock);
+ mStepDetailsCalculator, mClock, mTracer);
when(mStepDetailsCalculator.getHistoryStepDetails())
.thenReturn(new BatteryStats.HistoryStepDetails());
}
@Test
+ public void testAtraceBinaryState1() {
+ mHistory.forceRecordAllHistory();
+
+ InOrder inOrder = Mockito.inOrder(mTracer);
+ Mockito.when(mTracer.tracingEnabled()).thenReturn(true);
+
+ mHistory.recordStateStartEvent(mClock.elapsedRealtime(),
+ mClock.uptimeMillis(), HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG);
+ mHistory.recordStateStopEvent(mClock.elapsedRealtime(),
+ mClock.uptimeMillis(), HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG);
+ mHistory.recordStateStartEvent(mClock.elapsedRealtime(),
+ mClock.uptimeMillis(), HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG);
+
+ inOrder.verify(mTracer).traceCounter("battery_stats.mobile_radio", 1);
+ inOrder.verify(mTracer).traceCounter("battery_stats.mobile_radio", 0);
+ inOrder.verify(mTracer).traceCounter("battery_stats.mobile_radio", 1);
+ }
+
+ @Test
+ public void testAtraceBinaryState2() {
+ mHistory.forceRecordAllHistory();
+
+ InOrder inOrder = Mockito.inOrder(mTracer);
+ Mockito.when(mTracer.tracingEnabled()).thenReturn(true);
+
+ mHistory.recordState2StartEvent(mClock.elapsedRealtime(),
+ mClock.uptimeMillis(), HistoryItem.STATE2_WIFI_ON_FLAG);
+ mHistory.recordState2StopEvent(mClock.elapsedRealtime(),
+ mClock.uptimeMillis(), HistoryItem.STATE2_WIFI_ON_FLAG);
+ mHistory.recordState2StartEvent(mClock.elapsedRealtime(),
+ mClock.uptimeMillis(), HistoryItem.STATE2_WIFI_ON_FLAG);
+
+ inOrder.verify(mTracer).traceCounter("battery_stats.wifi", 1);
+ inOrder.verify(mTracer).traceCounter("battery_stats.wifi", 0);
+ inOrder.verify(mTracer).traceCounter("battery_stats.wifi", 1);
+ }
+
+ @Test
+ public void testAtraceNumericalState() {
+ mHistory.forceRecordAllHistory();
+
+ InOrder inOrder = Mockito.inOrder(mTracer);
+ Mockito.when(mTracer.tracingEnabled()).thenReturn(true);
+
+ mHistory.recordDataConnectionTypeChangeEvent(mClock.elapsedRealtime(),
+ mClock.uptimeMillis(), 1);
+ mHistory.recordDataConnectionTypeChangeEvent(mClock.elapsedRealtime(),
+ mClock.uptimeMillis(), 2);
+ mHistory.recordDataConnectionTypeChangeEvent(mClock.elapsedRealtime(),
+ mClock.uptimeMillis(), 3);
+
+ inOrder.verify(mTracer).traceCounter("battery_stats.data_conn", 1);
+ inOrder.verify(mTracer).traceCounter("battery_stats.data_conn", 2);
+ inOrder.verify(mTracer).traceCounter("battery_stats.data_conn", 3);
+ }
+
+ @Test
public void testConstruct() {
createActiveFile(mHistory);
verifyFileNumbers(mHistory, Arrays.asList(0));
@@ -131,7 +193,7 @@
// create a new BatteryStatsHistory object, it will pick up existing history files.
BatteryStatsHistory history2 = new BatteryStatsHistory(mHistoryBuffer, mSystemDir, 32, 1024,
- null, mClock);
+ null, mClock, mTracer);
// verify constructor can pick up all files from file system.
verifyFileNumbers(history2, fileList);
verifyActiveFile(history2, "33.bin");
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 939c7de..b0ccbd1 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -436,15 +436,6 @@
</intent-filter>
</activity>
- <activity android:name="SurfaceViewAlphaActivity"
- android:label="SurfaceView/SurfaceView with Alpha"
- android:exported="true">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="com.android.test.hwui.TEST"/>
- </intent-filter>
- </activity>
-
<activity android:name=".PenStylusActivity"
android:label="Pen/Draw"
android:exported="true">
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/SurfaceViewAlphaActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/SurfaceViewAlphaActivity.java
deleted file mode 100644
index 01fe6ae0..0000000
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/SurfaceViewAlphaActivity.java
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Copyright 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.test.hwui;
-
-import android.app.Activity;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.os.Bundle;
-import android.view.SurfaceHolder;
-import android.view.SurfaceHolder.Callback;
-import android.view.SurfaceView;
-import android.view.View;
-import android.widget.Button;
-import android.widget.LinearLayout;
-import android.widget.RelativeLayout;
-import android.widget.SeekBar;
-import android.widget.TextView;
-
-public class SurfaceViewAlphaActivity extends Activity implements Callback {
- SurfaceView mSurfaceView;
-
- private enum ZOrder {
- ABOVE,
- BELOW
- }
-
- private float mAlpha = 127f / 255f;
- private ZOrder mZOrder = ZOrder.BELOW;
-
-
- private String getAlphaText() {
- return "Alpha: " + mAlpha;
- }
-
- private void toggleZOrder() {
- if (ZOrder.ABOVE.equals(mZOrder)) {
- mZOrder = ZOrder.BELOW;
- } else {
- mZOrder = ZOrder.ABOVE;
- }
- }
-
- // Overlaps a blue view on the left, then the SurfaceView in the center, then a blue view on the
- // right.
- private void overlapViews(SurfaceView view, LinearLayout parent) {
- float density = getResources().getDisplayMetrics().density;
- int surfaceViewSize = (int) (200 * density);
- int blueViewSize = (int) (surfaceViewSize * 2 / 3f);
- int totalSize = (int) (surfaceViewSize * 5 / 3f);
-
- RelativeLayout overlapLayout = new RelativeLayout(this);
-
- RelativeLayout.LayoutParams leftViewLayoutParams = new RelativeLayout.LayoutParams(
- blueViewSize, surfaceViewSize);
- leftViewLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
-
- View leftBlueView = new View(this);
- leftBlueView.setBackgroundColor(Color.BLUE);
- overlapLayout.addView(leftBlueView, leftViewLayoutParams);
-
- RelativeLayout.LayoutParams sVLayoutParams = new RelativeLayout.LayoutParams(
- surfaceViewSize, surfaceViewSize);
- sVLayoutParams.addRule(RelativeLayout.CENTER_IN_PARENT);
- overlapLayout.addView(view, sVLayoutParams);
-
- RelativeLayout.LayoutParams rightViewLayoutParams = new RelativeLayout.LayoutParams(
- blueViewSize, surfaceViewSize);
- rightViewLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
-
- View rightBlueView = new View(this);
- rightBlueView.setBackgroundColor(Color.BLUE);
- overlapLayout.addView(rightBlueView, rightViewLayoutParams);
-
- parent.addView(overlapLayout, new LinearLayout.LayoutParams(
- totalSize, surfaceViewSize));
- }
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- mSurfaceView = new SurfaceView(this);
- mSurfaceView.getHolder().addCallback(this);
- mSurfaceView.setAlpha(mAlpha);
-
- LinearLayout content = new LinearLayout(this);
- content.setOrientation(LinearLayout.VERTICAL);
-
- TextView alphaText = new TextView(this);
- alphaText.setText(getAlphaText());
-
- SeekBar alphaToggle = new SeekBar(this);
- alphaToggle.setMin(0);
- alphaToggle.setMax(255);
- alphaToggle.setProgress(Math.round(mAlpha * 255));
- alphaToggle.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
- @Override
- public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
- mAlpha = progress / 255f;
- alphaText.setText(getAlphaText());
- mSurfaceView.setAlpha(mAlpha);
- }
-
- @Override
- public void onStartTrackingTouch(SeekBar seekBar) {
-
- }
-
- @Override
- public void onStopTrackingTouch(SeekBar seekBar) {
-
- }
- });
-
- content.addView(alphaText, new LinearLayout.LayoutParams(
- LinearLayout.LayoutParams.WRAP_CONTENT,
- LinearLayout.LayoutParams.WRAP_CONTENT));
-
- content.addView(alphaToggle, new LinearLayout.LayoutParams(
- LinearLayout.LayoutParams.MATCH_PARENT,
- LinearLayout.LayoutParams.WRAP_CONTENT));
-
- Button button = new Button(this);
- button.setText("Z " + mZOrder.toString());
- button.setOnClickListener(v -> {
- toggleZOrder();
- mSurfaceView.setZOrderOnTop(ZOrder.ABOVE.equals(mZOrder));
- button.setText("Z " + mZOrder.toString());
- });
-
- content.addView(button, new LinearLayout.LayoutParams(
- LinearLayout.LayoutParams.WRAP_CONTENT,
- LinearLayout.LayoutParams.WRAP_CONTENT));
-
- overlapViews(mSurfaceView, content);
-
- setContentView(content);
- }
-
- @Override
- public void surfaceCreated(SurfaceHolder holder) {
- }
-
- @Override
- public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
- Canvas canvas = holder.lockCanvas();
- canvas.drawColor(Color.RED);
- holder.unlockCanvasAndPost(canvas);
- }
-
- @Override
- public void surfaceDestroyed(SurfaceHolder holder) {
- }
-}