Merge "[CS] Move LkscrnShadeTransitionCtlr to ShadeInteractor#isShadeEnabled." into udc-qpr-dev
diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java
index c4e4995..2b5175c 100644
--- a/core/java/android/app/TaskInfo.java
+++ b/core/java/android/app/TaskInfo.java
@@ -242,6 +242,18 @@
public boolean isLetterboxDoubleTapEnabled;
/**
+ * Whether the user aspect ratio settings button is enabled
+ * @hide
+ */
+ public boolean topActivityEligibleForUserAspectRatioButton;
+
+ /**
+ * Hint about the letterbox state of the top activity.
+ * @hide
+ */
+ public boolean topActivityBoundsLetterboxed;
+
+ /**
* Whether the update comes from a letterbox double-tap action from the user or not.
* @hide
*/
@@ -460,7 +472,8 @@
public boolean hasCompatUI() {
return hasCameraCompatControl() || topActivityInSizeCompat
|| topActivityEligibleForLetterboxEducation
- || isLetterboxDoubleTapEnabled;
+ || isLetterboxDoubleTapEnabled
+ || topActivityEligibleForUserAspectRatioButton;
}
/**
@@ -510,6 +523,8 @@
&& supportsMultiWindow == that.supportsMultiWindow
&& displayAreaFeatureId == that.displayAreaFeatureId
&& isFromLetterboxDoubleTap == that.isFromLetterboxDoubleTap
+ && topActivityEligibleForUserAspectRatioButton
+ == that.topActivityEligibleForUserAspectRatioButton
&& topActivityLetterboxVerticalPosition == that.topActivityLetterboxVerticalPosition
&& topActivityLetterboxWidth == that.topActivityLetterboxWidth
&& topActivityLetterboxHeight == that.topActivityLetterboxHeight
@@ -543,6 +558,8 @@
&& taskId == that.taskId
&& topActivityInSizeCompat == that.topActivityInSizeCompat
&& isFromLetterboxDoubleTap == that.isFromLetterboxDoubleTap
+ && topActivityEligibleForUserAspectRatioButton
+ == that.topActivityEligibleForUserAspectRatioButton
&& topActivityEligibleForLetterboxEducation
== that.topActivityEligibleForLetterboxEducation
&& topActivityLetterboxVerticalPosition == that.topActivityLetterboxVerticalPosition
@@ -606,6 +623,8 @@
displayAreaFeatureId = source.readInt();
cameraCompatControlState = source.readInt();
isLetterboxDoubleTapEnabled = source.readBoolean();
+ topActivityEligibleForUserAspectRatioButton = source.readBoolean();
+ topActivityBoundsLetterboxed = source.readBoolean();
isFromLetterboxDoubleTap = source.readBoolean();
topActivityLetterboxVerticalPosition = source.readInt();
topActivityLetterboxHorizontalPosition = source.readInt();
@@ -660,6 +679,8 @@
dest.writeInt(displayAreaFeatureId);
dest.writeInt(cameraCompatControlState);
dest.writeBoolean(isLetterboxDoubleTapEnabled);
+ dest.writeBoolean(topActivityEligibleForUserAspectRatioButton);
+ dest.writeBoolean(topActivityBoundsLetterboxed);
dest.writeBoolean(isFromLetterboxDoubleTap);
dest.writeInt(topActivityLetterboxVerticalPosition);
dest.writeInt(topActivityLetterboxHorizontalPosition);
@@ -701,8 +722,11 @@
+ " topActivityInSizeCompat=" + topActivityInSizeCompat
+ " topActivityEligibleForLetterboxEducation= "
+ topActivityEligibleForLetterboxEducation
- + " topActivityLetterboxed= " + isLetterboxDoubleTapEnabled
- + " isFromDoubleTap= " + isFromLetterboxDoubleTap
+ + " isLetterboxDoubleTapEnabled= " + isLetterboxDoubleTapEnabled
+ + " topActivityEligibleForUserAspectRatioButton= "
+ + topActivityEligibleForUserAspectRatioButton
+ + " topActivityBoundsLetterboxed= " + topActivityBoundsLetterboxed
+ + " isFromLetterboxDoubleTap= " + isFromLetterboxDoubleTap
+ " topActivityLetterboxVerticalPosition= " + topActivityLetterboxVerticalPosition
+ " topActivityLetterboxHorizontalPosition= "
+ topActivityLetterboxHorizontalPosition
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 06635ee..6d82922 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -683,7 +683,7 @@
public static final int BIND_EXTERNAL_SERVICE = 0x80000000;
/**
- * Works in the same way as {@link #BIND_EXTERNAL_SERVICE}, but it's defined as a (@code long)
+ * Works in the same way as {@link #BIND_EXTERNAL_SERVICE}, but it's defined as a {@code long}
* value that is compatible to {@link BindServiceFlags}.
*/
public static final long BIND_EXTERNAL_SERVICE_LONG = 1L << 62;
@@ -1413,7 +1413,7 @@
* </ul>
* <p>
* If a shared storage device is emulated (as determined by
- * {@link Environment#isExternalStorageEmulated(File)}), it's contents are
+ * {@link Environment#isExternalStorageEmulated(File)}), its contents are
* backed by a private user data partition, which means there is little
* benefit to storing data here instead of the private directories returned
* by {@link #getFilesDir()}, etc.
@@ -1501,7 +1501,7 @@
* </ul>
* <p>
* If a shared storage device is emulated (as determined by
- * {@link Environment#isExternalStorageEmulated(File)}), it's contents are
+ * {@link Environment#isExternalStorageEmulated(File)}), its contents are
* backed by a private user data partition, which means there is little
* benefit to storing data here instead of the private directories returned
* by {@link #getFilesDir()}, etc.
@@ -1812,7 +1812,7 @@
* </ul>
* <p>
* If a shared storage device is emulated (as determined by
- * {@link Environment#isExternalStorageEmulated(File)}), it's contents are
+ * {@link Environment#isExternalStorageEmulated(File)}), its contents are
* backed by a private user data partition, which means there is little
* benefit to storing data here instead of the private directory returned by
* {@link #getCacheDir()}.
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 6195443..f594377 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -980,23 +980,6 @@
}
/**
- * @hide
- */
- @RequiresPermission(USE_BIOMETRIC_INTERNAL)
- public void setUdfpsOverlay(@NonNull IUdfpsOverlay controller) {
- if (mService == null) {
- Slog.w(TAG, "setUdfpsOverlay: no fingerprint service");
- return;
- }
-
- try {
- mService.setUdfpsOverlay(controller);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
* Forwards BiometricStateListener to FingerprintService
* @param listener new BiometricStateListener being added
* @hide
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index ff2f313..9975852 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -27,7 +27,6 @@
import android.hardware.fingerprint.IFingerprintServiceReceiver;
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.hardware.fingerprint.ISidefpsController;
-import android.hardware.fingerprint.IUdfpsOverlay;
import android.hardware.fingerprint.Fingerprint;
import android.hardware.fingerprint.FingerprintAuthenticateOptions;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
@@ -203,10 +202,6 @@
@EnforcePermission("USE_BIOMETRIC_INTERNAL")
void setSidefpsController(in ISidefpsController controller);
- // Sets the controller for managing the UDFPS overlay.
- @EnforcePermission("USE_BIOMETRIC_INTERNAL")
- void setUdfpsOverlay(in IUdfpsOverlay controller);
-
// Registers BiometricStateListener.
@EnforcePermission("USE_BIOMETRIC_INTERNAL")
void registerBiometricStateListener(IBiometricStateListener listener);
diff --git a/core/java/android/hardware/fingerprint/IUdfpsOverlay.aidl b/core/java/android/hardware/fingerprint/IUdfpsOverlay.aidl
deleted file mode 100644
index c99fccc..0000000
--- a/core/java/android/hardware/fingerprint/IUdfpsOverlay.aidl
+++ /dev/null
@@ -1,29 +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 android.hardware.fingerprint;
-
-/**
- * Interface for interacting with the under-display fingerprint sensor (UDFPS) overlay.
- * @hide
- */
-oneway interface IUdfpsOverlay {
- // Shows the overlay.
- void show(long requestId, int sensorId, int reason);
-
- // Hides the overlay.
- void hide(int sensorId);
-}
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 2f9c207..a9c4818 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -52,6 +52,8 @@
import static android.view.WindowInsets.Type.navigationBars;
import static android.view.WindowInsets.Type.statusBars;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
import android.annotation.AnyThread;
import android.annotation.CallSuper;
import android.annotation.DrawableRes;
@@ -158,7 +160,6 @@
import com.android.internal.inputmethod.InputMethodPrivilegedOperations;
import com.android.internal.inputmethod.InputMethodPrivilegedOperationsRegistry;
import com.android.internal.inputmethod.SoftInputShowHideReason;
-import com.android.internal.util.Preconditions;
import com.android.internal.util.RingBuffer;
import org.xmlpull.v1.XmlPullParserException;
@@ -481,53 +482,43 @@
public static final int BACK_DISPOSITION_ADJUST_NOTHING = 3;
/**
- * Enum values to be used for {@link #setBackDisposition(int)}.
+ * Enum flag to be used for {@link #setBackDisposition(int)}.
*
* @hide
*/
- @IntDef(prefix = { "BACK_DISPOSITION_" }, value = {
- BACK_DISPOSITION_DEFAULT,
- BACK_DISPOSITION_WILL_NOT_DISMISS,
- BACK_DISPOSITION_WILL_DISMISS,
- BACK_DISPOSITION_ADJUST_NOTHING,
- })
- @Retention(RetentionPolicy.SOURCE)
+ @Retention(SOURCE)
+ @IntDef(value = {BACK_DISPOSITION_DEFAULT, BACK_DISPOSITION_WILL_NOT_DISMISS,
+ BACK_DISPOSITION_WILL_DISMISS, BACK_DISPOSITION_ADJUST_NOTHING},
+ prefix = "BACK_DISPOSITION_")
public @interface BackDispositionMode {}
/**
- * Enum flags to be used for {@link #setImeWindowStatus}, representing the current state of the
- * IME window visibility.
- *
* @hide
- */
- @IntDef(flag = true, prefix = { "IME_" }, value = {
- IME_ACTIVE,
- IME_VISIBLE,
- IME_VISIBLE_IMPERCEPTIBLE,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface ImeWindowVisibility {}
-
- /**
* The IME is active. It may or may not be visible.
- * @hide
*/
public static final int IME_ACTIVE = 0x1;
/**
- * The IME is perceptibly visible to the user.
* @hide
+ * The IME is perceptibly visible to the user.
*/
public static final int IME_VISIBLE = 0x2;
/**
+ * @hide
+ * The IME is active and ready with views but set invisible.
+ * This flag cannot be combined with {@link #IME_VISIBLE}.
+ */
+ public static final int IME_INVISIBLE = 0x4;
+
+ /**
+ * @hide
* The IME is visible, but not yet perceptible to the user (e.g. fading in)
* by {@link android.view.WindowInsetsController}.
*
* @see InputMethodManager#reportPerceptible
- * @hide
*/
- public static final int IME_VISIBLE_IMPERCEPTIBLE = 0x4;
+ public static final int IME_VISIBLE_IMPERCEPTIBLE = 0x8;
// Min and max values for back disposition.
private static final int BACK_DISPOSITION_MIN = BACK_DISPOSITION_DEFAULT;
@@ -640,18 +631,9 @@
int mStatusIcon;
- /**
- * Latest value reported of back disposition mode.
- */
@BackDispositionMode
int mBackDisposition;
- /**
- * Latest value reported of IME window visibility flags.
- */
- @ImeWindowVisibility
- private int mImeWindowVisibility;
-
private Object mLock = new Object();
@GuardedBy("mLock")
private boolean mNotifyUserActionSent;
@@ -1228,14 +1210,8 @@
mImeSurfaceRemoverRunnable = null;
}
- private void setImeWindowStatus(@ImeWindowVisibility int vis,
- @BackDispositionMode int backDisposition) {
- if (vis == mImeWindowVisibility && backDisposition == mBackDisposition) {
- return;
- }
- mImeWindowVisibility = Preconditions.checkFlagsArgument(vis, IME_ACTIVE | IME_VISIBLE);
- mBackDisposition = backDisposition;
- mPrivOps.setImeWindowStatusAsync(mImeWindowVisibility, mBackDisposition);
+ private void setImeWindowStatus(int visibilityFlags, int backDisposition) {
+ mPrivOps.setImeWindowStatusAsync(visibilityFlags, backDisposition);
}
/** Set region of the keyboard to be avoided from back gesture */
@@ -1909,11 +1885,15 @@
* @param disposition disposition mode to be set
*/
public void setBackDisposition(@BackDispositionMode int disposition) {
- if (disposition < BACK_DISPOSITION_MIN || disposition > BACK_DISPOSITION_MAX) {
+ if (disposition == mBackDisposition) {
+ return;
+ }
+ if (disposition > BACK_DISPOSITION_MAX || disposition < BACK_DISPOSITION_MIN) {
Log.e(TAG, "Invalid back disposition value (" + disposition + ") specified.");
return;
}
- setImeWindowStatus(mImeWindowVisibility, disposition);
+ mBackDisposition = disposition;
+ setImeWindowStatus(mapToImeWindowStatus(), mBackDisposition);
}
/**
@@ -2887,8 +2867,14 @@
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.showWindow");
mDecorViewWasVisible = mDecorViewVisible;
mInShowWindow = true;
+ final int previousImeWindowStatus =
+ (mDecorViewVisible ? IME_ACTIVE : 0) | (isInputViewShown()
+ ? (!mWindowVisible ? IME_INVISIBLE : IME_VISIBLE) : 0);
startViews(prepareWindow(showInput));
- setImeWindowStatus(mapToImeWindowStatus(), mBackDisposition);
+ final int nextImeWindowStatus = mapToImeWindowStatus();
+ if (previousImeWindowStatus != nextImeWindowStatus) {
+ setImeWindowStatus(nextImeWindowStatus, mBackDisposition);
+ }
mNavigationBarController.onWindowShown();
// compute visibility
@@ -4099,9 +4085,9 @@
};
}
- @ImeWindowVisibility
private int mapToImeWindowStatus() {
- return IME_ACTIVE | (mDecorViewVisible ? IME_VISIBLE : 0);
+ return IME_ACTIVE
+ | (isInputViewShown() ? IME_VISIBLE : 0);
}
private boolean isAutomotive() {
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index c9073fa..e6bdfe1 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -116,6 +116,8 @@
private static final String ANGLE_GL_DRIVER_CHOICE_ANGLE = "angle";
private static final String ANGLE_GL_DRIVER_CHOICE_NATIVE = "native";
+ private static final String PROPERTY_RO_ANGLE_SUPPORTED = "ro.gfx.angle.supported";
+
private ClassLoader mClassLoader;
private String mLibrarySearchPaths;
private String mLibraryPermittedPaths;
@@ -501,10 +503,12 @@
final List<ResolveInfo> resolveInfos =
pm.queryIntentActivities(intent, PackageManager.MATCH_SYSTEM_ONLY);
if (resolveInfos.size() != 1) {
- Log.e(TAG, "Invalid number of ANGLE packages. Required: 1, Found: "
+ Log.v(TAG, "Invalid number of ANGLE packages. Required: 1, Found: "
+ resolveInfos.size());
- for (ResolveInfo resolveInfo : resolveInfos) {
- Log.e(TAG, "Found ANGLE package: " + resolveInfo.activityInfo.packageName);
+ if (DEBUG) {
+ for (ResolveInfo resolveInfo : resolveInfos) {
+ Log.d(TAG, "Found ANGLE package: " + resolveInfo.activityInfo.packageName);
+ }
}
return "";
}
@@ -539,26 +543,42 @@
}
/**
- * Determine whether ANGLE should be used, set it up if so, and pass ANGLE details down to
- * the C++ GraphicsEnv class.
+ * Determine whether ANGLE should be used, attempt to set up from apk first, if ANGLE can be
+ * set up from apk, pass ANGLE details down to the C++ GraphicsEnv class via
+ * GraphicsEnv::setAngleInfo(). If apk setup fails, attempt to set up to use system ANGLE.
+ * Return false if both fail.
*
- * If ANGLE will be used, GraphicsEnv::setAngleInfo() will be called to enable ANGLE to be
- * properly used.
- *
- * @param context
- * @param bundle
- * @param pm
+ * @param context - Context of the application.
+ * @param bundle - Bundle of the application.
+ * @param packageManager - PackageManager of the application process.
* @param packageName - package name of the application.
- * @return true: ANGLE setup successfully
- * false: ANGLE not setup (not on allowlist, ANGLE not present, etc.)
+ * @return true: can set up to use ANGLE successfully.
+ * false: can not set up to use ANGLE (not on allowlist, ANGLE not present, etc.)
*/
- private boolean setupAngle(Context context, Bundle bundle, PackageManager pm,
+ private boolean setupAngle(Context context, Bundle bundle, PackageManager packageManager,
String packageName) {
if (!shouldUseAngle(context, bundle, packageName)) {
return false;
}
+ return setupAngleFromApk(context, bundle, packageManager, packageName)
+ || setupAngleFromSystem(context, bundle, packageName);
+ }
+
+ /**
+ * Attempt to set up ANGLE from the packaged apk, if the apk can be found, pass ANGLE details to
+ * the C++ GraphicsEnv class.
+ *
+ * @param context - Context of the application.
+ * @param bundle - Bundle of the application.
+ * @param packageManager - PackageManager of the application process.
+ * @param packageName - package name of the application.
+ * @return true: can set up to use ANGLE apk.
+ * false: can not set up to use ANGLE apk (ANGLE apk not present, etc.)
+ */
+ private boolean setupAngleFromApk(Context context, Bundle bundle, PackageManager packageManager,
+ String packageName) {
ApplicationInfo angleInfo = null;
// If the developer has specified a debug package over ADB, attempt to find it
@@ -567,7 +587,7 @@
Log.v(TAG, "ANGLE debug package enabled: " + anglePkgName);
try {
// Note the debug package does not have to be pre-installed
- angleInfo = pm.getApplicationInfo(anglePkgName, 0);
+ angleInfo = packageManager.getApplicationInfo(anglePkgName, 0);
} catch (PackageManager.NameNotFoundException e) {
// If the debug package is specified but not found, abort.
Log.v(TAG, "ANGLE debug package '" + anglePkgName + "' not installed");
@@ -577,7 +597,7 @@
// Otherwise, check to see if ANGLE is properly installed
if (angleInfo == null) {
- anglePkgName = getAnglePackageName(pm);
+ anglePkgName = getAnglePackageName(packageManager);
if (TextUtils.isEmpty(anglePkgName)) {
Log.v(TAG, "Failed to find ANGLE package.");
return false;
@@ -586,7 +606,7 @@
Log.v(TAG, "ANGLE package enabled: " + anglePkgName);
try {
// Production ANGLE libraries must be pre-installed as a system app
- angleInfo = pm.getApplicationInfo(anglePkgName,
+ angleInfo = packageManager.getApplicationInfo(anglePkgName,
PackageManager.MATCH_SYSTEM_ONLY);
} catch (PackageManager.NameNotFoundException e) {
Log.v(TAG, "ANGLE package '" + anglePkgName + "' not installed");
@@ -610,12 +630,36 @@
// If we make it to here, ANGLE will be used. Call setAngleInfo() with the package name,
// and features to use.
final String[] features = getAngleEglFeatures(context, bundle);
- setAngleInfo(paths, packageName, ANGLE_GL_DRIVER_CHOICE_ANGLE, features);
+ setAngleInfo(paths, false, packageName, features);
return true;
}
/**
+ * Attempt to set up ANGLE from system, if the apk can be found, pass ANGLE details to
+ * the C++ GraphicsEnv class.
+ *
+ * @param context - Context of the application.
+ * @param bundle - Bundle of the application.
+ * @param packageName - package name of the application.
+ * @return true: can set up to use system ANGLE.
+ * false: can not set up to use system ANGLE because it doesn't exist.
+ */
+ private boolean setupAngleFromSystem(Context context, Bundle bundle, String packageName) {
+ final boolean systemAngleSupported = SystemProperties
+ .getBoolean(PROPERTY_RO_ANGLE_SUPPORTED, false);
+ if (!systemAngleSupported) {
+ return false;
+ }
+
+ // If we make it to here, ANGLE will be used. Call setAngleInfo() with the package name,
+ // and features to use.
+ final String[] features = getAngleEglFeatures(context, bundle);
+ setAngleInfo("", true, packageName, features);
+ return true;
+ }
+
+ /**
* Determine if the "ANGLE In Use" dialog box should be shown.
*/
private boolean shouldShowAngleInUseDialogBox(Context context) {
@@ -651,7 +695,9 @@
final Intent intent = new Intent(ACTION_ANGLE_FOR_ANDROID_TOAST_MESSAGE);
final String anglePkg = getAnglePackageName(context.getPackageManager());
- intent.setPackage(anglePkg);
+ if (anglePkg.isEmpty()) {
+ return;
+ }
context.sendOrderedBroadcast(intent, null, new BroadcastReceiver() {
@Override
@@ -890,8 +936,8 @@
private static native void setDriverPathAndSphalLibraries(String path, String sphalLibraries);
private static native void setGpuStats(String driverPackageName, String driverVersionName,
long driverVersionCode, long driverBuildTime, String appPackageName, int vulkanVersion);
- private static native void setAngleInfo(String path, String packageName,
- String devOptIn, String[] features);
+ private static native void setAngleInfo(String path, boolean useSystemAngle, String packageName,
+ String[] features);
private static native boolean setInjectLayersPrSetDumpable();
private static native void nativeToggleAngleAsSystemDriver(boolean enabled);
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 40b060a..3f308e6 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -2657,17 +2657,6 @@
}
}
- if (windowGainingFocus == null) {
- windowGainingFocus = view.getWindowToken();
- if (windowGainingFocus == null) {
- Log.e(TAG, "ABORT input: ServedView must be attached to a Window");
- return false;
- }
- startInputFlags = getStartInputFlags(view, startInputFlags);
- softInputMode = view.getViewRootImpl().mWindowAttributes.softInputMode;
- windowFlags = view.getViewRootImpl().mWindowAttributes.flags;
- }
-
// Now we need to get an input connection from the served view.
// This is complicated in a couple ways: we can't be holding our lock
// when calling out to the view, and we need to make sure we call into
@@ -2690,6 +2679,17 @@
return false;
}
+ if (windowGainingFocus == null) {
+ windowGainingFocus = view.getWindowToken();
+ if (windowGainingFocus == null) {
+ Log.e(TAG, "ABORT input: ServedView must be attached to a Window");
+ return false;
+ }
+ startInputFlags = getStartInputFlags(view, startInputFlags);
+ softInputMode = view.getViewRootImpl().mWindowAttributes.softInputMode;
+ windowFlags = view.getViewRootImpl().mWindowAttributes.flags;
+ }
+
// Okay we are now ready to call into the served view and have it
// do its stuff.
// Life is good: let's hook everything up!
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index d37c37a..3da9e96 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -8105,6 +8105,16 @@
private final Paint mHighlightPaint;
private final Path mHighlightPath;
+ /**
+ * Whether it is in the progress of updating transformation method. It's needed because
+ * {@link TextView#setTransformationMethod(TransformationMethod)} will eventually call
+ * {@link TextView#setText(CharSequence)}.
+ * Because it normally should exit insert mode when {@link TextView#setText(CharSequence)}
+ * is called externally, we need this boolean to distinguish whether setText is triggered
+ * by setTransformation or not.
+ */
+ private boolean mUpdatingTransformationMethod;
+
InsertModeController(@NonNull TextView textView) {
mTextView = Objects.requireNonNull(textView);
mIsInsertModeActive = false;
@@ -8137,7 +8147,7 @@
final boolean isSingleLine = mTextView.isSingleLine();
mInsertModeTransformationMethod = new InsertModeTransformationMethod(offset,
isSingleLine, oldTransformationMethod);
- mTextView.setTransformationMethodInternal(mInsertModeTransformationMethod);
+ setTransformationMethod(mInsertModeTransformationMethod, true);
Selection.setSelection((Spannable) mTextView.getText(), offset);
mIsInsertModeActive = true;
@@ -8145,6 +8155,10 @@
}
void exitInsertMode() {
+ exitInsertMode(true);
+ }
+
+ void exitInsertMode(boolean updateText) {
if (!mIsInsertModeActive) return;
if (mInsertModeTransformationMethod == null
|| mInsertModeTransformationMethod != mTextView.getTransformationMethod()) {
@@ -8157,7 +8171,7 @@
final int selectionEnd = mTextView.getSelectionEnd();
final TransformationMethod oldTransformationMethod =
mInsertModeTransformationMethod.getOldTransformationMethod();
- mTextView.setTransformationMethodInternal(oldTransformationMethod);
+ setTransformationMethod(oldTransformationMethod, updateText);
Selection.setSelection((Spannable) mTextView.getText(), selectionStart, selectionEnd);
mIsInsertModeActive = false;
}
@@ -8178,6 +8192,32 @@
}
/**
+ * Update the TransformationMethod on the {@link TextView}.
+ * @param method the new method to be set on the {@link TextView}/
+ * @param updateText whether to update the text during setTransformationMethod call.
+ */
+ private void setTransformationMethod(TransformationMethod method, boolean updateText) {
+ mUpdatingTransformationMethod = true;
+ mTextView.setTransformationMethodInternal(method, updateText);
+ mUpdatingTransformationMethod = false;
+ }
+
+ /**
+ * Notify the InsertMode controller that the {@link TextView} is about to set its text.
+ */
+ void beforeSetText() {
+ // TextView#setText is called because our call to
+ // TextView#setTransformationMethodInternal in enterInsertMode() or exitInsertMode().
+ // Do nothing in this case.
+ if (mUpdatingTransformationMethod) {
+ return;
+ }
+ // TextView#setText is called externally. Exit InsertMode but don't update text again
+ // when calling setTransformationMethod.
+ exitInsertMode(/* updateText */ false);
+ }
+
+ /**
* Notify the {@link InsertModeController} before the TextView's
* {@link TransformationMethod} is updated. If it's not in the insert mode,
* the given method is directly returned. Otherwise, it will wrap the given transformation
@@ -8205,6 +8245,9 @@
return mInsertModeController.enterInsertMode(offset);
}
+ /**
+ * Exit insert mode if this editor is in insert mode.
+ */
void exitInsertMode() {
if (mInsertModeController == null) return;
mInsertModeController.exitInsertMode();
@@ -8217,7 +8260,7 @@
*/
void setTransformationMethod(TransformationMethod method) {
if (mInsertModeController == null || !mInsertModeController.mIsInsertModeActive) {
- mTextView.setTransformationMethodInternal(method);
+ mTextView.setTransformationMethodInternal(method, /* updateText */ true);
return;
}
@@ -8226,11 +8269,19 @@
final int selectionStart = mTextView.getSelectionStart();
final int selectionEnd = mTextView.getSelectionEnd();
method = mInsertModeController.updateTransformationMethod(method);
- mTextView.setTransformationMethodInternal(method);
+ mTextView.setTransformationMethodInternal(method, /* updateText */ true);
Selection.setSelection((Spannable) mTextView.getText(), selectionStart, selectionEnd);
}
/**
+ * Notify that the Editor that the associated {@link TextView} is about to set its text.
+ */
+ void beforeSetText() {
+ if (mInsertModeController == null) return;
+ mInsertModeController.beforeSetText();
+ }
+
+ /**
* Initializes the nodeInfo with smart actions.
*/
void onInitializeSmartActionsAccessibilityNodeInfo(AccessibilityNodeInfo nodeInfo) {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 7e1e52d..438b974 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -2795,11 +2795,22 @@
if (mEditor != null) {
mEditor.setTransformationMethod(method);
} else {
- setTransformationMethodInternal(method);
+ setTransformationMethodInternal(method, /* updateText */ true);
}
}
- void setTransformationMethodInternal(@Nullable TransformationMethod method) {
+ /**
+ * Set the transformation that is applied to the text that this TextView is displaying,
+ * optionally call the setText.
+ * @param method the new transformation method to be set.
+ * @param updateText whether the call {@link #setText} which will update the TextView to display
+ * the new content. This method is helpful when updating
+ * {@link TransformationMethod} inside {@link #setText}. It should only be
+ * false if text will be updated immediately after this call, otherwise the
+ * TextView will enter an inconsistent state.
+ */
+ void setTransformationMethodInternal(@Nullable TransformationMethod method,
+ boolean updateText) {
if (method == mTransformation) {
// Avoid the setText() below if the transformation is
// the same.
@@ -2821,7 +2832,9 @@
mAllowTransformationLengthChange = false;
}
- setText(mText);
+ if (updateText) {
+ setText(mText);
+ }
if (hasPasswordTransformationMethod()) {
notifyViewAccessibilityStateChangedIfNeeded(
@@ -7000,6 +7013,9 @@
@UnsupportedAppUsage
private void setText(CharSequence text, BufferType type,
boolean notifyBefore, int oldlen) {
+ if (mEditor != null) {
+ mEditor.beforeSetText();
+ }
mTextSetFromXmlOrResourceId = false;
if (text == null) {
text = "";
@@ -13811,13 +13827,14 @@
}
/**
- * Helper method to set {@code rect} to the text content's non-clipped area in the view's
- * coordinates.
+ * Helper method to set {@code rect} to this TextView's non-clipped area in its own coordinates.
+ * This method obtains the view's visible rectangle whereas the method
+ * {@link #getContentVisibleRect} returns the text layout's visible rectangle.
*
* @return true if at least part of the text content is visible; false if the text content is
* completely clipped or translated out of the visible area.
*/
- private boolean getContentVisibleRect(Rect rect) {
+ private boolean getViewVisibleRect(Rect rect) {
if (!getLocalVisibleRect(rect)) {
return false;
}
@@ -13826,6 +13843,20 @@
// view's coordinates. So we need to offset it with the negative scrolled amount to convert
// it to view's coordinate.
rect.offset(-getScrollX(), -getScrollY());
+ return true;
+ }
+
+ /**
+ * Helper method to set {@code rect} to the text content's non-clipped area in the view's
+ * coordinates.
+ *
+ * @return true if at least part of the text content is visible; false if the text content is
+ * completely clipped or translated out of the visible area.
+ */
+ private boolean getContentVisibleRect(Rect rect) {
+ if (!getViewVisibleRect(rect)) {
+ return false;
+ }
// Clip the view's visible rect with the text layout's visible rect.
return rect.intersect(getCompoundPaddingLeft(), getCompoundPaddingTop(),
getWidth() - getCompoundPaddingRight(), getHeight() - getCompoundPaddingBottom());
@@ -13955,14 +13986,25 @@
builder.setMatrix(viewToScreenMatrix);
if (includeEditorBounds) {
- final RectF editorBounds = new RectF();
- editorBounds.set(0 /* left */, 0 /* top */,
- getWidth(), getHeight());
- final RectF handwritingBounds = new RectF(
- -getHandwritingBoundsOffsetLeft(),
- -getHandwritingBoundsOffsetTop(),
- getWidth() + getHandwritingBoundsOffsetRight(),
- getHeight() + getHandwritingBoundsOffsetBottom());
+ if (mTempRect == null) {
+ mTempRect = new Rect();
+ }
+ final Rect bounds = mTempRect;
+ final RectF editorBounds;
+ final RectF handwritingBounds;
+ if (getViewVisibleRect(bounds)) {
+ editorBounds = new RectF(bounds);
+ handwritingBounds = new RectF(editorBounds);
+ handwritingBounds.top -= getHandwritingBoundsOffsetTop();
+ handwritingBounds.left -= getHandwritingBoundsOffsetLeft();
+ handwritingBounds.bottom += getHandwritingBoundsOffsetBottom();
+ handwritingBounds.right += getHandwritingBoundsOffsetRight();
+ } else {
+ // The editor is not visible at all, return empty rectangles. We still need to
+ // return an EditorBoundsInfo because IME has subscribed the EditorBoundsInfo.
+ editorBounds = new RectF();
+ handwritingBounds = new RectF();
+ }
EditorBoundsInfo.Builder boundsBuilder = new EditorBoundsInfo.Builder();
EditorBoundsInfo editorBoundsInfo = boundsBuilder.setEditorBounds(editorBounds)
.setHandwritingBounds(handwritingBounds).build();
diff --git a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
index 1a38049..66e3333 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
@@ -20,7 +20,6 @@
import android.annotation.DrawableRes;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.inputmethodservice.InputMethodService;
import android.net.Uri;
import android.os.IBinder;
import android.os.RemoteException;
@@ -106,10 +105,14 @@
*
* @param vis visibility flags
* @param backDisposition disposition flags
+ * @see android.inputmethodservice.InputMethodService#IME_ACTIVE
+ * @see android.inputmethodservice.InputMethodService#IME_VISIBLE
+ * @see android.inputmethodservice.InputMethodService#IME_INVISIBLE
+ * @see android.inputmethodservice.InputMethodService#BACK_DISPOSITION_DEFAULT
+ * @see android.inputmethodservice.InputMethodService#BACK_DISPOSITION_ADJUST_NOTHING
*/
@AnyThread
- public void setImeWindowStatusAsync(@InputMethodService.ImeWindowVisibility int vis,
- @InputMethodService.BackDispositionMode int backDisposition) {
+ public void setImeWindowStatusAsync(int vis, int backDisposition) {
final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull();
if (ops == null) {
return;
diff --git a/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java b/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java
index 8b9a991..4f827cd 100644
--- a/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java
+++ b/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java
@@ -16,7 +16,6 @@
package com.android.internal.statusbar;
-import android.inputmethodservice.InputMethodService;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
@@ -32,9 +31,7 @@
public final int mDisabledFlags1; // switch[0]
public final int mAppearance; // switch[1]
public final AppearanceRegion[] mAppearanceRegions; // switch[2]
- @InputMethodService.ImeWindowVisibility
public final int mImeWindowVis; // switch[3]
- @InputMethodService.BackDispositionMode
public final int mImeBackDisposition; // switch[4]
public final boolean mShowImeSwitcher; // switch[5]
public final int mDisabledFlags2; // switch[6]
@@ -47,12 +44,10 @@
public final LetterboxDetails[] mLetterboxDetails;
public RegisterStatusBarResult(ArrayMap<String, StatusBarIcon> icons, int disabledFlags1,
- int appearance, AppearanceRegion[] appearanceRegions,
- @InputMethodService.ImeWindowVisibility int imeWindowVis,
- @InputMethodService.BackDispositionMode int imeBackDisposition, boolean showImeSwitcher,
- int disabledFlags2, IBinder imeToken, boolean navbarColorManagedByIme, int behavior,
- int requestedVisibleTypes, String packageName, int transientBarTypes,
- LetterboxDetails[] letterboxDetails) {
+ int appearance, AppearanceRegion[] appearanceRegions, int imeWindowVis,
+ int imeBackDisposition, boolean showImeSwitcher, int disabledFlags2, IBinder imeToken,
+ boolean navbarColorManagedByIme, int behavior, int requestedVisibleTypes,
+ String packageName, int transientBarTypes, LetterboxDetails[] letterboxDetails) {
mIcons = new ArrayMap<>(icons);
mDisabledFlags1 = disabledFlags1;
mAppearance = appearance;
diff --git a/core/java/com/android/internal/widget/NotificationExpandButton.java b/core/java/com/android/internal/widget/NotificationExpandButton.java
index 07ee9b5..d4dd1e7 100644
--- a/core/java/com/android/internal/widget/NotificationExpandButton.java
+++ b/core/java/com/android/internal/widget/NotificationExpandButton.java
@@ -21,6 +21,8 @@
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
import android.util.AttributeSet;
import android.view.RemotableViewMethod;
import android.view.View;
@@ -42,7 +44,7 @@
@RemoteViews.RemoteView
public class NotificationExpandButton extends FrameLayout {
- private View mPillView;
+ private Drawable mPillDrawable;
private TextView mNumberView;
private ImageView mIconView;
private boolean mExpanded;
@@ -73,7 +75,10 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mPillView = findViewById(R.id.expand_button_pill);
+
+ final View pillView = findViewById(R.id.expand_button_pill);
+ final LayerDrawable layeredPill = (LayerDrawable) pillView.getBackground();
+ mPillDrawable = layeredPill.findDrawableByLayerId(R.id.expand_button_pill_colorized_layer);
mNumberView = findViewById(R.id.expand_button_number);
mIconView = findViewById(R.id.expand_button_icon);
}
@@ -156,7 +161,7 @@
private void updateColors() {
if (shouldShowNumber()) {
if (mHighlightPillColor != 0) {
- mPillView.setBackgroundTintList(ColorStateList.valueOf(mHighlightPillColor));
+ mPillDrawable.setTintList(ColorStateList.valueOf(mHighlightPillColor));
}
mIconView.setColorFilter(mHighlightTextColor);
if (mHighlightTextColor != 0) {
@@ -164,7 +169,7 @@
}
} else {
if (mDefaultPillColor != 0) {
- mPillView.setBackgroundTintList(ColorStateList.valueOf(mDefaultPillColor));
+ mPillDrawable.setTintList(ColorStateList.valueOf(mDefaultPillColor));
}
mIconView.setColorFilter(mDefaultTextColor);
if (mDefaultTextColor != 0) {
diff --git a/core/jni/android_os_GraphicsEnvironment.cpp b/core/jni/android_os_GraphicsEnvironment.cpp
index d94b982..afc3cbd 100644
--- a/core/jni/android_os_GraphicsEnvironment.cpp
+++ b/core/jni/android_os_GraphicsEnvironment.cpp
@@ -16,11 +16,12 @@
#define LOG_TAG "GraphicsEnvironment"
-#include <vector>
-
#include <graphicsenv/GraphicsEnv.h>
#include <nativehelper/ScopedUtfChars.h>
#include <nativeloader/native_loader.h>
+
+#include <vector>
+
#include "core_jni_helpers.h"
namespace {
@@ -49,11 +50,10 @@
appPackageNameChars.c_str(), vulkanVersion);
}
-void setAngleInfo_native(JNIEnv* env, jobject clazz, jstring path, jstring packageName,
- jstring devOptIn, jobjectArray featuresObj) {
+void setAngleInfo_native(JNIEnv* env, jobject clazz, jstring path, jboolean useSystemAngle,
+ jstring packageName, jobjectArray featuresObj) {
ScopedUtfChars pathChars(env, path);
ScopedUtfChars packageNameChars(env, packageName);
- ScopedUtfChars devOptInChars(env, devOptIn);
std::vector<std::string> features;
if (featuresObj != nullptr) {
@@ -73,8 +73,8 @@
}
}
- android::GraphicsEnv::getInstance().setAngleInfo(pathChars.c_str(), packageNameChars.c_str(),
- devOptInChars.c_str(), features);
+ android::GraphicsEnv::getInstance().setAngleInfo(pathChars.c_str(), useSystemAngle,
+ packageNameChars.c_str(), features);
}
void setLayerPaths_native(JNIEnv* env, jobject clazz, jobject classLoader, jstring layerPaths) {
@@ -118,8 +118,7 @@
reinterpret_cast<void*>(setGpuStats_native)},
{"setInjectLayersPrSetDumpable", "()Z",
reinterpret_cast<void*>(setInjectLayersPrSetDumpable_native)},
- {"setAngleInfo",
- "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;)V",
+ {"setAngleInfo", "(Ljava/lang/String;ZLjava/lang/String;[Ljava/lang/String;)V",
reinterpret_cast<void*>(setAngleInfo_native)},
{"setLayerPaths", "(Ljava/lang/ClassLoader;Ljava/lang/String;)V",
reinterpret_cast<void*>(setLayerPaths_native)},
diff --git a/core/res/res/color-night/notification_expand_button_state_tint.xml b/core/res/res/color-night/notification_expand_button_state_tint.xml
new file mode 100644
index 0000000..a794d53
--- /dev/null
+++ b/core/res/res/color-night/notification_expand_button_state_tint.xml
@@ -0,0 +1,21 @@
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_pressed="true" android:color="@android:color/system_on_surface_dark" android:alpha="0.06"/>
+ <item android:state_hovered="true" android:color="@android:color/system_on_surface_dark" android:alpha="0.03"/>
+ <item android:color="@android:color/system_on_surface_dark" android:alpha="0.00"/>
+</selector>
\ No newline at end of file
diff --git a/core/res/res/color/notification_expand_button_state_tint.xml b/core/res/res/color/notification_expand_button_state_tint.xml
new file mode 100644
index 0000000..67b2c25
--- /dev/null
+++ b/core/res/res/color/notification_expand_button_state_tint.xml
@@ -0,0 +1,21 @@
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_pressed="true" android:color="@android:color/system_on_surface_light" android:alpha="0.12"/>
+ <item android:state_hovered="true" android:color="@android:color/system_on_surface_light" android:alpha="0.08"/>
+ <item android:color="@android:color/system_on_surface_light" android:alpha="0.00"/>
+</selector>
\ No newline at end of file
diff --git a/core/res/res/drawable/expand_button_pill_bg.xml b/core/res/res/drawable/expand_button_pill_bg.xml
index f95044a..a14d33c 100644
--- a/core/res/res/drawable/expand_button_pill_bg.xml
+++ b/core/res/res/drawable/expand_button_pill_bg.xml
@@ -13,7 +13,17 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<shape xmlns:android="http://schemas.android.com/apk/res/android">
- <corners android:radius="@dimen/notification_expand_button_pill_height" />
- <solid android:color="@android:color/white" />
-</shape>
\ No newline at end of file
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@+id/expand_button_pill_colorized_layer">
+ <shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <corners android:radius="@dimen/notification_expand_button_pill_height" />
+ <solid android:color="@android:color/white" />
+ </shape>
+ </item>
+ <item>
+ <shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <corners android:radius="@dimen/notification_expand_button_pill_height" />
+ <solid android:color="@color/notification_expand_button_state_tint" />
+ </shape>
+ </item>
+</layer-list>
\ No newline at end of file
diff --git a/core/res/res/layout/notification_expand_button.xml b/core/res/res/layout/notification_expand_button.xml
index 8eae064..63fe471 100644
--- a/core/res/res/layout/notification_expand_button.xml
+++ b/core/res/res/layout/notification_expand_button.xml
@@ -34,6 +34,7 @@
android:background="@drawable/expand_button_pill_bg"
android:gravity="center_vertical"
android:layout_gravity="center_vertical"
+ android:duplicateParentState="true"
>
<TextView
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index f27535c..3be0d7f 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -46,6 +46,7 @@
<item><xliff:g id="id">@string/status_bar_secure</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_managed_profile</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_cast</xliff:g></item>
+ <item><xliff:g id="id">@string/status_bar_connected_display</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_screen_record</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_vpn</xliff:g></item>
<item><xliff:g id="id">@string/status_bar_bluetooth</xliff:g></item>
@@ -72,6 +73,7 @@
<string translatable="false" name="status_bar_sync_failing">sync_failing</string>
<string translatable="false" name="status_bar_sync_active">sync_active</string>
<string translatable="false" name="status_bar_cast">cast</string>
+ <string translatable="false" name="status_bar_connected_display">connected_display</string>
<string translatable="false" name="status_bar_hotspot">hotspot</string>
<string translatable="false" name="status_bar_location">location</string>
<string translatable="false" name="status_bar_bluetooth">bluetooth</string>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 04fef58..f795bd7 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3792,7 +3792,7 @@
keyboard is connected -->
<string name="show_ime">Keep it on screen while physical keyboard is active</string>
<!-- Title of the physical keyboard category in the input method selector [CHAR LIMIT=30] -->
- <string name="hardware">Show virtual keyboard</string>
+ <string name="hardware">Use on-screen keyboard</string>
<!-- Title of the notification to prompt the user to configure physical keyboard settings. [CHAR LIMIT=NOTIF_TITLE] -->
<string name="select_keyboard_layout_notification_title">Configure <xliff:g id="device_name" example="Foobar USB Keyboard">%s</xliff:g></string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 2e5da33..85e9792 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3050,6 +3050,7 @@
<java-symbol type="id" name="header_text_secondary" />
<java-symbol type="id" name="expand_button" />
<java-symbol type="id" name="expand_button_pill" />
+ <java-symbol type="id" name="expand_button_pill_colorized_layer" />
<java-symbol type="id" name="expand_button_number" />
<java-symbol type="id" name="expand_button_icon" />
<java-symbol type="id" name="alternate_expand_target" />
@@ -3099,6 +3100,7 @@
<java-symbol type="string" name="status_bar_sync_failing" />
<java-symbol type="string" name="status_bar_sync_active" />
<java-symbol type="string" name="status_bar_cast" />
+ <java-symbol type="string" name="status_bar_connected_display" />
<java-symbol type="string" name="status_bar_hotspot" />
<java-symbol type="string" name="status_bar_location" />
<java-symbol type="string" name="status_bar_bluetooth" />
diff --git a/core/tests/coretests/src/android/widget/EditTextCursorAnchorInfoTest.java b/core/tests/coretests/src/android/widget/EditTextCursorAnchorInfoTest.java
index 1a01987..62adc20 100644
--- a/core/tests/coretests/src/android/widget/EditTextCursorAnchorInfoTest.java
+++ b/core/tests/coretests/src/android/widget/EditTextCursorAnchorInfoTest.java
@@ -30,6 +30,7 @@
import android.view.Gravity;
import android.view.View;
import android.view.inputmethod.CursorAnchorInfo;
+import android.view.inputmethod.EditorBoundsInfo;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry;
@@ -54,8 +55,15 @@
private static final int[] sLocationOnScreen = new int[2];
private static Typeface sTypeface;
private static final float TEXT_SIZE = 1f;
- // The line height of the test font font is 1.2 * textSize.
+ // The line height of the test font is 1.2 * textSize.
private static final int LINE_HEIGHT = 12;
+ private static final int HW_BOUNDS_OFFSET_LEFT = 10;
+ private static final int HW_BOUNDS_OFFSET_TOP = 20;
+ private static final int HW_BOUNDS_OFFSET_RIGHT = 30;
+ private static final int HW_BOUNDS_OFFSET_BOTTOM = 40;
+
+
+ // Default text has 5 lines of text. The needed width is 50px and the needed height is 60px.
private static final CharSequence DEFAULT_TEXT = "X\nXX\nXXX\nXXXX\nXXXXX";
private static final ImmutableList<RectF> DEFAULT_LINE_BOUNDS = ImmutableList.of(
new RectF(0f, 0f, 10f, LINE_HEIGHT),
@@ -131,6 +139,55 @@
}
@Test
+ public void testEditorBoundsInfo_allVisible() {
+ // The needed width and height of the DEFAULT_TEXT are 50 px and 60 px respectfully.
+ int width = 100;
+ int height = 200;
+ setupEditText(DEFAULT_TEXT, width, height);
+ CursorAnchorInfo cursorAnchorInfo =
+ mEditText.getCursorAnchorInfo(0, sCursorAnchorInfoBuilder, sMatrix);
+ EditorBoundsInfo editorBoundsInfo = cursorAnchorInfo.getEditorBoundsInfo();
+ assertThat(editorBoundsInfo).isNotNull();
+ assertThat(editorBoundsInfo.getEditorBounds()).isEqualTo(new RectF(0, 0, width, height));
+ assertThat(editorBoundsInfo.getHandwritingBounds())
+ .isEqualTo(new RectF(-HW_BOUNDS_OFFSET_LEFT, -HW_BOUNDS_OFFSET_TOP,
+ width + HW_BOUNDS_OFFSET_RIGHT, height + HW_BOUNDS_OFFSET_BOTTOM));
+ }
+
+ @Test
+ public void testEditorBoundsInfo_scrolled() {
+ // The height of the editor will be 60 px.
+ int width = 100;
+ int visibleTop = 10;
+ int visibleBottom = 30;
+ setupVerticalClippedEditText(width, visibleTop, visibleBottom);
+ CursorAnchorInfo cursorAnchorInfo =
+ mEditText.getCursorAnchorInfo(0, sCursorAnchorInfoBuilder, sMatrix);
+ EditorBoundsInfo editorBoundsInfo = cursorAnchorInfo.getEditorBoundsInfo();
+ assertThat(editorBoundsInfo).isNotNull();
+ assertThat(editorBoundsInfo.getEditorBounds())
+ .isEqualTo(new RectF(0, visibleTop, width, visibleBottom));
+ assertThat(editorBoundsInfo.getHandwritingBounds())
+ .isEqualTo(new RectF(-HW_BOUNDS_OFFSET_LEFT, visibleTop - HW_BOUNDS_OFFSET_TOP,
+ width + HW_BOUNDS_OFFSET_RIGHT, visibleBottom + HW_BOUNDS_OFFSET_BOTTOM));
+ }
+
+ @Test
+ public void testEditorBoundsInfo_invisible() {
+ // The height of the editor will be 60px. Scroll it to 70px will make it invisible.
+ int width = 100;
+ int visibleTop = 70;
+ int visibleBottom = 70;
+ setupVerticalClippedEditText(width, visibleTop, visibleBottom);
+ CursorAnchorInfo cursorAnchorInfo =
+ mEditText.getCursorAnchorInfo(0, sCursorAnchorInfoBuilder, sMatrix);
+ EditorBoundsInfo editorBoundsInfo = cursorAnchorInfo.getEditorBoundsInfo();
+ assertThat(editorBoundsInfo).isNotNull();
+ assertThat(editorBoundsInfo.getEditorBounds()).isEqualTo(new RectF(0, 0, 0, 0));
+ assertThat(editorBoundsInfo.getHandwritingBounds()).isEqualTo(new RectF(0, 0, 0, 0));
+ }
+
+ @Test
public void testVisibleLineBounds_allVisible() {
setupEditText(DEFAULT_TEXT, /* height= */ 100);
CursorAnchorInfo cursorAnchorInfo =
@@ -465,32 +522,26 @@
}
private void setupVerticalClippedEditText(int visibleTop, int visibleBottom) {
+ setupVerticalClippedEditText(1000, visibleTop, visibleBottom);
+ }
+
+ /**
+ * Helper method to create an EditText in a vertical ScrollView so that its visible bounds
+ * is Rect(0, visibleTop, width, visibleBottom) in the EditText's coordinates. Both ScrollView
+ * and EditText's width is set to the given width.
+ */
+ private void setupVerticalClippedEditText(int width, int visibleTop, int visibleBottom) {
ScrollView scrollView = new ScrollView(mActivity);
- mEditText = new EditText(mActivity);
- mEditText.setTypeface(sTypeface);
- mEditText.setText(DEFAULT_TEXT);
- mEditText.setTextSize(TypedValue.COMPLEX_UNIT_PX, TEXT_SIZE);
-
- mEditText.setPadding(0, 0, 0, 0);
- mEditText.setCompoundDrawables(null, null, null, null);
- mEditText.setCompoundDrawablePadding(0);
-
- mEditText.scrollTo(0, 0);
- mEditText.setLineSpacing(0f, 1f);
-
- // Place the text layout top to the view's top.
- mEditText.setGravity(Gravity.TOP);
- int width = 1000;
- int height = visibleBottom - visibleTop;
+ createEditText();
+ int scrollViewHeight = visibleBottom - visibleTop;
scrollView.addView(mEditText, new FrameLayout.LayoutParams(
View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(5 * LINE_HEIGHT, View.MeasureSpec.EXACTLY)));
scrollView.measure(
View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
- View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY));
- scrollView.layout(0, 0, width, height);
-
+ View.MeasureSpec.makeMeasureSpec(scrollViewHeight, View.MeasureSpec.EXACTLY));
+ scrollView.layout(0, 0, width, scrollViewHeight);
scrollView.scrollTo(0, visibleTop);
}
@@ -499,6 +550,11 @@
measureEditText(height);
}
+ private void setupEditText(CharSequence text, int width, int height) {
+ createEditText(text);
+ measureEditText(width, height);
+ }
+
private void setupEditText(CharSequence text, int height, float lineSpacing,
float lineMultiplier) {
createEditText(text);
@@ -537,6 +593,8 @@
mEditText.setTypeface(sTypeface);
mEditText.setText(text);
mEditText.setTextSize(TypedValue.COMPLEX_UNIT_PX, TEXT_SIZE);
+ mEditText.setHandwritingBoundsOffsets(HW_BOUNDS_OFFSET_LEFT, HW_BOUNDS_OFFSET_TOP,
+ HW_BOUNDS_OFFSET_RIGHT, HW_BOUNDS_OFFSET_BOTTOM);
mEditText.setPadding(0, 0, 0, 0);
mEditText.setCompoundDrawables(null, null, null, null);
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index 2e3f604..14e8253 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -419,4 +419,8 @@
<dimen name="freeform_resize_handle">15dp</dimen>
<dimen name="freeform_resize_corner">44dp</dimen>
+
+ <!-- The height of the area at the top of the screen where a freeform task will transition to
+ fullscreen if dragged until the top bound of the task is within the area. -->
+ <dimen name="desktop_mode_transition_area_height">16dp</dimen>
</resources>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index 65a35b2..4fda4b7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -100,6 +100,10 @@
}
}
+ private val transitionAreaHeight
+ get() = context.resources.getDimensionPixelSize(
+ com.android.wm.shell.R.dimen.desktop_mode_transition_area_height)
+
init {
desktopMode = DesktopModeImpl()
if (DesktopModeStatus.isProto2Enabled()) {
@@ -700,13 +704,12 @@
y: Float
) {
if (taskInfo.windowingMode == WINDOWING_MODE_FREEFORM) {
- val statusBarHeight = getStatusBarHeight(taskInfo)
- if (y <= statusBarHeight && visualIndicator == null) {
+ if (y <= transitionAreaHeight && visualIndicator == null) {
visualIndicator = DesktopModeVisualIndicator(syncQueue, taskInfo,
displayController, context, taskSurface, shellTaskOrganizer,
rootTaskDisplayAreaOrganizer)
visualIndicator?.createFullscreenIndicatorWithAnimatedBounds()
- } else if (y > statusBarHeight && visualIndicator != null) {
+ } else if (y > transitionAreaHeight && visualIndicator != null) {
releaseVisualIndicator()
}
}
@@ -726,8 +729,7 @@
y: Float,
windowDecor: DesktopModeWindowDecoration
) {
- val statusBarHeight = getStatusBarHeight(taskInfo)
- if (y <= statusBarHeight && taskInfo.windowingMode == WINDOWING_MODE_FREEFORM) {
+ if (y <= transitionAreaHeight && taskInfo.windowingMode == WINDOWING_MODE_FREEFORM) {
windowDecor.incrementRelayoutBlock()
moveToFullscreenWithAnimation(taskInfo, position)
}
@@ -746,9 +748,9 @@
taskSurface: SurfaceControl,
y: Float
) {
- // If the motion event is above the status bar, return since we do not need to show the
- // visual indicator at this point.
- if (y < getStatusBarHeight(taskInfo)) {
+ // If the motion event is above the status bar and the visual indicator is not yet visible,
+ // return since we do not need to show the visual indicator at this point.
+ if (y < getStatusBarHeight(taskInfo) && visualIndicator == null) {
return
}
if (visualIndicator == null) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index d8a8877..7565996 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -27,6 +27,7 @@
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static android.view.WindowManager.fixScale;
+import static android.window.TransitionInfo.FLAG_IS_BEHIND_STARTING_WINDOW;
import static android.window.TransitionInfo.FLAG_IS_OCCLUDED;
import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
import static android.window.TransitionInfo.FLAG_MOVED_TO_TOP;
@@ -728,11 +729,15 @@
final int changeSize = info.getChanges().size();
boolean taskChange = false;
boolean transferStartingWindow = false;
+ int noAnimationBehindStartingWindow = 0;
boolean allOccluded = changeSize > 0;
for (int i = changeSize - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i);
taskChange |= change.getTaskInfo() != null;
transferStartingWindow |= change.hasFlags(FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT);
+ if (change.hasAllFlags(FLAG_IS_BEHIND_STARTING_WINDOW | FLAG_NO_ANIMATION)) {
+ noAnimationBehindStartingWindow++;
+ }
if (!change.hasFlags(FLAG_IS_OCCLUDED)) {
allOccluded = false;
}
@@ -740,9 +745,11 @@
// There does not need animation when:
// A. Transfer starting window. Apply transfer starting window directly if there is no other
// task change. Since this is an activity->activity situation, we can detect it by selecting
- // transitions with only 2 changes where neither are tasks and one is a starting-window
- // recipient.
- if (!taskChange && transferStartingWindow && changeSize == 2
+ // transitions with only 2 changes where
+ // 1. neither are tasks, and
+ // 2. one is a starting-window recipient, or all change is behind starting window.
+ if (!taskChange && (transferStartingWindow || noAnimationBehindStartingWindow == changeSize)
+ && changeSize == 2
// B. It's visibility change if the TRANSIT_TO_BACK/TO_FRONT happened when all
// changes are underneath another change.
|| ((info.getType() == TRANSIT_TO_BACK || info.getType() == TRANSIT_TO_FRONT)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
index 92c2a7c..cf16920 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
@@ -193,7 +193,7 @@
final DragPositioningCallback dragPositioningCallback =
new FluidResizeTaskPositioner(mTaskOrganizer, windowDecoration, mDisplayController,
- null /* disallowedAreaForEndBounds */);
+ 0 /* disallowedAreaForEndBoundsHeight */);
final CaptionTouchEventListener touchEventListener =
new CaptionTouchEventListener(taskInfo, dragPositioningCallback);
windowDecoration.setCaptionListeners(touchEventListener, touchEventListener);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
index 331835c..7245bc9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
@@ -845,7 +845,7 @@
windowDecoration.createResizeVeil();
final DragPositioningCallback dragPositioningCallback = createDragPositioningCallback(
- windowDecoration, taskInfo);
+ windowDecoration);
final DesktopModeTouchEventListener touchEventListener =
new DesktopModeTouchEventListener(taskInfo, dragPositioningCallback);
@@ -858,24 +858,17 @@
incrementEventReceiverTasks(taskInfo.displayId);
}
private DragPositioningCallback createDragPositioningCallback(
- @NonNull DesktopModeWindowDecoration windowDecoration,
- @NonNull RunningTaskInfo taskInfo) {
- final int screenWidth = mDisplayController.getDisplayLayout(taskInfo.displayId).width();
- final Rect disallowedAreaForEndBounds;
- if (DesktopModeStatus.isProto2Enabled()) {
- disallowedAreaForEndBounds = new Rect(0, 0, screenWidth,
- getStatusBarHeight(taskInfo.displayId));
- } else {
- disallowedAreaForEndBounds = null;
- }
+ @NonNull DesktopModeWindowDecoration windowDecoration) {
+ final int transitionAreaHeight = mContext.getResources().getDimensionPixelSize(
+ R.dimen.desktop_mode_transition_area_height);
if (!DesktopModeStatus.isVeiledResizeEnabled()) {
return new FluidResizeTaskPositioner(mTaskOrganizer, windowDecoration,
- mDisplayController, disallowedAreaForEndBounds, mDragStartListener,
- mTransactionFactory);
+ mDisplayController, mDragStartListener, mTransactionFactory,
+ transitionAreaHeight);
} else {
return new VeiledResizeTaskPositioner(mTaskOrganizer, windowDecoration,
- mDisplayController, disallowedAreaForEndBounds, mDragStartListener,
- mTransitions);
+ mDisplayController, mDragStartListener, mTransitions,
+ transitionAreaHeight);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtility.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtility.java
index 09e29bc..e32bd42 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtility.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtility.java
@@ -83,8 +83,6 @@
// Make sure the new resizing destination in any direction falls within the stable bounds.
// If not, set the bounds back to the old location that was valid to avoid conflicts with
// some regions such as the gesture area.
- displayController.getDisplayLayout(windowDecoration.mDisplay.getDisplayId())
- .getStableBounds(stableBounds);
if ((ctrlType & CTRL_TYPE_LEFT) != 0) {
final int candidateLeft = repositionTaskBounds.left + (int) delta.x;
repositionTaskBounds.left = (candidateLeft > stableBounds.left)
@@ -136,7 +134,7 @@
repositionTaskBounds.top);
}
- static void updateTaskBounds(Rect repositionTaskBounds, Rect taskBoundsAtDragStart,
+ private static void updateTaskBounds(Rect repositionTaskBounds, Rect taskBoundsAtDragStart,
PointF repositionStartPoint, float x, float y) {
final float deltaX = x - repositionStartPoint.x;
final float deltaY = y - repositionStartPoint.y;
@@ -145,6 +143,23 @@
}
/**
+ * Updates repositionTaskBounds to the final bounds of the task after the drag is finished. If
+ * the bounds are outside of the stable bounds, they are shifted to place task at the top of the
+ * stable bounds.
+ */
+ static void onDragEnd(Rect repositionTaskBounds, Rect taskBoundsAtDragStart, Rect stableBounds,
+ PointF repositionStartPoint, float x, float y) {
+ updateTaskBounds(repositionTaskBounds, taskBoundsAtDragStart, repositionStartPoint,
+ x, y);
+
+ // If task is outside of stable bounds (in the status bar area), shift the task down.
+ if (stableBounds.top > repositionTaskBounds.top) {
+ final int yShift = stableBounds.top - repositionTaskBounds.top;
+ repositionTaskBounds.offset(0, yShift);
+ }
+ }
+
+ /**
* Apply a bounds change to a task.
* @param windowDecoration decor of task we are changing bounds for
* @param taskBounds new bounds of this task
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositioner.java
index 9082323..917abf5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositioner.java
@@ -21,8 +21,6 @@
import android.view.SurfaceControl;
import android.window.WindowContainerTransaction;
-import androidx.annotation.Nullable;
-
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
@@ -42,28 +40,31 @@
private final Rect mTaskBoundsAtDragStart = new Rect();
private final PointF mRepositionStartPoint = new PointF();
private final Rect mRepositionTaskBounds = new Rect();
- // If a task move (not resize) finishes in this region, the positioner will not attempt to
+ // If a task move (not resize) finishes with the positions y less than this value, do not
// finalize the bounds there using WCT#setBounds
- private final Rect mDisallowedAreaForEndBounds;
+ private final int mDisallowedAreaForEndBoundsHeight;
private boolean mHasDragResized;
private int mCtrlType;
FluidResizeTaskPositioner(ShellTaskOrganizer taskOrganizer, WindowDecoration windowDecoration,
- DisplayController displayController, @Nullable Rect disallowedAreaForEndBounds) {
- this(taskOrganizer, windowDecoration, displayController, disallowedAreaForEndBounds,
- dragStartListener -> {}, SurfaceControl.Transaction::new);
+ DisplayController displayController, int disallowedAreaForEndBoundsHeight) {
+ this(taskOrganizer, windowDecoration, displayController, dragStartListener -> {},
+ SurfaceControl.Transaction::new, disallowedAreaForEndBoundsHeight);
}
FluidResizeTaskPositioner(ShellTaskOrganizer taskOrganizer, WindowDecoration windowDecoration,
- DisplayController displayController, @Nullable Rect disallowedAreaForEndBounds,
+ DisplayController displayController,
DragPositioningCallbackUtility.DragStartListener dragStartListener,
- Supplier<SurfaceControl.Transaction> supplier) {
+ Supplier<SurfaceControl.Transaction> supplier,
+ int disallowedAreaForEndBoundsHeight) {
mTaskOrganizer = taskOrganizer;
mWindowDecoration = windowDecoration;
mDisplayController = displayController;
- mDisallowedAreaForEndBounds = new Rect(disallowedAreaForEndBounds);
mDragStartListener = dragStartListener;
mTransactionSupplier = supplier;
+ mDisallowedAreaForEndBoundsHeight = disallowedAreaForEndBoundsHeight;
+ mDisplayController.getDisplayLayout(windowDecoration.mDisplay.getDisplayId())
+ .getStableBounds(mStableBounds);
}
@Override
@@ -121,10 +122,10 @@
}
mTaskOrganizer.applyTransaction(wct);
} else if (mCtrlType == CTRL_TYPE_UNDEFINED
- && !mDisallowedAreaForEndBounds.contains((int) x, (int) y)) {
+ && y > mDisallowedAreaForEndBoundsHeight) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
- DragPositioningCallbackUtility.updateTaskBounds(mRepositionTaskBounds,
- mTaskBoundsAtDragStart, mRepositionStartPoint, x, y);
+ DragPositioningCallbackUtility.onDragEnd(mRepositionTaskBounds,
+ mTaskBoundsAtDragStart, mStableBounds, mRepositionStartPoint, x, y);
wct.setBounds(mWindowDecoration.mTaskInfo.token, mRepositionTaskBounds);
mTaskOrganizer.applyTransaction(wct);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java
index 39b9021..bf3ff3f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java
@@ -53,33 +53,35 @@
private final Rect mTaskBoundsAtDragStart = new Rect();
private final PointF mRepositionStartPoint = new PointF();
private final Rect mRepositionTaskBounds = new Rect();
- // If a task move (not resize) finishes in this region, the positioner will not attempt to
+ // If a task move (not resize) finishes with the positions y less than this value, do not
// finalize the bounds there using WCT#setBounds
- private final Rect mDisallowedAreaForEndBounds;
+ private final int mDisallowedAreaForEndBoundsHeight;
private final Supplier<SurfaceControl.Transaction> mTransactionSupplier;
private int mCtrlType;
public VeiledResizeTaskPositioner(ShellTaskOrganizer taskOrganizer,
DesktopModeWindowDecoration windowDecoration, DisplayController displayController,
- Rect disallowedAreaForEndBounds,
DragPositioningCallbackUtility.DragStartListener dragStartListener,
- Transitions transitions) {
- this(taskOrganizer, windowDecoration, displayController, disallowedAreaForEndBounds,
- dragStartListener, SurfaceControl.Transaction::new, transitions);
+ Transitions transitions,
+ int disallowedAreaForEndBoundsHeight) {
+ this(taskOrganizer, windowDecoration, displayController, dragStartListener,
+ SurfaceControl.Transaction::new, transitions, disallowedAreaForEndBoundsHeight);
}
public VeiledResizeTaskPositioner(ShellTaskOrganizer taskOrganizer,
DesktopModeWindowDecoration windowDecoration, DisplayController displayController,
- Rect disallowedAreaForEndBounds,
DragPositioningCallbackUtility.DragStartListener dragStartListener,
- Supplier<SurfaceControl.Transaction> supplier, Transitions transitions) {
+ Supplier<SurfaceControl.Transaction> supplier, Transitions transitions,
+ int disallowedAreaForEndBoundsHeight) {
mTaskOrganizer = taskOrganizer;
mDesktopWindowDecoration = windowDecoration;
mDisplayController = displayController;
mDragStartListener = dragStartListener;
- mDisallowedAreaForEndBounds = new Rect(disallowedAreaForEndBounds);
mTransactionSupplier = supplier;
mTransitions = transitions;
+ mDisallowedAreaForEndBoundsHeight = disallowedAreaForEndBoundsHeight;
+ mDisplayController.getDisplayLayout(windowDecoration.mDisplay.getDisplayId())
+ .getStableBounds(mStableBounds);
}
@Override
@@ -110,8 +112,7 @@
} else if (mCtrlType == CTRL_TYPE_UNDEFINED) {
final SurfaceControl.Transaction t = mTransactionSupplier.get();
DragPositioningCallbackUtility.setPositionOnDrag(mDesktopWindowDecoration,
- mRepositionTaskBounds, mTaskBoundsAtDragStart, mRepositionStartPoint, t,
- x, y);
+ mRepositionTaskBounds, mTaskBoundsAtDragStart, mRepositionStartPoint, t, x, y);
t.apply();
}
}
@@ -138,9 +139,9 @@
// won't be called.
mDesktopWindowDecoration.hideResizeVeil();
}
- } else if (!mDisallowedAreaForEndBounds.contains((int) x, (int) y)) {
- DragPositioningCallbackUtility.updateTaskBounds(mRepositionTaskBounds,
- mTaskBoundsAtDragStart, mRepositionStartPoint, x, y);
+ } else if (y > mDisallowedAreaForEndBoundsHeight) {
+ DragPositioningCallbackUtility.onDragEnd(mRepositionTaskBounds,
+ mTaskBoundsAtDragStart, mStableBounds, mRepositionStartPoint, x, y);
DragPositioningCallbackUtility.applyTaskBoundsChange(new WindowContainerTransaction(),
mDesktopWindowDecoration, mRepositionTaskBounds, mTaskOrganizer);
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenUtils.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenUtils.kt
index 27eaa40..f4828f1 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenUtils.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenUtils.kt
@@ -326,14 +326,14 @@
dividerBar.drag(
Point(
if (dragToRight) {
- displayBounds.width * 4 / 5
+ displayBounds.right
} else {
- displayBounds.width * 1 / 5
+ displayBounds.left
},
if (dragToBottom) {
- displayBounds.height * 4 / 5
+ displayBounds.bottom
} else {
- displayBounds.height * 1 / 5
+ displayBounds.top
}
)
)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.java
index 23158ea..adc2a6f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.java
@@ -90,6 +90,7 @@
@Mock private DesktopModeWindowDecorViewModel.InputMonitorFactory mMockInputMonitorFactory;
@Mock private Supplier<SurfaceControl.Transaction> mTransactionFactory;
@Mock private SurfaceControl.Transaction mTransaction;
+ @Mock private Display mDisplay;
private final List<InputManager> mMockInputManagers = new ArrayList<>();
private DesktopModeWindowDecorViewModel mDesktopModeWindowDecorViewModel;
@@ -126,6 +127,9 @@
final InputChannel[] inputChannels = InputChannel.openInputChannelPair(TAG);
inputChannels[0].dispose();
when(mInputMonitor.getInputChannel()).thenReturn(inputChannels[1]);
+
+ mDesktopModeWindowDecoration.mDisplay = mDisplay;
+ doReturn(Display.DEFAULT_DISPLAY).when(mDisplay).getDisplayId();
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt
index 69604dd..6f0599a 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt
@@ -22,6 +22,7 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.eq
import org.mockito.Mock
import org.mockito.Mockito.any
import org.mockito.Mockito.argThat
@@ -71,16 +72,6 @@
fun setUp() {
MockitoAnnotations.initMocks(this)
- taskPositioner =
- FluidResizeTaskPositioner(
- mockShellTaskOrganizer,
- mockWindowDecoration,
- mockDisplayController,
- DISALLOWED_AREA_FOR_END_BOUNDS,
- mockDragStartListener,
- mockTransactionFactory
- )
-
whenever(taskToken.asBinder()).thenReturn(taskBinder)
whenever(mockDisplayController.getDisplayLayout(DISPLAY_ID)).thenReturn(mockDisplayLayout)
whenever(mockDisplayLayout.densityDpi()).thenReturn(DENSITY_DPI)
@@ -101,6 +92,15 @@
}
mockWindowDecoration.mDisplay = mockDisplay
whenever(mockDisplay.displayId).thenAnswer { DISPLAY_ID }
+
+ taskPositioner = FluidResizeTaskPositioner(
+ mockShellTaskOrganizer,
+ mockWindowDecoration,
+ mockDisplayController,
+ mockDragStartListener,
+ mockTransactionFactory,
+ DISALLOWED_AREA_FOR_END_BOUNDS_HEIGHT
+ )
}
@Test
@@ -544,7 +544,7 @@
)
val newX = STARTING_BOUNDS.right.toFloat() + 5
- val newY = STARTING_BOUNDS.top.toFloat() + 5
+ val newY = DISALLOWED_AREA_FOR_END_BOUNDS_HEIGHT.toFloat() - 1
taskPositioner.onDragPositioningMove(
newX,
newY
@@ -614,6 +614,38 @@
})
}
+ @Test
+ fun testDragResize_drag_taskPositionedInStableBounds() {
+ taskPositioner.onDragPositioningStart(
+ CTRL_TYPE_UNDEFINED, // drag
+ STARTING_BOUNDS.left.toFloat(),
+ STARTING_BOUNDS.top.toFloat()
+ )
+
+ val newX = STARTING_BOUNDS.left.toFloat()
+ val newY = STABLE_BOUNDS.top.toFloat() - 5
+ taskPositioner.onDragPositioningMove(
+ newX,
+ newY
+ )
+ verify(mockTransaction).setPosition(any(), eq(newX), eq(newY))
+
+ taskPositioner.onDragPositioningEnd(
+ newX,
+ newY
+ )
+ // Verify task's top bound is set to stable bounds top since dragged outside stable bounds
+ // but not in disallowed end bounds area.
+ verify(mockShellTaskOrganizer).applyTransaction(argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder &&
+ (change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0 &&
+ change.configuration.windowConfiguration.bounds.top ==
+ STABLE_BOUNDS.top
+ }
+ })
+ }
+
companion object {
private const val TASK_ID = 5
private const val MIN_WIDTH = 10
@@ -622,10 +654,11 @@
private const val DEFAULT_MIN = 40
private const val DISPLAY_ID = 1
private const val NAVBAR_HEIGHT = 50
+ private const val CAPTION_HEIGHT = 50
+ private const val DISALLOWED_AREA_FOR_END_BOUNDS_HEIGHT = 10
private val DISPLAY_BOUNDS = Rect(0, 0, 2400, 1600)
- private val STARTING_BOUNDS = Rect(0, 0, 100, 100)
+ private val STARTING_BOUNDS = Rect(100, 100, 200, 200)
private val STABLE_INSETS = Rect(0, 50, 0, 0)
- private val DISALLOWED_AREA_FOR_END_BOUNDS = Rect(0, 0, 300, 300)
private val DISALLOWED_RESIZE_AREA = Rect(
DISPLAY_BOUNDS.left,
DISPLAY_BOUNDS.bottom - NAVBAR_HEIGHT,
@@ -633,7 +666,7 @@
DISPLAY_BOUNDS.bottom)
private val STABLE_BOUNDS = Rect(
DISPLAY_BOUNDS.left,
- DISPLAY_BOUNDS.top,
+ DISPLAY_BOUNDS.top + CAPTION_HEIGHT,
DISPLAY_BOUNDS.right,
DISPLAY_BOUNDS.bottom - NAVBAR_HEIGHT
)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt
index 4147dd8..3465ddd 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt
@@ -89,17 +89,6 @@
fun setUp() {
MockitoAnnotations.initMocks(this)
- taskPositioner =
- VeiledResizeTaskPositioner(
- mockShellTaskOrganizer,
- mockDesktopWindowDecoration,
- mockDisplayController,
- DISALLOWED_AREA_FOR_END_BOUNDS,
- mockDragStartListener,
- mockTransactionFactory,
- mockTransitions
- )
-
whenever(taskToken.asBinder()).thenReturn(taskBinder)
whenever(mockDisplayController.getDisplayLayout(DISPLAY_ID)).thenReturn(mockDisplayLayout)
whenever(mockDisplayLayout.densityDpi()).thenReturn(DENSITY_DPI)
@@ -119,6 +108,17 @@
}
mockDesktopWindowDecoration.mDisplay = mockDisplay
whenever(mockDisplay.displayId).thenAnswer { DISPLAY_ID }
+
+ taskPositioner =
+ VeiledResizeTaskPositioner(
+ mockShellTaskOrganizer,
+ mockDesktopWindowDecoration,
+ mockDisplayController,
+ mockDragStartListener,
+ mockTransactionFactory,
+ mockTransitions,
+ DISALLOWED_AREA_FOR_END_BOUNDS_HEIGHT
+ )
}
@Test
@@ -269,7 +269,7 @@
)
val newX = STARTING_BOUNDS.left.toFloat() + 5
- val newY = STARTING_BOUNDS.top.toFloat() + 5
+ val newY = DISALLOWED_AREA_FOR_END_BOUNDS_HEIGHT.toFloat() - 1
taskPositioner.onDragPositioningMove(
newX,
newY
@@ -334,6 +334,38 @@
})
}
+ @Test
+ fun testDragResize_drag_taskPositionedInStableBounds() {
+ taskPositioner.onDragPositioningStart(
+ CTRL_TYPE_UNDEFINED, // drag
+ STARTING_BOUNDS.left.toFloat(),
+ STARTING_BOUNDS.top.toFloat()
+ )
+
+ val newX = STARTING_BOUNDS.left.toFloat()
+ val newY = STABLE_BOUNDS.top.toFloat() - 5
+ taskPositioner.onDragPositioningMove(
+ newX,
+ newY
+ )
+ verify(mockTransaction).setPosition(any(), eq(newX), eq(newY))
+
+ taskPositioner.onDragPositioningEnd(
+ newX,
+ newY
+ )
+ // Verify task's top bound is set to stable bounds top since dragged outside stable bounds
+ // but not in disallowed end bounds area.
+ verify(mockShellTaskOrganizer).applyTransaction(argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder &&
+ (change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0 &&
+ change.configuration.windowConfiguration.bounds.top ==
+ STABLE_BOUNDS.top
+ }
+ })
+ }
+
companion object {
private const val TASK_ID = 5
private const val MIN_WIDTH = 10
@@ -342,12 +374,13 @@
private const val DEFAULT_MIN = 40
private const val DISPLAY_ID = 1
private const val NAVBAR_HEIGHT = 50
+ private const val CAPTION_HEIGHT = 50
+ private const val DISALLOWED_AREA_FOR_END_BOUNDS_HEIGHT = 10
private val DISPLAY_BOUNDS = Rect(0, 0, 2400, 1600)
- private val STARTING_BOUNDS = Rect(0, 0, 100, 100)
- private val DISALLOWED_AREA_FOR_END_BOUNDS = Rect(0, 0, 50, 50)
+ private val STARTING_BOUNDS = Rect(100, 100, 200, 200)
private val STABLE_BOUNDS = Rect(
DISPLAY_BOUNDS.left,
- DISPLAY_BOUNDS.top,
+ DISPLAY_BOUNDS.top + CAPTION_HEIGHT,
DISPLAY_BOUNDS.right,
DISPLAY_BOUNDS.bottom - NAVBAR_HEIGHT
)
diff --git a/libs/hwui/pipeline/skia/ShaderCache.cpp b/libs/hwui/pipeline/skia/ShaderCache.cpp
index 00919dc..f71e728 100644
--- a/libs/hwui/pipeline/skia/ShaderCache.cpp
+++ b/libs/hwui/pipeline/skia/ShaderCache.cpp
@@ -79,7 +79,7 @@
void ShaderCache::initShaderDiskCache(const void* identity, ssize_t size) {
ATRACE_NAME("initShaderDiskCache");
- std::lock_guard<std::mutex> lock(mMutex);
+ std::lock_guard lock(mMutex);
// Emulators can switch between different renders either as part of config
// or snapshot migration. Also, program binaries may not work well on some
@@ -92,7 +92,7 @@
}
void ShaderCache::setFilename(const char* filename) {
- std::lock_guard<std::mutex> lock(mMutex);
+ std::lock_guard lock(mMutex);
mFilename = filename;
}
@@ -104,7 +104,7 @@
sk_sp<SkData> ShaderCache::load(const SkData& key) {
ATRACE_NAME("ShaderCache::load");
size_t keySize = key.size();
- std::lock_guard<std::mutex> lock(mMutex);
+ std::lock_guard lock(mMutex);
if (!mInitialized) {
return nullptr;
}
@@ -181,13 +181,18 @@
auto key = sIDKey;
set(mBlobCache.get(), &key, sizeof(key), mIDHash.data(), mIDHash.size());
}
+ // The most straightforward way to make ownership shared
+ mMutex.unlock();
+ mMutex.lock_shared();
mBlobCache->writeToFile();
+ mMutex.unlock_shared();
+ mMutex.lock();
}
}
void ShaderCache::store(const SkData& key, const SkData& data, const SkString& /*description*/) {
ATRACE_NAME("ShaderCache::store");
- std::lock_guard<std::mutex> lock(mMutex);
+ std::lock_guard lock(mMutex);
mNumShadersCachedInRam++;
ATRACE_FORMAT("HWUI RAM cache: %d shaders", mNumShadersCachedInRam);
@@ -229,7 +234,7 @@
mSavePending = true;
std::thread deferredSaveThread([this]() {
usleep(mDeferredSaveDelayMs * 1000); // milliseconds to microseconds
- std::lock_guard<std::mutex> lock(mMutex);
+ std::lock_guard lock(mMutex);
// Store file on disk if there a new shader or Vulkan pipeline cache size changed.
if (mCacheDirty || mNewPipelineCacheSize != mOldPipelineCacheSize) {
saveToDiskLocked();
@@ -245,11 +250,12 @@
void ShaderCache::onVkFrameFlushed(GrDirectContext* context) {
{
- std::lock_guard<std::mutex> lock(mMutex);
-
+ mMutex.lock_shared();
if (!mInitialized || !mTryToStorePipelineCache) {
+ mMutex.unlock_shared();
return;
}
+ mMutex.unlock_shared();
}
mInStoreVkPipelineInProgress = true;
context->storeVkPipelineCacheData();
diff --git a/libs/hwui/pipeline/skia/ShaderCache.h b/libs/hwui/pipeline/skia/ShaderCache.h
index f5506d6..2f91c77 100644
--- a/libs/hwui/pipeline/skia/ShaderCache.h
+++ b/libs/hwui/pipeline/skia/ShaderCache.h
@@ -19,8 +19,10 @@
#include <GrContextOptions.h>
#include <SkRefCnt.h>
#include <cutils/compiler.h>
+#include <ftl/shared_mutex.h>
+#include <utils/Mutex.h>
+
#include <memory>
-#include <mutex>
#include <string>
#include <vector>
@@ -99,20 +101,20 @@
* this will do so, loading the serialized cache contents from disk if
* possible.
*/
- BlobCache* getBlobCacheLocked();
+ BlobCache* getBlobCacheLocked() REQUIRES(mMutex);
/**
* "validateCache" updates the cache to match the given identity. If the
* cache currently has the wrong identity, all entries in the cache are cleared.
*/
- bool validateCache(const void* identity, ssize_t size);
+ bool validateCache(const void* identity, ssize_t size) REQUIRES(mMutex);
/**
- * "saveToDiskLocked" attemps to save the current contents of the cache to
+ * "saveToDiskLocked" attempts to save the current contents of the cache to
* disk. If the identity hash exists, we will insert the identity hash into
* the cache for next validation.
*/
- void saveToDiskLocked();
+ void saveToDiskLocked() REQUIRES(mMutex);
/**
* "mInitialized" indicates whether the ShaderCache is in the initialized
@@ -122,7 +124,7 @@
* the load and store methods will return without performing any cache
* operations.
*/
- bool mInitialized = false;
+ bool mInitialized GUARDED_BY(mMutex) = false;
/**
* "mBlobCache" is the cache in which the key/value blob pairs are stored. It
@@ -131,7 +133,7 @@
* The blob cache contains the Android build number. We treat version mismatches as an empty
* cache (logic implemented in BlobCache::unflatten).
*/
- std::unique_ptr<FileBlobCache> mBlobCache;
+ std::unique_ptr<FileBlobCache> mBlobCache GUARDED_BY(mMutex);
/**
* "mFilename" is the name of the file for storing cache contents in between
@@ -140,7 +142,7 @@
* empty string indicates that the cache should not be saved to or restored
* from disk.
*/
- std::string mFilename;
+ std::string mFilename GUARDED_BY(mMutex);
/**
* "mIDHash" is the current identity hash for the cache validation. It is
@@ -149,7 +151,7 @@
* indicates that cache validation is not performed, and the hash should
* not be stored on disk.
*/
- std::vector<uint8_t> mIDHash;
+ std::vector<uint8_t> mIDHash GUARDED_BY(mMutex);
/**
* "mSavePending" indicates whether or not a deferred save operation is
@@ -159,7 +161,7 @@
* contents to disk, unless mDeferredSaveDelayMs is 0 in which case saving
* is disabled.
*/
- bool mSavePending = false;
+ bool mSavePending GUARDED_BY(mMutex) = false;
/**
* "mObservedBlobValueSize" is the maximum value size observed by the cache reading function.
@@ -174,16 +176,16 @@
unsigned int mDeferredSaveDelayMs = 4 * 1000;
/**
- * "mMutex" is the mutex used to prevent concurrent access to the member
+ * "mMutex" is the shared mutex used to prevent concurrent access to the member
* variables. It must be locked whenever the member variables are accessed.
*/
- mutable std::mutex mMutex;
+ mutable ftl::SharedMutex mMutex;
/**
* If set to "true", the next call to onVkFrameFlushed, will invoke
* GrCanvas::storeVkPipelineCacheData. This does not guarantee that data will be stored on disk.
*/
- bool mTryToStorePipelineCache = true;
+ bool mTryToStorePipelineCache GUARDED_BY(mMutex) = true;
/**
* This flag is used by "ShaderCache::store" to distinguish between shader data and
@@ -195,16 +197,16 @@
* "mNewPipelineCacheSize" has the size of the new Vulkan pipeline cache data. It is used
* to prevent unnecessary disk writes, if the pipeline cache size has not changed.
*/
- size_t mNewPipelineCacheSize = -1;
+ size_t mNewPipelineCacheSize GUARDED_BY(mMutex) = -1;
/**
* "mOldPipelineCacheSize" has the size of the Vulkan pipeline cache data stored on disk.
*/
- size_t mOldPipelineCacheSize = -1;
+ size_t mOldPipelineCacheSize GUARDED_BY(mMutex) = -1;
/**
* "mCacheDirty" is true when there is new shader cache data, which is not saved to disk.
*/
- bool mCacheDirty = false;
+ bool mCacheDirty GUARDED_BY(mMutex) = false;
/**
* "sCache" is the singleton ShaderCache object.
@@ -221,7 +223,7 @@
* interesting to keep track of how many shaders are stored in RAM. This
* class provides a convenient entry point for that.
*/
- int mNumShadersCachedInRam = 0;
+ int mNumShadersCachedInRam GUARDED_BY(mMutex) = 0;
friend class ShaderCacheTestUtils; // used for unit testing
};
diff --git a/libs/hwui/tests/unit/ShaderCacheTests.cpp b/libs/hwui/tests/unit/ShaderCacheTests.cpp
index 7bcd45c..9aa2e1d 100644
--- a/libs/hwui/tests/unit/ShaderCacheTests.cpp
+++ b/libs/hwui/tests/unit/ShaderCacheTests.cpp
@@ -49,7 +49,7 @@
*/
static void reinitializeAllFields(ShaderCache& cache) {
ShaderCache newCache = ShaderCache();
- std::lock_guard<std::mutex> lock(cache.mMutex);
+ std::lock_guard lock(cache.mMutex), newLock(newCache.mMutex);
// By order of declaration
cache.mInitialized = newCache.mInitialized;
cache.mBlobCache.reset(nullptr);
@@ -72,7 +72,7 @@
* manually, as seen in the "terminate" testing helper function.
*/
static void setSaveDelayMs(ShaderCache& cache, unsigned int saveDelayMs) {
- std::lock_guard<std::mutex> lock(cache.mMutex);
+ std::lock_guard lock(cache.mMutex);
cache.mDeferredSaveDelayMs = saveDelayMs;
}
@@ -81,7 +81,7 @@
* Next call to "initShaderDiskCache" will load again the in-memory cache from disk.
*/
static void terminate(ShaderCache& cache, bool saveContent) {
- std::lock_guard<std::mutex> lock(cache.mMutex);
+ std::lock_guard lock(cache.mMutex);
if (saveContent) {
cache.saveToDiskLocked();
}
@@ -93,6 +93,7 @@
*/
template <typename T>
static bool validateCache(ShaderCache& cache, std::vector<T> hash) {
+ std::lock_guard lock(cache.mMutex);
return cache.validateCache(hash.data(), hash.size() * sizeof(T));
}
@@ -108,7 +109,7 @@
*/
static void waitForPendingSave(ShaderCache& cache, const int timeoutMs = 50) {
{
- std::lock_guard<std::mutex> lock(cache.mMutex);
+ std::lock_guard lock(cache.mMutex);
ASSERT_TRUE(cache.mSavePending);
}
bool saving = true;
@@ -123,7 +124,7 @@
usleep(delayMicroseconds);
elapsedMilliseconds += (float)delayMicroseconds / 1000;
- std::lock_guard<std::mutex> lock(cache.mMutex);
+ std::lock_guard lock(cache.mMutex);
saving = cache.mSavePending;
}
}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt
index e07a629..90a723f 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt
@@ -50,7 +50,7 @@
import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.Stable
import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.ui.Alignment
@@ -286,21 +286,22 @@
)
}
val pinnedHeightPx: Float
- val density = LocalDensity.current
- val maxHeightPx = density.run {
- remember { mutableStateOf((MaxHeightWithoutTitle + DefaultTitleHeight).toPx()) }
- }
val titleBottomPaddingPx: Int
+ val defaultMaxHeightPx: Float
+ val density = LocalDensity.current
density.run {
pinnedHeightPx = pinnedHeight.toPx()
titleBottomPaddingPx = titleBottomPadding.roundToPx()
+ defaultMaxHeightPx = (MaxHeightWithoutTitle + DefaultTitleHeight).toPx()
}
+ val maxHeightPx = remember(density) { mutableFloatStateOf(defaultMaxHeightPx) }
+
// Sets the app bar's height offset limit to hide just the bottom title area and keep top title
// visible when collapsed.
SideEffect {
- if (scrollBehavior?.state?.heightOffsetLimit != pinnedHeightPx - maxHeightPx.value) {
- scrollBehavior?.state?.heightOffsetLimit = pinnedHeightPx - maxHeightPx.value
+ if (scrollBehavior?.state?.heightOffsetLimit != pinnedHeightPx - maxHeightPx.floatValue) {
+ scrollBehavior?.state?.heightOffsetLimit = pinnedHeightPx - maxHeightPx.floatValue
}
}
@@ -370,16 +371,20 @@
)
TopAppBarLayout(
modifier = Modifier.clipToBounds(),
- heightPx = maxHeightPx.value - pinnedHeightPx +
+ heightPx = maxHeightPx.floatValue - pinnedHeightPx +
(scrollBehavior?.state?.heightOffset ?: 0f),
navigationIconContentColor = colors.navigationIconContentColor,
titleContentColor = colors.titleContentColor,
actionIconContentColor = colors.actionIconContentColor,
title = {
Box(modifier = Modifier.onGloballyPositioned { coordinates ->
- density.run {
- maxHeightPx.value =
- MaxHeightWithoutTitle.toPx() + coordinates.size.height.toFloat()
+ val measuredMaxHeightPx = density.run {
+ MaxHeightWithoutTitle.toPx() + coordinates.size.height.toFloat()
+ }
+ // Allow larger max height for multi-line title, but do not reduce
+ // max height to prevent flaky.
+ if (measuredMaxHeightPx > defaultMaxHeightPx) {
+ maxHeightPx.floatValue = measuredMaxHeightPx
}
}) { title() }
},
@@ -506,7 +511,7 @@
0
}
- val layoutHeight = heightPx.roundToInt()
+ val layoutHeight = if (heightPx.isNaN()) 0 else heightPx.roundToInt()
layout(constraints.maxWidth, layoutHeight) {
// Navigation icon
@@ -612,9 +617,9 @@
// Medium or Large app bar.
private val TopTitleAlphaEasing = CubicBezierEasing(.8f, 0f, .8f, .15f)
-private val MaxHeightWithoutTitle = 124.dp
-private val DefaultTitleHeight = 52.dp
-private val ContainerHeight = 56.dp
+internal val MaxHeightWithoutTitle = 124.dp
+internal val DefaultTitleHeight = 52.dp
+internal val ContainerHeight = 56.dp
private val LargeTitleBottomPadding = 28.dp
private val TopAppBarHorizontalPadding = 4.dp
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt
index 67c4cdc..67f4418 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt
@@ -163,7 +163,6 @@
BackHandler { onClose() }
}
-@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun SearchBox(query: TextFieldValue, onQueryChange: (TextFieldValue) -> Unit) {
val focusRequester = remember { FocusRequester() }
@@ -186,8 +185,9 @@
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Search),
keyboardActions = KeyboardActions(onSearch = { hideKeyboardAction() }),
singleLine = true,
- colors = TextFieldDefaults.textFieldColors(
- containerColor = Color.Transparent,
+ colors = TextFieldDefaults.colors(
+ focusedContainerColor = Color.Transparent,
+ unfocusedContainerColor = Color.Transparent,
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
),
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBarTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBarTest.kt
new file mode 100644
index 0000000..a6a5ed22
--- /dev/null
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBarTest.kt
@@ -0,0 +1,457 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spa.widget.scaffold
+
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.lazy.LazyListState
+import androidx.compose.foundation.lazy.LazyRow
+import androidx.compose.foundation.lazy.rememberLazyListState
+import androidx.compose.material3.CenterAlignedTopAppBar
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
+import androidx.compose.material3.LocalContentColor
+import androidx.compose.material3.LocalTextStyle
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Scaffold
+import androidx.compose.material3.Text
+import androidx.compose.material3.TopAppBarDefaults
+import androidx.compose.material3.TopAppBarScrollBehavior
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.painter.ColorPainter
+import androidx.compose.ui.input.nestedscroll.nestedScroll
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.test.assertHeightIsEqualTo
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.assertLeftPositionInRootIsEqualTo
+import androidx.compose.ui.test.assertTopPositionInRootIsEqualTo
+import androidx.compose.ui.test.assertWidthIsEqualTo
+import androidx.compose.ui.test.getUnclippedBoundsInRoot
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.onNodeWithText
+import androidx.compose.ui.test.performTouchInput
+import androidx.compose.ui.test.swipeLeft
+import androidx.compose.ui.test.swipeRight
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.height
+import androidx.compose.ui.unit.width
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spa.testutils.rootWidth
+import com.android.settingslib.spa.testutils.setContentForSizeAssertions
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalMaterial3Api::class)
+@RunWith(AndroidJUnit4::class)
+class CustomizedAppBarTest {
+
+ @get:Rule
+ val rule = createComposeRule()
+
+ @Test
+ fun smallTopAppBar_expandsToScreen() {
+ rule
+ .setContentForSizeAssertions {
+ CustomizedTopAppBar(title = { Text("Title") })
+ }
+ .assertHeightIsEqualTo(ContainerHeight)
+ .assertWidthIsEqualTo(rule.rootWidth())
+ }
+
+ @Test
+ fun smallTopAppBar_withTitle() {
+ val title = "Title"
+ rule.setContent {
+ Box(Modifier.testTag(TopAppBarTestTag)) {
+ CustomizedTopAppBar(title = { Text(title) })
+ }
+ }
+ rule.onNodeWithText(title).assertIsDisplayed()
+ }
+
+ @Test
+ fun smallTopAppBar_default_positioning() {
+ rule.setContent {
+ Box(Modifier.testTag(TopAppBarTestTag)) {
+ CustomizedTopAppBar(
+ navigationIcon = {
+ FakeIcon(Modifier.testTag(NavigationIconTestTag))
+ },
+ title = {
+ Text("Title", Modifier.testTag(TitleTestTag))
+ },
+ actions = {
+ FakeIcon(Modifier.testTag(ActionsTestTag))
+ }
+ )
+ }
+ }
+ assertSmallDefaultPositioning()
+ }
+
+ @Test
+ fun smallTopAppBar_noNavigationIcon_positioning() {
+ rule.setContent {
+ Box(Modifier.testTag(TopAppBarTestTag)) {
+ CustomizedTopAppBar(
+ title = {
+ Text("Title", Modifier.testTag(TitleTestTag))
+ },
+ actions = {
+ FakeIcon(Modifier.testTag(ActionsTestTag))
+ }
+ )
+ }
+ }
+ assertSmallPositioningWithoutNavigation()
+ }
+
+ @Test
+ fun smallTopAppBar_titleDefaultStyle() {
+ var textStyle: TextStyle? = null
+ var expectedTextStyle: TextStyle? = null
+ rule.setContent {
+ CustomizedTopAppBar(
+ title = {
+ Text("Title")
+ textStyle = LocalTextStyle.current
+ expectedTextStyle = MaterialTheme.typography.titleMedium
+ },
+ )
+ }
+ assertThat(textStyle).isNotNull()
+ assertThat(textStyle).isEqualTo(expectedTextStyle)
+ }
+
+ @Test
+ fun smallTopAppBar_contentColor() {
+ var titleColor: Color = Color.Unspecified
+ var navigationIconColor: Color = Color.Unspecified
+ var actionsColor: Color = Color.Unspecified
+ var expectedTitleColor: Color = Color.Unspecified
+ var expectedNavigationIconColor: Color = Color.Unspecified
+ var expectedActionsColor: Color = Color.Unspecified
+
+ rule.setContent {
+ CustomizedTopAppBar(
+ navigationIcon = {
+ FakeIcon(Modifier.testTag(NavigationIconTestTag))
+ navigationIconColor = LocalContentColor.current
+ expectedNavigationIconColor =
+ TopAppBarDefaults.topAppBarColors().navigationIconContentColor
+ // fraction = 0f to indicate no scroll.
+ },
+ title = {
+ Text("Title", Modifier.testTag(TitleTestTag))
+ titleColor = LocalContentColor.current
+ expectedTitleColor = TopAppBarDefaults.topAppBarColors().titleContentColor
+ },
+ actions = {
+ FakeIcon(Modifier.testTag(ActionsTestTag))
+ actionsColor = LocalContentColor.current
+ expectedActionsColor =
+ TopAppBarDefaults.topAppBarColors().actionIconContentColor
+ }
+ )
+ }
+ assertThat(navigationIconColor).isNotNull()
+ assertThat(titleColor).isNotNull()
+ assertThat(actionsColor).isNotNull()
+ assertThat(navigationIconColor).isEqualTo(expectedNavigationIconColor)
+ assertThat(titleColor).isEqualTo(expectedTitleColor)
+ assertThat(actionsColor).isEqualTo(expectedActionsColor)
+ }
+
+ @Test
+ fun largeTopAppBar_scrolled_positioning() {
+ val content = @Composable { scrollBehavior: TopAppBarScrollBehavior? ->
+ Box(Modifier.testTag(TopAppBarTestTag)) {
+ CustomizedLargeTopAppBar(
+ navigationIcon = {
+ FakeIcon(Modifier.testTag(NavigationIconTestTag))
+ },
+ title = "Title",
+ actions = {
+ FakeIcon(Modifier.testTag(ActionsTestTag))
+ },
+ scrollBehavior = scrollBehavior,
+ )
+ }
+ }
+ assertLargeScrolledHeight(
+ MaxHeightWithoutTitle + DefaultTitleHeight,
+ MaxHeightWithoutTitle + DefaultTitleHeight,
+ content,
+ )
+ }
+
+ @OptIn(ExperimentalMaterial3Api::class)
+ @Test
+ fun topAppBar_enterAlways_allowHorizontalScroll() {
+ lateinit var state: LazyListState
+ rule.setContent {
+ state = rememberLazyListState()
+ MultiPageContent(TopAppBarDefaults.enterAlwaysScrollBehavior(), state)
+ }
+
+ rule.onNodeWithTag(LazyListTag).performTouchInput { swipeLeft() }
+ rule.runOnIdle {
+ assertThat(state.firstVisibleItemIndex).isEqualTo(1)
+ }
+
+ rule.onNodeWithTag(LazyListTag).performTouchInput { swipeRight() }
+ rule.runOnIdle {
+ assertThat(state.firstVisibleItemIndex).isEqualTo(0)
+ }
+ }
+
+ @OptIn(ExperimentalMaterial3Api::class)
+ @Test
+ fun topAppBar_exitUntilCollapsed_allowHorizontalScroll() {
+ lateinit var state: LazyListState
+ rule.setContent {
+ state = rememberLazyListState()
+ MultiPageContent(TopAppBarDefaults.exitUntilCollapsedScrollBehavior(), state)
+ }
+
+ rule.onNodeWithTag(LazyListTag).performTouchInput { swipeLeft() }
+ rule.runOnIdle {
+ assertThat(state.firstVisibleItemIndex).isEqualTo(1)
+ }
+
+ rule.onNodeWithTag(LazyListTag).performTouchInput { swipeRight() }
+ rule.runOnIdle {
+ assertThat(state.firstVisibleItemIndex).isEqualTo(0)
+ }
+ }
+
+ @OptIn(ExperimentalMaterial3Api::class)
+ @Test
+ fun topAppBar_pinned_allowHorizontalScroll() {
+ lateinit var state: LazyListState
+ rule.setContent {
+ state = rememberLazyListState()
+ MultiPageContent(
+ TopAppBarDefaults.pinnedScrollBehavior(),
+ state
+ )
+ }
+
+ rule.onNodeWithTag(LazyListTag).performTouchInput { swipeLeft() }
+ rule.runOnIdle {
+ assertThat(state.firstVisibleItemIndex).isEqualTo(1)
+ }
+
+ rule.onNodeWithTag(LazyListTag).performTouchInput { swipeRight() }
+ rule.runOnIdle {
+ assertThat(state.firstVisibleItemIndex).isEqualTo(0)
+ }
+ }
+
+ @OptIn(ExperimentalMaterial3Api::class)
+ @Composable
+ private fun MultiPageContent(scrollBehavior: TopAppBarScrollBehavior, state: LazyListState) {
+ Scaffold(
+ modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
+ topBar = {
+ CustomizedTopAppBar(
+ title = { Text(text = "Title") },
+ )
+ }
+ ) { contentPadding ->
+ LazyRow(
+ Modifier
+ .fillMaxSize()
+ .testTag(LazyListTag), state
+ ) {
+ items(2) { page ->
+ LazyColumn(
+ modifier = Modifier.fillParentMaxSize(),
+ contentPadding = contentPadding
+ ) {
+ items(50) {
+ Text(
+ modifier = Modifier.fillParentMaxWidth(),
+ text = "Item #$page x $it"
+ )
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Checks the app bar's components positioning when it's a [CustomizedTopAppBar], a
+ * [CenterAlignedTopAppBar], or a larger app bar that is scrolled up and collapsed into a small
+ * configuration and there is no navigation icon.
+ */
+ private fun assertSmallPositioningWithoutNavigation(isCenteredTitle: Boolean = false) {
+ val appBarBounds = rule.onNodeWithTag(TopAppBarTestTag).getUnclippedBoundsInRoot()
+ val titleBounds = rule.onNodeWithTag(TitleTestTag).getUnclippedBoundsInRoot()
+
+ val titleNode = rule.onNodeWithTag(TitleTestTag)
+ // Title should be vertically centered
+ titleNode.assertTopPositionInRootIsEqualTo((appBarBounds.height - titleBounds.height) / 2)
+ if (isCenteredTitle) {
+ // Title should be horizontally centered
+ titleNode.assertLeftPositionInRootIsEqualTo(
+ (appBarBounds.width - titleBounds.width) / 2
+ )
+ } else {
+ // Title should now be placed 16.dp from the start, as there is no navigation icon
+ // 4.dp padding for the whole app bar + 12.dp inset
+ titleNode.assertLeftPositionInRootIsEqualTo(4.dp + 12.dp)
+ }
+
+ rule.onNodeWithTag(ActionsTestTag)
+ // Action should still be placed at the end
+ .assertLeftPositionInRootIsEqualTo(expectedActionPosition(appBarBounds.width))
+ }
+
+ /**
+ * Checks the app bar's components positioning when it's a [CustomizedTopAppBar] or a
+ * [CenterAlignedTopAppBar].
+ */
+ private fun assertSmallDefaultPositioning(isCenteredTitle: Boolean = false) {
+ val appBarBounds = rule.onNodeWithTag(TopAppBarTestTag).getUnclippedBoundsInRoot()
+ val titleBounds = rule.onNodeWithTag(TitleTestTag).getUnclippedBoundsInRoot()
+ val appBarBottomEdgeY = appBarBounds.top + appBarBounds.height
+
+ rule.onNodeWithTag(NavigationIconTestTag)
+ // Navigation icon should be 4.dp from the start
+ .assertLeftPositionInRootIsEqualTo(AppBarStartAndEndPadding)
+ // Navigation icon should be centered within the height of the app bar.
+ .assertTopPositionInRootIsEqualTo(
+ appBarBottomEdgeY - AppBarTopAndBottomPadding - FakeIconSize
+ )
+
+ val titleNode = rule.onNodeWithTag(TitleTestTag)
+ // Title should be vertically centered
+ titleNode.assertTopPositionInRootIsEqualTo((appBarBounds.height - titleBounds.height) / 2)
+ if (isCenteredTitle) {
+ // Title should be horizontally centered
+ titleNode.assertLeftPositionInRootIsEqualTo(
+ (appBarBounds.width - titleBounds.width) / 2
+ )
+ } else {
+ // Title should be 56.dp from the start
+ // 4.dp padding for the whole app bar + 48.dp icon size + 4.dp title padding.
+ titleNode.assertLeftPositionInRootIsEqualTo(4.dp + FakeIconSize + 4.dp)
+ }
+
+ rule.onNodeWithTag(ActionsTestTag)
+ // Action should be placed at the end
+ .assertLeftPositionInRootIsEqualTo(expectedActionPosition(appBarBounds.width))
+ // Action should be 8.dp from the top
+ .assertTopPositionInRootIsEqualTo(
+ appBarBottomEdgeY - AppBarTopAndBottomPadding - FakeIconSize
+ )
+ }
+
+ /**
+ * Checks that changing values at a [CustomizedLargeTopAppBar] scroll behavior
+ * affects the height of the app bar.
+ *
+ * This check partially and fully collapses the app bar to test its height.
+ *
+ * @param appBarMaxHeight the max height of the app bar [content]
+ * @param appBarMinHeight the min height of the app bar [content]
+ * @param content a Composable that adds a CustomizedLargeTopAppBar
+ */
+ @OptIn(ExperimentalMaterial3Api::class)
+ private fun assertLargeScrolledHeight(
+ appBarMaxHeight: Dp,
+ appBarMinHeight: Dp,
+ content: @Composable (TopAppBarScrollBehavior?) -> Unit
+ ) {
+ val fullyCollapsedOffsetDp = appBarMaxHeight - appBarMinHeight
+ val partiallyCollapsedOffsetDp = fullyCollapsedOffsetDp / 3
+ var partiallyCollapsedHeightOffsetPx = 0f
+ var fullyCollapsedHeightOffsetPx = 0f
+ lateinit var scrollBehavior: TopAppBarScrollBehavior
+ rule.setContent {
+ scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
+ with(LocalDensity.current) {
+ partiallyCollapsedHeightOffsetPx = partiallyCollapsedOffsetDp.toPx()
+ fullyCollapsedHeightOffsetPx = fullyCollapsedOffsetDp.toPx()
+ }
+
+ content(scrollBehavior)
+ }
+
+ // Simulate a partially collapsed app bar.
+ rule.runOnIdle {
+ scrollBehavior.state.heightOffset = -partiallyCollapsedHeightOffsetPx
+ scrollBehavior.state.contentOffset = -partiallyCollapsedHeightOffsetPx
+ }
+ rule.waitForIdle()
+ rule.onNodeWithTag(TopAppBarTestTag)
+ .assertHeightIsEqualTo(
+ appBarMaxHeight - partiallyCollapsedOffsetDp
+ )
+
+ // Simulate a fully collapsed app bar.
+ rule.runOnIdle {
+ scrollBehavior.state.heightOffset = -fullyCollapsedHeightOffsetPx
+ // Simulate additional content scroll beyond the max offset scroll.
+ scrollBehavior.state.contentOffset =
+ -fullyCollapsedHeightOffsetPx - partiallyCollapsedHeightOffsetPx
+ }
+ rule.waitForIdle()
+ // Check that the app bar collapsed to its min height.
+ rule.onNodeWithTag(TopAppBarTestTag).assertHeightIsEqualTo(appBarMinHeight)
+ }
+
+ /**
+ * An [IconButton] with an [Icon] inside for testing positions.
+ *
+ * An [IconButton] is defaulted to be 48X48dp, while its child [Icon] is defaulted to 24x24dp.
+ */
+ private val FakeIcon = @Composable { modifier: Modifier ->
+ IconButton(
+ onClick = { /* doSomething() */ },
+ modifier = modifier.semantics(mergeDescendants = true) {}
+ ) {
+ Icon(ColorPainter(Color.Red), null)
+ }
+ }
+
+ private fun expectedActionPosition(appBarWidth: Dp): Dp =
+ appBarWidth - AppBarStartAndEndPadding - FakeIconSize
+
+ private val FakeIconSize = 48.dp
+ private val AppBarStartAndEndPadding = 4.dp
+ private val AppBarTopAndBottomPadding = (ContainerHeight - FakeIconSize) / 2
+
+ private val LazyListTag = "lazyList"
+ private val TopAppBarTestTag = "bar"
+ private val NavigationIconTestTag = "navigationIcon"
+ private val TitleTestTag = "title"
+ private val ActionsTestTag = "actions"
+}
diff --git a/packages/SettingsLib/Spa/testutils/src/com/android/settingslib/spa/testutils/ComposeContentTestRuleExt.kt b/packages/SettingsLib/Spa/testutils/src/com/android/settingslib/spa/testutils/ComposeContentTestRuleExt.kt
index a5d1f40..0436fc2 100644
--- a/packages/SettingsLib/Spa/testutils/src/com/android/settingslib/spa/testutils/ComposeContentTestRuleExt.kt
+++ b/packages/SettingsLib/Spa/testutils/src/com/android/settingslib/spa/testutils/ComposeContentTestRuleExt.kt
@@ -16,13 +16,28 @@
package com.android.settingslib.spa.testutils
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.sizeIn
+import androidx.compose.material3.Surface
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.testTag
import androidx.compose.ui.test.ComposeTimeoutException
import androidx.compose.ui.test.SemanticsMatcher
import androidx.compose.ui.test.SemanticsNodeInteraction
+import androidx.compose.ui.test.getUnclippedBoundsInRoot
import androidx.compose.ui.test.hasAnyAncestor
import androidx.compose.ui.test.hasText
import androidx.compose.ui.test.isDialog
import androidx.compose.ui.test.junit4.ComposeContentTestRule
+import androidx.compose.ui.test.junit4.ComposeTestRule
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.onRoot
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.height
+import androidx.compose.ui.unit.width
+import com.android.settingslib.spa.framework.theme.SettingsTheme
/** Blocks until the found a semantics node that match the given condition. */
fun ComposeContentTestRule.waitUntilExists(matcher: SemanticsMatcher) = waitUntil {
@@ -39,3 +54,39 @@
/** Finds a text node that within dialog. */
fun ComposeContentTestRule.onDialogText(text: String): SemanticsNodeInteraction =
onNode(hasAnyAncestor(isDialog()) and hasText(text))
+
+fun ComposeTestRule.rootWidth(): Dp = onRoot().getUnclippedBoundsInRoot().width
+
+fun ComposeTestRule.rootHeight(): Dp = onRoot().getUnclippedBoundsInRoot().height
+
+/**
+ * Constant to emulate very big but finite constraints
+ */
+private val sizeAssertionMaxSize = 5000.dp
+
+private const val SIZE_ASSERTION_TAG = "containerForSizeAssertion"
+
+fun ComposeContentTestRule.setContentForSizeAssertions(
+ parentMaxWidth: Dp = sizeAssertionMaxSize,
+ parentMaxHeight: Dp = sizeAssertionMaxSize,
+ // TODO : figure out better way to make it flexible
+ content: @Composable () -> Unit
+): SemanticsNodeInteraction {
+ setContent {
+ SettingsTheme {
+ Surface {
+ Box {
+ Box(
+ Modifier
+ .sizeIn(maxWidth = parentMaxWidth, maxHeight = parentMaxHeight)
+ .testTag(SIZE_ASSERTION_TAG)
+ ) {
+ content()
+ }
+ }
+ }
+ }
+ }
+
+ return onNodeWithTag(SIZE_ASSERTION_TAG)
+}
diff --git a/packages/SettingsLib/res/layout/dialog_with_icon.xml b/packages/SettingsLib/res/layout/dialog_with_icon.xml
index 2f30508..3586dcb 100644
--- a/packages/SettingsLib/res/layout/dialog_with_icon.xml
+++ b/packages/SettingsLib/res/layout/dialog_with_icon.xml
@@ -33,13 +33,13 @@
android:importantForAccessibility="no"/>
<TextView
android:id="@+id/dialog_with_icon_title"
- android:layout_width="wrap_content"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
style="@style/DialogWithIconTitle"/>
<TextView
android:id="@+id/dialog_with_icon_message"
- android:layout_width="wrap_content"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
style="@style/TextAppearanceSmall"/>
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/InterestingConfigChanges.java b/packages/SettingsLib/src/com/android/settingslib/applications/InterestingConfigChanges.java
index 64a0781..5d520ce 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/InterestingConfigChanges.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/InterestingConfigChanges.java
@@ -28,11 +28,11 @@
public class InterestingConfigChanges {
private final Configuration mLastConfiguration = new Configuration();
private final int mFlags;
- private int mLastDensity;
public InterestingConfigChanges() {
this(ActivityInfo.CONFIG_LOCALE | ActivityInfo.CONFIG_LAYOUT_DIRECTION
- | ActivityInfo.CONFIG_UI_MODE | ActivityInfo.CONFIG_ASSETS_PATHS);
+ | ActivityInfo.CONFIG_UI_MODE | ActivityInfo.CONFIG_ASSETS_PATHS
+ | ActivityInfo.CONFIG_DENSITY);
}
public InterestingConfigChanges(int flags) {
@@ -50,11 +50,6 @@
public boolean applyNewConfig(Resources res) {
int configChanges = mLastConfiguration.updateFrom(
Configuration.generateDelta(mLastConfiguration, res.getConfiguration()));
- boolean densityChanged = mLastDensity != res.getDisplayMetrics().densityDpi;
- if (densityChanged || (configChanges & (mFlags)) != 0) {
- mLastDensity = res.getDisplayMetrics().densityDpi;
- return true;
- }
- return false;
+ return (configChanges & (mFlags)) != 0;
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
index f2abf87..2a486a9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
@@ -91,6 +91,7 @@
MediaRouter2Manager mRouterManager;
@VisibleForTesting
String mPackageName;
+ boolean mIsScanning = false;
private MediaDevice mCurrentConnectedDevice;
private LocalBluetoothManager mBluetoothManager;
@@ -110,22 +111,29 @@
@Override
public void startScan() {
- mMediaDevices.clear();
- mRouterManager.registerCallback(mExecutor, mMediaRouterCallback);
- mRouterManager.registerScanRequest();
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE
- && !TextUtils.isEmpty(mPackageName)) {
- RouteListingPreference routeListingPreference =
- mRouterManager.getRouteListingPreference(mPackageName);
- Api34Impl.onRouteListingPreferenceUpdated(routeListingPreference, mPreferenceItemMap);
+ if (!mIsScanning) {
+ mMediaDevices.clear();
+ mRouterManager.registerCallback(mExecutor, mMediaRouterCallback);
+ mRouterManager.registerScanRequest();
+ mIsScanning = true;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE
+ && !TextUtils.isEmpty(mPackageName)) {
+ RouteListingPreference routeListingPreference =
+ mRouterManager.getRouteListingPreference(mPackageName);
+ Api34Impl.onRouteListingPreferenceUpdated(routeListingPreference,
+ mPreferenceItemMap);
+ }
+ refreshDevices();
}
- refreshDevices();
}
@Override
public void stopScan() {
- mRouterManager.unregisterCallback(mMediaRouterCallback);
- mRouterManager.unregisterScanRequest();
+ if (mIsScanning) {
+ mRouterManager.unregisterCallback(mMediaRouterCallback);
+ mRouterManager.unregisterScanRequest();
+ mIsScanning = false;
+ }
}
/**
@@ -701,20 +709,19 @@
List<MediaRoute2Info> selectedRouteInfos, List<MediaRoute2Info> infolist,
List<RouteListingPreference.Item> preferenceRouteListing) {
final List<MediaRoute2Info> sortedInfoList = new ArrayList<>(selectedRouteInfos);
+ infolist.removeAll(selectedRouteInfos);
+ sortedInfoList.addAll(infolist.stream().filter(
+ MediaRoute2Info::isSystemRoute).collect(Collectors.toList()));
for (RouteListingPreference.Item item : preferenceRouteListing) {
for (MediaRoute2Info info : infolist) {
if (item.getRouteId().equals(info.getId())
- && !selectedRouteInfos.contains(info)) {
+ && !selectedRouteInfos.contains(info)
+ && !info.isSystemRoute()) {
sortedInfoList.add(info);
break;
}
}
}
- if (sortedInfoList.size() != infolist.size()) {
- infolist.removeAll(sortedInfoList);
- sortedInfoList.addAll(infolist.stream().filter(
- MediaRoute2Info::isSystemRoute).collect(Collectors.toList()));
- }
return sortedInfoList;
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
index 39780f3..7b8815e 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
@@ -114,6 +114,23 @@
}
@Test
+ public void stopScan_notStartFirst_notCallsUnregister() {
+ mInfoMediaManager.mRouterManager = mRouterManager;
+ mInfoMediaManager.stopScan();
+
+ verify(mRouterManager, never()).unregisterScanRequest();
+ }
+
+ @Test
+ public void stopScan_startFirst_callsUnregister() {
+ mInfoMediaManager.mRouterManager = mRouterManager;
+ mInfoMediaManager.startScan();
+ mInfoMediaManager.stopScan();
+
+ verify(mRouterManager).unregisterScanRequest();
+ }
+
+ @Test
public void onRouteAdded_getAvailableRoutes_shouldAddMediaDevice() {
final List<RoutingSessionInfo> routingSessionInfos = new ArrayList<>();
final RoutingSessionInfo sessionInfo = mock(RoutingSessionInfo.class);
@@ -327,11 +344,12 @@
routeListingPreference);
mInfoMediaManager.mMediaRouterCallback.onRoutesUpdated();
- assertThat(mInfoMediaManager.mMediaDevices).hasSize(3);
+ assertThat(mInfoMediaManager.mMediaDevices).hasSize(4);
assertThat(mInfoMediaManager.mMediaDevices.get(0).getId()).isEqualTo(TEST_ID);
- assertThat(mInfoMediaManager.mMediaDevices.get(1).getId()).isEqualTo(TEST_ID_4);
- assertThat(mInfoMediaManager.mMediaDevices.get(1).isSuggestedDevice()).isTrue();
- assertThat(mInfoMediaManager.mMediaDevices.get(2).getId()).isEqualTo(TEST_ID_3);
+ assertThat(mInfoMediaManager.mMediaDevices.get(1).getId()).isEqualTo(TEST_ID_1);
+ assertThat(mInfoMediaManager.mMediaDevices.get(2).getId()).isEqualTo(TEST_ID_4);
+ assertThat(mInfoMediaManager.mMediaDevices.get(2).isSuggestedDevice()).isTrue();
+ assertThat(mInfoMediaManager.mMediaDevices.get(3).getId()).isEqualTo(TEST_ID_3);
}
@Test
@@ -405,8 +423,13 @@
when(availableInfo3.getClientPackageName()).thenReturn(packageName);
availableRoutes.add(availableInfo3);
- when(mRouterManager.getAvailableRoutes(packageName)).thenReturn(
- availableRoutes);
+ final MediaRoute2Info availableInfo4 = mock(MediaRoute2Info.class);
+ when(availableInfo4.getId()).thenReturn(TEST_ID_1);
+ when(availableInfo4.isSystemRoute()).thenReturn(true);
+ when(availableInfo4.getClientPackageName()).thenReturn(TEST_PACKAGE_NAME);
+ availableRoutes.add(availableInfo4);
+
+ when(mRouterManager.getAvailableRoutes(packageName)).thenReturn(availableRoutes);
return availableRoutes;
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index 48259e1..9da1ab8 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -38,6 +38,7 @@
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.ArraySet;
+import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.LocalePicker;
@@ -238,6 +239,7 @@
// If we fail to apply the setting, by definition nothing happened
sendBroadcast = false;
sendBroadcastSystemUI = false;
+ Log.e(TAG, "Failed to restore setting name: " + name + " + value: " + value, e);
} finally {
// If this was an element of interest, send the "we just restored it"
// broadcast with the historical value now that the new value has
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/Expandable.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/Expandable.kt
index d4a81f9..ac1ef15 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/animation/Expandable.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/Expandable.kt
@@ -70,8 +70,10 @@
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.dp
-import androidx.lifecycle.ViewTreeLifecycleOwner
-import androidx.lifecycle.ViewTreeViewModelStoreOwner
+import androidx.lifecycle.findViewTreeLifecycleOwner
+import androidx.lifecycle.findViewTreeViewModelStoreOwner
+import androidx.lifecycle.setViewTreeLifecycleOwner
+import androidx.lifecycle.setViewTreeViewModelStoreOwner
import com.android.systemui.animation.Expandable
import com.android.systemui.animation.LaunchAnimator
import kotlin.math.max
@@ -368,13 +370,10 @@
context,
overlay,
)
- ViewTreeLifecycleOwner.set(
- overlayViewGroup,
- ViewTreeLifecycleOwner.get(composeViewRoot),
- )
- ViewTreeViewModelStoreOwner.set(
- overlayViewGroup,
- ViewTreeViewModelStoreOwner.get(composeViewRoot),
+
+ overlayViewGroup.setViewTreeLifecycleOwner(composeViewRoot.findViewTreeLifecycleOwner())
+ overlayViewGroup.setViewTreeViewModelStoreOwner(
+ composeViewRoot.findViewTreeViewModelStoreOwner()
)
ViewTreeSavedStateRegistryOwner.set(
overlayViewGroup,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt
index 75bf281..13acde2 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt
@@ -121,8 +121,8 @@
}
}
- val backgroundColor = colorAttr(R.attr.underSurfaceColor)
- val contentColor = LocalAndroidColorScheme.current.deprecated.textColorPrimary
+ val backgroundColor = colorAttr(R.attr.underSurface)
+ val contentColor = LocalAndroidColorScheme.current.onSurface
val backgroundTopRadius = dimensionResource(R.dimen.qs_corner_radius)
val backgroundModifier =
remember(
@@ -268,7 +268,7 @@
val interactionSource = remember { MutableInteractionSource() }
Expandable(
- color = colorAttr(R.attr.offStateColor),
+ color = colorAttr(R.attr.shadeInactive),
shape = CircleShape,
onClick = onClick,
interactionSource = interactionSource,
@@ -287,7 +287,7 @@
number.toString(),
modifier = Modifier.align(Alignment.Center),
style = MaterialTheme.typography.bodyLarge,
- color = LocalAndroidColorScheme.current.deprecated.textColorPrimary,
+ color = colorAttr(R.attr.onShadeInactiveVariant),
// TODO(b/242040009): This should only use a standard text style instead and
// should not override the text size.
fontSize = 18.sp,
@@ -305,7 +305,7 @@
@Composable
private fun NewChangesDot(modifier: Modifier = Modifier) {
val contentDescription = stringResource(R.string.fgs_dot_content_description)
- val color = LocalAndroidColorScheme.current.deprecated.colorAccentTertiary
+ val color = LocalAndroidColorScheme.current.tertiary
Canvas(modifier.size(12.dp).semantics { this.contentDescription = contentDescription }) {
drawCircle(color)
@@ -323,10 +323,9 @@
) {
Expandable(
shape = CircleShape,
- color = colorAttr(R.attr.underSurfaceColor),
- contentColor = LocalAndroidColorScheme.current.deprecated.textColorSecondary,
- borderStroke =
- BorderStroke(1.dp, LocalAndroidColorScheme.current.deprecated.colorBackground),
+ color = colorAttr(R.attr.underSurface),
+ contentColor = LocalAndroidColorScheme.current.onSurfaceVariant,
+ borderStroke = BorderStroke(1.dp, colorAttr(R.attr.onShadeActive)),
modifier = modifier.padding(horizontal = 4.dp),
onClick = onClick,
) {
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
index 648ef03..d208404 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
@@ -34,7 +34,7 @@
import com.android.systemui.animation.TextAnimator
import com.android.systemui.customization.R
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel.DEBUG
+import com.android.systemui.log.core.LogLevel.DEBUG
import java.io.PrintWriter
import java.util.Calendar
import java.util.Locale
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
index 1443465..12f7452 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
@@ -24,11 +24,11 @@
import android.util.Log
import androidx.annotation.OpenForTesting
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
-import com.android.systemui.log.LogMessage
import com.android.systemui.log.LogMessageImpl
-import com.android.systemui.log.MessageInitializer
-import com.android.systemui.log.MessagePrinter
+import com.android.systemui.log.core.LogLevel
+import com.android.systemui.log.core.LogMessage
+import com.android.systemui.log.core.MessageInitializer
+import com.android.systemui.log.core.MessagePrinter
import com.android.systemui.plugins.ClockController
import com.android.systemui.plugins.ClockId
import com.android.systemui.plugins.ClockMetadata
diff --git a/packages/SystemUI/log/src/com/android/systemui/log/ConstantStringsLoggerImpl.kt b/packages/SystemUI/log/src/com/android/systemui/log/ConstantStringsLoggerImpl.kt
index 6fc52536..a4f4e13 100644
--- a/packages/SystemUI/log/src/com/android/systemui/log/ConstantStringsLoggerImpl.kt
+++ b/packages/SystemUI/log/src/com/android/systemui/log/ConstantStringsLoggerImpl.kt
@@ -16,6 +16,7 @@
package com.android.systemui.log
+import com.android.systemui.log.core.LogLevel
import com.google.errorprone.annotations.CompileTimeConstant
class ConstantStringsLoggerImpl(val buffer: LogBuffer, val tag: String) : ConstantStringsLogger {
diff --git a/packages/SystemUI/log/src/com/android/systemui/log/LogBuffer.kt b/packages/SystemUI/log/src/com/android/systemui/log/LogBuffer.kt
index 2007e76..8858738 100644
--- a/packages/SystemUI/log/src/com/android/systemui/log/LogBuffer.kt
+++ b/packages/SystemUI/log/src/com/android/systemui/log/LogBuffer.kt
@@ -19,6 +19,10 @@
import android.os.Trace
import android.util.Log
import com.android.systemui.common.buffer.RingBuffer
+import com.android.systemui.log.core.LogLevel
+import com.android.systemui.log.core.LogMessage
+import com.android.systemui.log.core.MessageInitializer
+import com.android.systemui.log.core.MessagePrinter
import com.google.errorprone.annotations.CompileTimeConstant
import java.io.PrintWriter
import java.util.concurrent.ArrayBlockingQueue
@@ -292,11 +296,5 @@
}
}
-/**
- * A function that will be called immediately to store relevant data on the log message. The value
- * of `this` will be the LogMessage to be initialized.
- */
-typealias MessageInitializer = LogMessage.() -> Unit
-
private const val TAG = "LogBuffer"
private val FROZEN_MESSAGE = LogMessageImpl.create()
diff --git a/packages/SystemUI/log/src/com/android/systemui/log/LogMessageImpl.kt b/packages/SystemUI/log/src/com/android/systemui/log/LogMessageImpl.kt
index 5e10f78..33cc199 100644
--- a/packages/SystemUI/log/src/com/android/systemui/log/LogMessageImpl.kt
+++ b/packages/SystemUI/log/src/com/android/systemui/log/LogMessageImpl.kt
@@ -16,6 +16,10 @@
package com.android.systemui.log
+import com.android.systemui.log.core.LogLevel
+import com.android.systemui.log.core.LogMessage
+import com.android.systemui.log.core.MessagePrinter
+
/** Recyclable implementation of [LogMessage]. */
data class LogMessageImpl(
override var level: LogLevel,
diff --git a/packages/SystemUI/log/src/com/android/systemui/log/LogcatEchoTracker.kt b/packages/SystemUI/log/src/com/android/systemui/log/LogcatEchoTracker.kt
index 55f3a73..ae717df 100644
--- a/packages/SystemUI/log/src/com/android/systemui/log/LogcatEchoTracker.kt
+++ b/packages/SystemUI/log/src/com/android/systemui/log/LogcatEchoTracker.kt
@@ -16,6 +16,8 @@
package com.android.systemui.log
+import com.android.systemui.log.core.LogLevel
+
/** Keeps track of which [LogBuffer] messages should also appear in logcat. */
interface LogcatEchoTracker {
/** Whether [bufferName] should echo messages of [level] or higher to logcat. */
diff --git a/packages/SystemUI/log/src/com/android/systemui/log/LogcatEchoTrackerDebug.kt b/packages/SystemUI/log/src/com/android/systemui/log/LogcatEchoTrackerDebug.kt
index d0ad28f..9ff48ca 100644
--- a/packages/SystemUI/log/src/com/android/systemui/log/LogcatEchoTrackerDebug.kt
+++ b/packages/SystemUI/log/src/com/android/systemui/log/LogcatEchoTrackerDebug.kt
@@ -23,6 +23,7 @@
import android.os.Looper
import android.os.Trace
import android.provider.Settings
+import com.android.systemui.log.core.LogLevel
/**
* Version of [LogcatEchoTracker] for debuggable builds
diff --git a/packages/SystemUI/log/src/com/android/systemui/log/LogcatEchoTrackerProd.kt b/packages/SystemUI/log/src/com/android/systemui/log/LogcatEchoTrackerProd.kt
index 56966773..044d97f 100644
--- a/packages/SystemUI/log/src/com/android/systemui/log/LogcatEchoTrackerProd.kt
+++ b/packages/SystemUI/log/src/com/android/systemui/log/LogcatEchoTrackerProd.kt
@@ -16,6 +16,8 @@
package com.android.systemui.log
+import com.android.systemui.log.core.LogLevel
+
/** Production version of [LogcatEchoTracker] that isn't configurable. */
class LogcatEchoTrackerProd : LogcatEchoTracker {
override val logInBackgroundThread = false
diff --git a/packages/SystemUI/log/src/com/android/systemui/log/LogLevel.kt b/packages/SystemUI/log/src/com/android/systemui/log/core/LogLevel.kt
similarity index 95%
rename from packages/SystemUI/log/src/com/android/systemui/log/LogLevel.kt
rename to packages/SystemUI/log/src/com/android/systemui/log/core/LogLevel.kt
index 7d9647a..d30d8e9 100644
--- a/packages/SystemUI/log/src/com/android/systemui/log/LogLevel.kt
+++ b/packages/SystemUI/log/src/com/android/systemui/log/core/LogLevel.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.log
+package com.android.systemui.log.core
import android.util.Log
diff --git a/packages/SystemUI/log/src/com/android/systemui/log/LogMessage.kt b/packages/SystemUI/log/src/com/android/systemui/log/core/LogMessage.kt
similarity index 92%
rename from packages/SystemUI/log/src/com/android/systemui/log/LogMessage.kt
rename to packages/SystemUI/log/src/com/android/systemui/log/core/LogMessage.kt
index 8c3988b..3bd6473 100644
--- a/packages/SystemUI/log/src/com/android/systemui/log/LogMessage.kt
+++ b/packages/SystemUI/log/src/com/android/systemui/log/core/LogMessage.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.log
+package com.android.systemui.log.core
import android.icu.text.SimpleDateFormat
import java.io.PrintWriter
@@ -67,6 +67,12 @@
}
/**
+ * A function that will be called immediately to store relevant data on the log message. The value
+ * of `this` will be the LogMessage to be initialized.
+ */
+typealias MessageInitializer = LogMessage.() -> Unit
+
+/**
* A function that will be called if and when the message needs to be dumped to logcat or a bug
* report. It should read the data stored by the initializer and convert it to a human-readable
* string. The value of `this` will be the LogMessage to be printed. **IMPORTANT:** The printer
diff --git a/packages/SystemUI/res-keyguard/color/shade_disabled.xml b/packages/SystemUI/res-keyguard/color/shade_disabled.xml
new file mode 100644
index 0000000..241f203
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/color/shade_disabled.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="@android:color/system_neutral1_500" android:lStar="4" />
+</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res-keyguard/layout/footer_actions_number_button.xml b/packages/SystemUI/res-keyguard/layout/footer_actions_number_button.xml
index a7ffe9c..c09607d 100644
--- a/packages/SystemUI/res-keyguard/layout/footer_actions_number_button.xml
+++ b/packages/SystemUI/res-keyguard/layout/footer_actions_number_button.xml
@@ -26,7 +26,7 @@
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.QS.SecurityFooter"
android:layout_gravity="center"
- android:textColor="?android:attr/textColorPrimary"
+ android:textColor="?attr/onShadeInactiveVariant"
android:textSize="18sp"/>
<ImageView
android:id="@+id/new_dot"
diff --git a/packages/SystemUI/res-keyguard/layout/footer_actions_text_button.xml b/packages/SystemUI/res-keyguard/layout/footer_actions_text_button.xml
index 6fe7d39..1c31f1d 100644
--- a/packages/SystemUI/res-keyguard/layout/footer_actions_text_button.xml
+++ b/packages/SystemUI/res-keyguard/layout/footer_actions_text_button.xml
@@ -33,7 +33,7 @@
android:layout_marginEnd="12dp"
android:contentDescription="@null"
android:src="@drawable/ic_info_outline"
- android:tint="?android:attr/textColorSecondary" />
+ android:tint="?attr/onSurfaceVariant" />
<TextView
android:id="@+id/text"
@@ -43,7 +43,7 @@
android:maxLines="1"
android:ellipsize="end"
android:textAppearance="@style/TextAppearance.QS.SecurityFooter"
- android:textColor="?android:attr/textColorSecondary"/>
+ android:textColor="?attr/onSurfaceVariant"/>
<ImageView
android:id="@+id/new_dot"
@@ -62,5 +62,5 @@
android:contentDescription="@null"
android:src="@*android:drawable/ic_chevron_end"
android:autoMirrored="true"
- android:tint="?android:attr/textColorSecondary" />
+ android:tint="?attr/onSurfaceVariant" />
</com.android.systemui.animation.view.LaunchableLinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res-product/values/strings.xml b/packages/SystemUI/res-product/values/strings.xml
index 13f72af0..42733a2 100644
--- a/packages/SystemUI/res-product/values/strings.xml
+++ b/packages/SystemUI/res-product/values/strings.xml
@@ -122,6 +122,44 @@
Try again in <xliff:g id="number">%3$d</xliff:g> seconds.
</string>
+ <!-- Title for notification & dialog that the user's phone last shut down because it got too hot. [CHAR LIMIT=40] -->
+ <string name="thermal_shutdown_title" product="default">Phone turned off due to heat</string>
+ <!-- Title for notification & dialog that the user's device last shut down because it got too hot. [CHAR LIMIT=40] -->
+ <string name="thermal_shutdown_title" product="device">Device turned off due to heat</string>
+ <!-- Title for notification & dialog that the user's tablet last shut down because it got too hot. [CHAR LIMIT=40] -->
+ <string name="thermal_shutdown_title" product="tablet">Tablet turned off due to heat</string>
+ <!-- Message body for notification that user's phone last shut down because it got too hot. [CHAR LIMIT=120] -->
+ <string name="thermal_shutdown_message" product="default">Your phone is now running normally.\nTap for more info</string>
+ <!-- Message body for notification that user's device last shut down because it got too hot. [CHAR LIMIT=120] -->
+ <string name="thermal_shutdown_message" product="device">Your device is now running normally.\nTap for more info</string>
+ <!-- Message body for notification that user's tablet last shut down because it got too hot. [CHAR LIMIT=120] -->
+ <string name="thermal_shutdown_message" product="tablet">Your tablet is now running normally.\nTap for more info</string>
+ <!-- Text body for dialog alerting user that their phone last shut down because it got too hot. [CHAR LIMIT=500] -->
+ <string name="thermal_shutdown_dialog_message" product="default">Your phone was too hot, so it turned off to cool down. Your phone is now running normally.\n\nYour phone may get too hot if you:\n\t• Use resource-intensive apps (such as gaming, video, or navigation apps)\n\t• Download or upload large files\n\t• Use your phone in high temperatures</string>
+ <!-- Text body for dialog alerting user that their device last shut down because it got too hot. [CHAR LIMIT=500] -->
+ <string name="thermal_shutdown_dialog_message" product="device">Your device was too hot, so it turned off to cool down. Your device is now running normally.\n\nYour device may get too hot if you:\n\t• Use resource-intensive apps (such as gaming, video, or navigation apps)\n\t• Download or upload large files\n\t• Use your device in high temperatures</string>
+ <!-- Text body for dialog alerting user that their tablet last shut down because it got too hot. [CHAR LIMIT=500] -->
+ <string name="thermal_shutdown_dialog_message" product="tablet">Your tablet was too hot, so it turned off to cool down. Your tablet is now running normally.\n\nYour tablet may get too hot if you:\n\t• Use resource-intensive apps (such as gaming, video, or navigation apps)\n\t• Download or upload large files\n\t• Use your tablet in high temperatures</string>
+
+ <!-- Title for notification (and dialog) that user's phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=30] -->
+ <string name="high_temp_title" product="default">Phone is getting warm</string>
+ <!-- Title for notification (and dialog) that user's phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=30] -->
+ <string name="high_temp_title" product="device">Device is getting warm</string>
+ <!-- Title for notification (and dialog) that user's phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=30] -->
+ <string name="high_temp_title" product="tablet">Tablet is getting warm</string>
+ <!-- Message body for notification that user's phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=120] -->
+ <string name="high_temp_notif_message" product="default">Some features limited while phone cools down.\nTap for more info</string>
+ <!-- Message body for notification that user's device has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=120] -->
+ <string name="high_temp_notif_message" product="device">Some features limited while device cools down.\nTap for more info</string>
+ <!-- Message body for notification that user's tablet has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=120] -->
+ <string name="high_temp_notif_message" product="tablet">Some features limited while tablet cools down.\nTap for more info</string>
+ <!-- Text body for dialog alerting user that their phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=350] -->
+ <string name="high_temp_dialog_message" product="default">Your phone will automatically try to cool down. You can still use your phone, but it may run slower.\n\nOnce your phone has cooled down, it will run normally.</string>
+ <!-- Text body for dialog alerting user that their phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=350] -->
+ <string name="high_temp_dialog_message" product="device">Your device will automatically try to cool down. You can still use your device, but it may run slower.\n\nOnce your device has cooled down, it will run normally.</string>
+ <!-- Text body for dialog alerting user that their phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=350] -->
+ <string name="high_temp_dialog_message" product="tablet">Your tablet will automatically try to cool down. You can still use your tablet, but it may run slower.\n\nOnce your tablet has cooled down, it will run normally.</string>
+
<!-- Content description of the fingerprint icon when the system-provided fingerprint dialog is showing, to locate the sensor (tablet) for accessibility (not shown on the screen). [CHAR LIMIT=NONE]-->
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet">The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the tablet.</string>
<!-- Content description of the fingerprint icon when the system-provided fingerprint dialog is showing, to locate the sensor (device) for accessibility (not shown on the screen). [CHAR LIMIT=NONE]-->
diff --git a/packages/SystemUI/res/drawable/brightness_mirror_background.xml b/packages/SystemUI/res/drawable/brightness_mirror_background.xml
index 2095103..b5c181b 100644
--- a/packages/SystemUI/res/drawable/brightness_mirror_background.xml
+++ b/packages/SystemUI/res/drawable/brightness_mirror_background.xml
@@ -15,6 +15,6 @@
~ limitations under the License
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android">
- <solid android:color="?attr/underSurfaceColor" />
+ <solid android:color="?attr/underSurface" />
<corners android:radius="@dimen/rounded_slider_background_rounded_corner" />
</shape>
diff --git a/packages/SystemUI/res/drawable/brightness_progress_drawable.xml b/packages/SystemUI/res/drawable/brightness_progress_drawable.xml
index 569ee76..95c7778c 100644
--- a/packages/SystemUI/res/drawable/brightness_progress_drawable.xml
+++ b/packages/SystemUI/res/drawable/brightness_progress_drawable.xml
@@ -24,7 +24,7 @@
<shape>
<size android:height="@dimen/rounded_slider_track_width" />
<corners android:radius="@dimen/rounded_slider_track_corner_radius" />
- <solid android:color="?attr/offStateColor" />
+ <solid android:color="?attr/shadeInactive" />
</shape>
</inset>
</item>
diff --git a/packages/SystemUI/res/drawable/brightness_progress_full_drawable.xml b/packages/SystemUI/res/drawable/brightness_progress_full_drawable.xml
index 4d9188c..2ea90c7 100644
--- a/packages/SystemUI/res/drawable/brightness_progress_full_drawable.xml
+++ b/packages/SystemUI/res/drawable/brightness_progress_full_drawable.xml
@@ -22,7 +22,7 @@
android:height="@dimen/rounded_slider_height">
<shape>
<size android:height="@dimen/rounded_slider_height" />
- <solid android:color="?priv-android:attr/colorAccentPrimary" />
+ <solid android:color="?attr/shadeActive" />
<corners android:radius="@dimen/rounded_slider_corner_radius"/>
</shape>
</item>
@@ -34,7 +34,7 @@
android:right="@dimen/rounded_slider_icon_inset">
<com.android.systemui.util.AlphaTintDrawableWrapper
android:drawable="@drawable/ic_brightness"
- android:tint="?android:attr/textColorPrimaryInverse"
+ android:tint="?attr/onShadeActive"
/>
</item>
</layer-list>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/fgs_dot.xml b/packages/SystemUI/res/drawable/fgs_dot.xml
index 3669e1d..0881d7c 100644
--- a/packages/SystemUI/res/drawable/fgs_dot.xml
+++ b/packages/SystemUI/res/drawable/fgs_dot.xml
@@ -19,5 +19,5 @@
android:shape="oval"
android:width="12dp"
android:height="12dp">
- <solid android:color="?androidprv:attr/colorAccentTertiary" />
+ <solid android:color="?attr/tertiary" />
</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/qs_customizer_background_primary.xml b/packages/SystemUI/res/drawable/qs_customizer_background_primary.xml
index ea0aafd..e138d09 100644
--- a/packages/SystemUI/res/drawable/qs_customizer_background_primary.xml
+++ b/packages/SystemUI/res/drawable/qs_customizer_background_primary.xml
@@ -15,7 +15,7 @@
-->
<inset xmlns:android="http://schemas.android.com/apk/res/android">
<shape>
- <solid android:color="?attr/underSurfaceColor"/>
+ <solid android:color="?attr/underSurface"/>
<corners android:radius="?android:attr/dialogCornerRadius" />
</shape>
</inset>
diff --git a/packages/SystemUI/res/drawable/qs_customizer_toolbar.xml b/packages/SystemUI/res/drawable/qs_customizer_toolbar.xml
index ef950fe..f1a24aa 100644
--- a/packages/SystemUI/res/drawable/qs_customizer_toolbar.xml
+++ b/packages/SystemUI/res/drawable/qs_customizer_toolbar.xml
@@ -15,6 +15,6 @@
-->
<inset xmlns:android="http://schemas.android.com/apk/res/android">
<shape>
- <solid android:color="?attr/underSurfaceColor"/>
+ <solid android:color="?attr/underSurface"/>
</shape>
</inset>
diff --git a/packages/SystemUI/res/drawable/qs_dialog_btn_filled.xml b/packages/SystemUI/res/drawable/qs_dialog_btn_filled.xml
index 14cb1de9..c4e45bf 100644
--- a/packages/SystemUI/res/drawable/qs_dialog_btn_filled.xml
+++ b/packages/SystemUI/res/drawable/qs_dialog_btn_filled.xml
@@ -28,7 +28,7 @@
<item>
<shape android:shape="rectangle">
<corners android:radius="?android:attr/buttonCornerRadius"/>
- <solid android:color="?androidprv:attr/colorAccentPrimary"/>
+ <solid android:color="?androidprv:attr/materialColorPrimary"/>
<padding android:left="@dimen/dialog_button_horizontal_padding"
android:top="@dimen/dialog_button_vertical_padding"
android:right="@dimen/dialog_button_horizontal_padding"
diff --git a/packages/SystemUI/res/drawable/qs_dialog_btn_filled_large.xml b/packages/SystemUI/res/drawable/qs_dialog_btn_filled_large.xml
index 0544b871..1590daa 100644
--- a/packages/SystemUI/res/drawable/qs_dialog_btn_filled_large.xml
+++ b/packages/SystemUI/res/drawable/qs_dialog_btn_filled_large.xml
@@ -26,7 +26,7 @@
<item>
<shape android:shape="rectangle">
<corners android:radius="18dp"/>
- <solid android:color="?androidprv:attr/colorAccentPrimary"/>
+ <solid android:color="?androidprv:attr/materialColorPrimaryFixed"/>
</shape>
</item>
</ripple>
diff --git a/packages/SystemUI/res/drawable/qs_dialog_btn_outline.xml b/packages/SystemUI/res/drawable/qs_dialog_btn_outline.xml
index a47299d..b0dc652 100644
--- a/packages/SystemUI/res/drawable/qs_dialog_btn_outline.xml
+++ b/packages/SystemUI/res/drawable/qs_dialog_btn_outline.xml
@@ -29,7 +29,7 @@
<shape android:shape="rectangle">
<corners android:radius="?android:attr/buttonCornerRadius"/>
<solid android:color="@android:color/transparent"/>
- <stroke android:color="?androidprv:attr/colorAccentPrimaryVariant"
+ <stroke android:color="?androidprv:attr/materialColorPrimary"
android:width="1dp"
/>
<padding android:left="@dimen/dialog_button_horizontal_padding"
diff --git a/packages/SystemUI/res/drawable/qs_footer_action_circle.xml b/packages/SystemUI/res/drawable/qs_footer_action_circle.xml
index c8c36b0..4a5d4af 100644
--- a/packages/SystemUI/res/drawable/qs_footer_action_circle.xml
+++ b/packages/SystemUI/res/drawable/qs_footer_action_circle.xml
@@ -28,7 +28,7 @@
</item>
<item>
<shape android:shape="rectangle">
- <solid android:color="?attr/offStateColor"/>
+ <solid android:color="?attr/shadeInactive"/>
<corners android:radius="@dimen/qs_footer_action_corner_radius"/>
</shape>
</item>
diff --git a/packages/SystemUI/res/drawable/qs_footer_action_circle_color.xml b/packages/SystemUI/res/drawable/qs_footer_action_circle_color.xml
index 6a365000..a8c0349 100644
--- a/packages/SystemUI/res/drawable/qs_footer_action_circle_color.xml
+++ b/packages/SystemUI/res/drawable/qs_footer_action_circle_color.xml
@@ -28,7 +28,7 @@
</item>
<item>
<shape android:shape="rectangle">
- <solid android:color="?android:attr/colorAccent"/>
+ <solid android:color="?attr/shadeActive"/>
<corners android:radius="@dimen/qs_footer_action_corner_radius"/>
</shape>
</item>
diff --git a/packages/SystemUI/res/drawable/qs_footer_actions_background.xml b/packages/SystemUI/res/drawable/qs_footer_actions_background.xml
index c9517cd9..a7e8762 100644
--- a/packages/SystemUI/res/drawable/qs_footer_actions_background.xml
+++ b/packages/SystemUI/res/drawable/qs_footer_actions_background.xml
@@ -15,7 +15,7 @@
-->
<inset xmlns:android="http://schemas.android.com/apk/res/android">
<shape>
- <solid android:color="?attr/underSurfaceColor"/>
+ <solid android:color="?attr/underSurface"/>
<corners android:topLeftRadius="@dimen/qs_corner_radius"
android:topRightRadius="@dimen/qs_corner_radius"/>
</shape>
diff --git a/packages/SystemUI/res/drawable/qs_security_footer_background.xml b/packages/SystemUI/res/drawable/qs_security_footer_background.xml
index 381af50..0b0055b 100644
--- a/packages/SystemUI/res/drawable/qs_security_footer_background.xml
+++ b/packages/SystemUI/res/drawable/qs_security_footer_background.xml
@@ -29,7 +29,7 @@
<item>
<shape android:shape="rectangle">
<stroke android:width="1dp"
- android:color="?android:attr/colorBackground"/>
+ android:color="?attr/shadeInactive"/>
<corners android:radius="@dimen/qs_security_footer_corner_radius"/>
</shape>
</item>
diff --git a/packages/SystemUI/res/drawable/stat_sys_connected_display.xml b/packages/SystemUI/res/drawable/stat_sys_connected_display.xml
new file mode 100644
index 0000000..3f3d6f5
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_connected_display.xml
@@ -0,0 +1,25 @@
+<!--
+Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:fillColor="@android:color/white"
+ android:viewportWidth="960"
+ android:viewportHeight="960">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M320,840L320,760L400,760L400,680L160,680Q127,680 103.5,656.5Q80,633 80,600L80,200Q80,167 103.5,143.5Q127,120 160,120L800,120Q833,120 856.5,143.5Q880,167 880,200L880,600Q880,633 856.5,656.5Q833,680 800,680L560,680L560,760L640,760L640,840L320,840ZM160,600L800,600Q800,600 800,600Q800,600 800,600L800,200Q800,200 800,200Q800,200 800,200L160,200Q160,200 160,200Q160,200 160,200L160,600Q160,600 160,600Q160,600 160,600ZM160,600Q160,600 160,600Q160,600 160,600L160,200Q160,200 160,200Q160,200 160,200L160,200Q160,200 160,200Q160,200 160,200L160,600Q160,600 160,600Q160,600 160,600L160,600Z" />
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/alert_dialog_title_systemui.xml b/packages/SystemUI/res/layout/alert_dialog_title_systemui.xml
index 88f13b4..ca7df86 100644
--- a/packages/SystemUI/res/layout/alert_dialog_title_systemui.xml
+++ b/packages/SystemUI/res/layout/alert_dialog_title_systemui.xml
@@ -42,7 +42,7 @@
android:layout_marginBottom="16dp"
android:scaleType="fitCenter"
android:src="@null"
- android:tint="?androidprv:attr/colorAccentPrimaryVariant"
+ android:tint="?androidprv:attr/materialColorPrimary"
/>
<TextView
diff --git a/packages/SystemUI/res/layout/qs_footer_impl.xml b/packages/SystemUI/res/layout/qs_footer_impl.xml
index 745cfc6..b8f4c0f 100644
--- a/packages/SystemUI/res/layout/qs_footer_impl.xml
+++ b/packages/SystemUI/res/layout/qs_footer_impl.xml
@@ -53,6 +53,7 @@
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
+ android:tint="?attr/shadeActive"
android:visibility="gone" />
<FrameLayout
@@ -70,7 +71,7 @@
android:focusable="true"
android:padding="@dimen/qs_footer_icon_padding"
android:src="@*android:drawable/ic_mode_edit"
- android:tint="?android:attr/textColorPrimary" />
+ android:tint="?attr/onSurfaceVariant" />
</FrameLayout>
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/qs_tile_label.xml b/packages/SystemUI/res/layout/qs_tile_label.xml
index c124aea..974cad3 100644
--- a/packages/SystemUI/res/layout/qs_tile_label.xml
+++ b/packages/SystemUI/res/layout/qs_tile_label.xml
@@ -54,6 +54,6 @@
android:focusable="false"
android:importantForAccessibility="no"
android:textAppearance="@style/TextAppearance.QS.TileLabel.Secondary"
- android:textColor="?android:attr/textColorSecondary"/>
+ android:textColor="?attr/onShadeInactive"/>
</com.android.systemui.qs.tileimpl.IgnorableChildLinearLayout>
diff --git a/packages/SystemUI/res/layout/screen_record_dialog.xml b/packages/SystemUI/res/layout/screen_record_dialog.xml
index bbf3adf..f6ce70d 100644
--- a/packages/SystemUI/res/layout/screen_record_dialog.xml
+++ b/packages/SystemUI/res/layout/screen_record_dialog.xml
@@ -15,6 +15,7 @@
limitations under the License.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
@@ -47,7 +48,7 @@
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceLarge"
+ android:textAppearance="@style/TextAppearance.Dialog.Title"
android:fontFamily="@*android:string/config_headlineFontFamily"
android:text="@string/screenrecord_permission_dialog_title"
android:layout_marginTop="22dp"
@@ -56,8 +57,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/screenrecord_permission_dialog_warning_entire_screen"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="?android:textColorSecondary"
+ android:textAppearance="@style/TextAppearance.Dialog.Body.Message"
android:gravity="center"
android:layout_marginBottom="20dp"/>
@@ -81,6 +81,7 @@
android:minHeight="48dp"
android:layout_weight="1"
android:popupBackground="@drawable/screenrecord_spinner_background"
+ android:textColor="?androidprv:attr/materialColorOnSurface"
android:dropDownWidth="274dp"
android:prompt="@string/screenrecord_audio_label"/>
<Switch
@@ -117,7 +118,7 @@
android:text="@string/screenrecord_taps_label"
android:textAppearance="?android:attr/textAppearanceMedium"
android:fontFamily="@*android:string/config_headlineFontFamily"
- android:textColor="?android:attr/textColorPrimary"
+ android:textColor="?androidprv:attr/materialColorOnSurface"
android:importantForAccessibility="no"/>
<Switch
android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/layout/screen_share_dialog.xml b/packages/SystemUI/res/layout/screen_share_dialog.xml
index ab522a3..9af46c5 100644
--- a/packages/SystemUI/res/layout/screen_share_dialog.xml
+++ b/packages/SystemUI/res/layout/screen_share_dialog.xml
@@ -36,14 +36,13 @@
android:layout_width="@dimen/screenrecord_logo_size"
android:layout_height="@dimen/screenrecord_logo_size"
android:src="@drawable/ic_media_projection_permission"
- android:tint="?androidprv:attr/colorAccentPrimaryVariant"
+ android:tint="?androidprv:attr/materialColorPrimary"
android:importantForAccessibility="no"/>
<TextView
android:id="@+id/screen_share_dialog_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceLarge"
- android:fontFamily="@*android:string/config_headlineFontFamily"
+ android:textAppearance="@style/TextAppearance.Dialog.Title"
android:layout_marginTop="@dimen/screenrecord_title_margin_top"
android:gravity="center"/>
<Spinner
@@ -64,8 +63,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/screenrecord_permission_dialog_warning_entire_screen"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="?android:textColorSecondary"
+ style="@style/TextAppearance.Dialog.Body.Message"
android:gravity="start"
android:lineHeight="@dimen/screenrecord_warning_line_height"/>
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index 3a1d1a8..d693631 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -118,8 +118,25 @@
<attr name="wallpaperTextColorSecondary" format="reference|color" />
<attr name="wallpaperTextColorAccent" format="reference|color" />
<attr name="backgroundProtectedStyle" format="reference" />
- <attr name="offStateColor" format="reference|color" />
- <attr name="underSurfaceColor" format="reference|color" />
+
+ <!-- color attribute tokens for QS -->
+ <attr name="isQsTheme" format="boolean" />
+ <attr name="underSurface" format="reference|color"/>
+ <attr name="shadeActive" format="reference|color" />
+ <attr name="onShadeActive" format="reference|color" />
+ <attr name="onShadeActiveVariant" format="reference|color" />
+ <attr name="shadeInactive" format="reference|color" />
+ <attr name="onShadeInactive" format="reference|color" />
+ <attr name="onShadeInactiveVariant" format="reference|color" />
+ <attr name="shadeDisabled" format="reference|color" />
+ <attr name="surfaceBright" format="reference|color" />
+ <attr name="scHigh" format="reference|color" />
+ <attr name="tertiary" format="reference|color" />
+ <attr name="onSurface" format="reference|color" />
+ <attr name="onSurfaceVariant" format="reference|color" />
+ <attr name="outline" format="reference|color" />
+ <attr name="primary" format="reference|color" />
+
<declare-styleable name="SmartReplyView">
<attr name="spacing" format="dimension" />
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 25f3d22..a36f318 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2089,23 +2089,11 @@
<!-- Tuner string -->
<!-- Tuner string -->
- <!-- Title for notification & dialog that the user's phone last shut down because it got too hot. [CHAR LIMIT=40] -->
- <string name="thermal_shutdown_title">Phone turned off due to heat</string>
- <!-- Message body for notification that user's phone last shut down because it got too hot. [CHAR LIMIT=120] -->
- <string name="thermal_shutdown_message">Your phone is now running normally.\nTap for more info</string>
- <!-- Text body for dialog alerting user that their phone last shut down because it got too hot. [CHAR LIMIT=500] -->
- <string name="thermal_shutdown_dialog_message">Your phone was too hot, so it turned off to cool down. Your phone is now running normally.\n\nYour phone may get too hot if you:\n\t• Use resource-intensive apps (such as gaming, video, or navigation apps)\n\t• Download or upload large files\n\t• Use your phone in high temperatures</string>
<!-- Text help link for care instructions for overheating devices [CHAR LIMIT=40] -->
<string name="thermal_shutdown_dialog_help_text">See care steps</string>
<!-- URL for care instructions for overheating devices -->
<string name="thermal_shutdown_dialog_help_url" translatable="false"></string>
- <!-- Title for notification (and dialog) that user's phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=30] -->
- <string name="high_temp_title">Phone is getting warm</string>
- <!-- Message body for notification that user's phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=120] -->
- <string name="high_temp_notif_message">Some features limited while phone cools down.\nTap for more info</string>
- <!-- Text body for dialog alerting user that their phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=350] -->
- <string name="high_temp_dialog_message">Your phone will automatically try to cool down. You can still use your phone, but it may run slower.\n\nOnce your phone has cooled down, it will run normally.</string>
<!-- Text help link for care instructions for overheating devices [CHAR LIMIT=40] -->
<string name="high_temp_dialog_help_text">See care steps</string>
<!-- URL for care instructions for overheating devices -->
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index cb5342a..fd74c7e 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -83,7 +83,7 @@
<style name="TextAppearance.QS">
<item name="android:textStyle">normal</item>
- <item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="android:textColor">?attr/onShadeInactive</item>
<item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
</style>
@@ -93,7 +93,7 @@
<style name="TextAppearance.QS.DetailItemSecondary">
<item name="android:textSize">@dimen/qs_tile_text_size</item>
- <item name="android:textColor">?android:attr/colorAccent</item>
+ <item name="android:textColor">?attr/shadeActive</item>
</style>
<style name="TextAppearance.QS.Introduction">
@@ -117,11 +117,11 @@
<style name="TextAppearance.QS.DataUsage.Usage">
<item name="android:textSize">@dimen/qs_data_usage_usage_text_size</item>
- <item name="android:textColor">?android:attr/colorAccent</item>
+ <item name="android:textColor">?attr/shadeActive</item>
</style>
<style name="TextAppearance.QS.DataUsage.Secondary">
- <item name="android:textColor">?android:attr/textColorSecondary</item>
+ <item name="android:textColor">?attr/onShadeInactiveVariant</item>
</style>
<style name="TextAppearance.QS.TileLabel">
@@ -137,31 +137,31 @@
<style name="TextAppearance.QS.UserSwitcher">
<item name="android:textSize">@dimen/qs_tile_text_size</item>
- <item name="android:textColor">?android:attr/textColorSecondary</item>
+ <item name="android:textColor">?androidprv:attr/materialColorOnSurfaceVariant</item>
</style>
<!-- This is hard coded to be sans-serif-condensed to match the icons -->
<style name="TextAppearance.QS.Status">
<item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
- <item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="android:textColor">?attr/onSurface</item>
<item name="android:textSize">14sp</item>
<item name="android:letterSpacing">0.01</item>
</style>
<style name="TextAppearance.QS.SecurityFooter" parent="@style/TextAppearance.QS.Status">
<item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
- <item name="android:textColor">?android:attr/textColorSecondary</item>
+ <item name="android:textColor">?attr/onSurface</item>
</style>
<style name="TextAppearance.QS.Status.Carriers" />
<style name="TextAppearance.QS.Status.Carriers.NoCarrierText">
- <item name="android:textColor">?android:attr/textColorSecondary</item>
+ <item name="android:textColor">?attr/onSurfaceVariant</item>
</style>
<style name="TextAppearance.QS.Status.Build">
- <item name="android:textColor">?android:attr/textColorSecondary</item>
+ <item name="android:textColor">?attr/onSurfaceVariant</item>
</style>
<style name="TextAppearance.DeviceManagementDialog.Title" parent="@android:style/TextAppearance.DeviceDefault.DialogWindowTitle"/>
@@ -278,10 +278,10 @@
<style name="DeviceManagementDialogTitle">
<item name="android:gravity">center</item>
- <item name="android:textAppearance">@style/TextAppearance.DeviceManagementDialog.Title</item>
+ <item name="android:textAppearance">@style/TextAppearance.Dialog.Title</item>
</style>
- <style name="TextAppearance.DeviceManagementDialog.Content" parent="@*android:style/TextAppearance.DeviceDefault.Subhead"/>
+ <style name="TextAppearance.DeviceManagementDialog.Content" parent="@style/TextAppearance.Dialog.Body.Message"/>
<style name="BaseBrightnessDialogContainer" parent="@style/Theme.SystemUI">
<item name="android:layout_width">match_parent</item>
@@ -371,14 +371,30 @@
</style>
<style name="Theme.SystemUI.QuickSettings" parent="@*android:style/Theme.DeviceDefault">
+ <item name="isQsTheme">true</item>
<item name="lightIconTheme">@style/QSIconTheme</item>
<item name="darkIconTheme">@style/QSIconTheme</item>
<item name="android:colorError">@*android:color/error_color_material_dark</item>
<item name="android:windowIsFloating">true</item>
<item name="android:homeAsUpIndicator">@drawable/ic_arrow_back</item>
- <item name="offStateColor">@color/material_dynamic_neutral20</item>
- <item name="underSurfaceColor">@color/material_dynamic_neutral0</item>
- <item name="android:colorBackground">@color/material_dynamic_neutral10</item>
+
+ <item name="surfaceBright">?androidprv:attr/materialColorSurfaceBright</item>
+ <item name="android:colorBackground">?attr/surfaceBright</item>
+ <item name="scHigh">?androidprv:attr/materialColorSurfaceContainerHigh</item>
+ <item name="primary">?androidprv:attr/materialColorPrimary</item>
+ <item name="tertiary">?androidprv:attr/materialColorTertiary</item>
+ <item name="onSurface">?androidprv:attr/materialColorOnSurface</item>
+ <item name="onSurfaceVariant">?androidprv:attr/materialColorOnSurfaceVariant</item>
+ <item name="outline">?androidprv:attr/materialColorOutline</item>
+
+ <item name="shadeActive">@color/material_dynamic_primary90</item>
+ <item name="onShadeActive">@color/material_dynamic_primary10</item>
+ <item name="onShadeActiveVariant">@color/material_dynamic_primary30</item>
+ <item name="shadeInactive">@color/material_dynamic_neutral20</item>
+ <item name="onShadeInactive">@color/material_dynamic_neutral90</item>
+ <item name="onShadeInactiveVariant">@color/material_dynamic_neutral_variant80</item>
+ <item name="shadeDisabled">@color/shade_disabled</item>
+ <item name="underSurface">@color/material_dynamic_neutral0</item>
<item name="android:itemTextAppearance">@style/Control.MenuItem</item>
</style>
@@ -390,8 +406,15 @@
<item name="android:windowBackground">@android:color/transparent</item>
</style>
- <style name="Theme.SystemUI.QuickSettings.Dialog" parent="@android:style/Theme.DeviceDefault.Dialog">
+ <style name="Theme.SystemUI.QuickSettings.Dialog" parent="@style/Theme.SystemUI.Dialog.QuickSettings">
+ </style>
+
+ <!-- Parent style overrides style in the dot inheritance -->
+ <style name="Theme.SystemUI.Dialog.QuickSettings" parent="@style/Theme.SystemUI.QuickSettings">
<item name="android:dialogCornerRadius">@dimen/notification_corner_radius</item>
+ <item name="android:buttonBarPositiveButtonStyle">@style/Widget.Dialog.Button.QuickSettings</item>
+ <item name="android:buttonBarNegativeButtonStyle">@style/Widget.Dialog.Button.QuickSettings</item>
+ <item name="android:buttonBarNeutralButtonStyle">@style/Widget.Dialog.Button.QuickSettings</item>
</style>
<!-- Overridden by values-television/styles.xml with tv-specific settings -->
@@ -406,7 +429,7 @@
<item name="android:buttonBarPositiveButtonStyle">@style/Widget.Dialog.Button</item>
<item name="android:buttonBarNegativeButtonStyle">@style/Widget.Dialog.Button.BorderButton</item>
<item name="android:buttonBarNeutralButtonStyle">@style/Widget.Dialog.Button.BorderButton</item>
- <item name="android:colorBackground">?androidprv:attr/colorSurface</item>
+ <item name="android:colorBackground">?androidprv:attr/materialColorSurfaceBright</item>
<item name="android:alertDialogStyle">@style/ScrollableAlertDialogStyle</item>
<item name="android:buttonBarStyle">@style/ButtonBarStyle</item>
<item name="android:buttonBarButtonStyle">@style/Widget.Dialog.Button.Large</item>
@@ -605,11 +628,11 @@
<item name="android:letterSpacing">0.01</item>
<item name="android:lineHeight">20sp</item>
<item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
- <item name="android:textColor">?android:attr/textColorSecondary</item>
+ <item name="android:textColor">?attr/onSurfaceVariant</item>
</style>
<style name="QSCustomizeToolbar" parent="@*android:style/Widget.DeviceDefault.Toolbar">
- <item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="android:textColor">?attr/onSurface</item>
<item name="android:elevation">10dp</item>
</style>
@@ -1055,7 +1078,7 @@
</style>
<style name="TextAppearance.Dialog.Title" parent="@android:style/TextAppearance.DeviceDefault.Large">
- <item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item>
<item name="android:textSize">@dimen/dialog_title_text_size</item>
<item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
<item name="android:lineHeight">32sp</item>
@@ -1064,7 +1087,7 @@
</style>
<style name="TextAppearance.Dialog.Body" parent="@android:style/TextAppearance.DeviceDefault.Medium">
- <item name="android:textColor">?android:attr/textColorSecondary</item>
+ <item name="android:textColor">?androidprv:attr/materialColorOnSurfaceVariant</item>
<item name="android:textSize">14sp</item>
<item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
<item name="android:lineHeight">20sp</item>
@@ -1092,7 +1115,7 @@
<style name="Widget.Dialog.Button">
<item name="android:buttonCornerRadius">28dp</item>
<item name="android:background">@drawable/qs_dialog_btn_filled</item>
- <item name="android:textColor">?androidprv:attr/textColorOnAccent</item>
+ <item name="android:textColor">?androidprv:attr/materialColorOnPrimary</item>
<item name="android:textSize">14sp</item>
<item name="android:lineHeight">20sp</item>
<item name="android:fontFamily">@*android:string/config_bodyFontFamilyMedium</item>
@@ -1102,12 +1125,18 @@
<style name="Widget.Dialog.Button.BorderButton">
<item name="android:background">@drawable/qs_dialog_btn_outline</item>
- <item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item>
</style>
<style name="Widget.Dialog.Button.Large">
<item name="android:background">@drawable/qs_dialog_btn_filled_large</item>
<item name="android:minHeight">56dp</item>
+ <item name="android:textColor">?androidprv:attr/materialColorOnPrimaryFixed</item>
+ </style>
+
+ <style name="Widget.Dialog.Button.QuickSettings">
+ <item name="android:textColor">?attr/primary</item>
+ <item name="android:background">?android:attr/selectableItemBackground</item>
</style>
<style name="MainSwitch.Settingslib" parent="@android:style/Theme.DeviceDefault">
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java
index 2e6c485..751a3f8 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java
@@ -104,8 +104,7 @@
* @return updated set of flags from InputMethodService based off {@param oldHints}
* Leaves original hints unmodified
*/
- public static int calculateBackDispositionHints(int oldHints,
- @InputMethodService.BackDispositionMode int backDisposition,
+ public static int calculateBackDispositionHints(int oldHints, int backDisposition,
boolean imeShown, boolean showImeSwitcher) {
int hints = oldHints;
switch (backDisposition) {
diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
index 84a2c25..91937af 100644
--- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
+++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
@@ -42,7 +42,7 @@
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel.DEBUG
+import com.android.systemui.log.core.LogLevel.DEBUG
import com.android.systemui.log.dagger.KeyguardLargeClockLog
import com.android.systemui.log.dagger.KeyguardSmallClockLog
import com.android.systemui.plugins.ClockController
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index 360f755..4793b4f 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -29,7 +29,7 @@
import com.android.keyguard.dagger.KeyguardStatusViewScope;
import com.android.systemui.R;
import com.android.systemui.log.LogBuffer;
-import com.android.systemui.log.LogLevel;
+import com.android.systemui.log.core.LogLevel;
import com.android.systemui.plugins.ClockController;
import com.android.systemui.shared.clocks.DefaultClockController;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index 62a2f90..dba1246 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -40,7 +40,7 @@
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.log.LogBuffer;
-import com.android.systemui.log.LogLevel;
+import com.android.systemui.log.core.LogLevel;
import com.android.systemui.log.dagger.KeyguardClockLog;
import com.android.systemui.plugins.ClockController;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
index 3e16d55..6f59684 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
@@ -43,6 +43,15 @@
private long mPinLength;
private boolean mDisabledAutoConfirmation;
+ /**
+ * Responsible for identifying if PIN hinting is to be enabled or not
+ */
+ private boolean mIsPinHinting;
+
+ /**
+ * Responsible for identifying if auto confirm is enabled or not in Settings
+ */
+ private boolean mIsAutoPinConfirmEnabledInSettings;
protected KeyguardPinViewController(KeyguardPINView view,
KeyguardUpdateMonitor keyguardUpdateMonitor,
@@ -63,6 +72,9 @@
mFeatureFlags = featureFlags;
mBackspaceKey = view.findViewById(R.id.delete_button);
mPinLength = mLockPatternUtils.getPinLength(KeyguardUpdateMonitor.getCurrentUser());
+ mIsPinHinting = mPinLength == DEFAULT_PIN_LENGTH;
+ mIsAutoPinConfirmEnabledInSettings = mLockPatternUtils.isAutoPinConfirmEnabled(
+ KeyguardUpdateMonitor.getCurrentUser());
}
@Override
@@ -82,7 +94,7 @@
protected void onUserInput() {
super.onUserInput();
- if (isAutoPinConfirmEnabledInSettings()) {
+ if (mIsAutoPinConfirmEnabledInSettings) {
updateAutoConfirmationState();
if (mPasswordEntry.getText().length() == mPinLength
&& mOkButton.getVisibility() == View.INVISIBLE) {
@@ -130,7 +142,7 @@
* Updates the visibility of the OK button for auto confirm feature
*/
private void updateOKButtonVisibility() {
- if (isAutoPinConfirmEnabledInSettings() && !mDisabledAutoConfirmation) {
+ if (mIsPinHinting && !mDisabledAutoConfirmation) {
mOkButton.setVisibility(View.INVISIBLE);
} else {
mOkButton.setVisibility(View.VISIBLE);
@@ -142,10 +154,9 @@
* Visibility changes are only for auto confirmation configuration.
*/
private void updateBackSpaceVisibility() {
- boolean isAutoConfirmation = isAutoPinConfirmEnabledInSettings();
mBackspaceKey.setTransparentMode(/* isTransparentMode= */
- isAutoConfirmation && !mDisabledAutoConfirmation);
- if (isAutoConfirmation) {
+ mIsAutoPinConfirmEnabledInSettings && !mDisabledAutoConfirmation);
+ if (mIsAutoPinConfirmEnabledInSettings) {
if (mPasswordEntry.getText().length() > 0
|| mDisabledAutoConfirmation) {
mBackspaceKey.setVisibility(View.VISIBLE);
@@ -155,24 +166,8 @@
}
}
/** Updates whether to use pin hinting or not. */
- void updatePinHinting() {
- mPasswordEntry.setIsPinHinting(isAutoPinConfirmEnabledInSettings() && isPinHinting()
+ private void updatePinHinting() {
+ mPasswordEntry.setIsPinHinting(mIsAutoPinConfirmEnabledInSettings && mIsPinHinting
&& !mDisabledAutoConfirmation);
}
-
- /**
- * Responsible for identifying if PIN hinting is to be enabled or not
- */
- private boolean isPinHinting() {
- return mLockPatternUtils.getPinLength(KeyguardUpdateMonitor.getCurrentUser())
- == DEFAULT_PIN_LENGTH;
- }
-
- /**
- * Responsible for identifying if auto confirm is enabled or not in Settings
- */
- private boolean isAutoPinConfirmEnabledInSettings() {
- //Checks if user has enabled the auto confirm in Settings
- return mLockPatternUtils.isAutoPinConfirmEnabled(KeyguardUpdateMonitor.getCurrentUser());
- }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 841b5b3..6853f81 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -281,6 +281,8 @@
public interface SwipeListener {
void onSwipeUp();
+ /** */
+ void onSwipeDown();
}
@VisibleForTesting
@@ -543,6 +545,11 @@
if (mSwipeListener != null) {
mSwipeListener.onSwipeUp();
}
+ } else if (getTranslationY() > TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+ MIN_DRAG_SIZE, getResources().getDisplayMetrics())) {
+ if (mSwipeListener != null) {
+ mSwipeListener.onSwipeDown();
+ }
}
}
return true;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index 7c511a3..880f242 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -70,11 +70,11 @@
import com.android.systemui.R;
import com.android.systemui.biometrics.SideFpsController;
import com.android.systemui.biometrics.SideFpsUiRequestSource;
+import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor;
import com.android.systemui.classifier.FalsingA11yDelegate;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
-import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor;
import com.android.systemui.log.SessionTracker;
import com.android.systemui.plugins.ActivityStarter;
@@ -319,6 +319,11 @@
"swipeUpOnBouncer");
}
}
+
+ @Override
+ public void onSwipeDown() {
+ mViewMediatorCallback.onBouncerSwipeDown();
+ }
};
private final ConfigurationController.ConfigurationListener mConfigurationListener =
new ConfigurationController.ConfigurationListener() {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 89ef749..c4ea45d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -24,6 +24,8 @@
import static android.content.Intent.ACTION_USER_REMOVED;
import static android.content.Intent.ACTION_USER_STOPPED;
import static android.content.Intent.ACTION_USER_UNLOCKED;
+import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
+import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_LOCKOUT_NONE;
import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_LOCKOUT_PERMANENT;
import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_LOCKOUT_TIMED;
@@ -251,6 +253,7 @@
private static final int MSG_REQUIRE_NFC_UNLOCK = 345;
private static final int MSG_KEYGUARD_DISMISS_ANIMATION_FINISHED = 346;
private static final int MSG_SERVICE_PROVIDERS_UPDATED = 347;
+ private static final int MSG_BIOMETRIC_ENROLLMENT_STATE_CHANGED = 348;
/** Biometric authentication state: Not listening. */
private static final int BIOMETRIC_STATE_STOPPED = 0;
@@ -2484,6 +2487,9 @@
case MSG_KEYGUARD_DISMISS_ANIMATION_FINISHED:
handleKeyguardDismissAnimationFinished();
break;
+ case MSG_BIOMETRIC_ENROLLMENT_STATE_CHANGED:
+ notifyAboutEnrollmentChange(msg.arg1);
+ break;
default:
super.handleMessage(msg);
break;
@@ -2584,6 +2590,8 @@
@Override
public void onEnrollmentsChanged(@BiometricAuthenticator.Modality int modality) {
+ mHandler.obtainMessage(MSG_BIOMETRIC_ENROLLMENT_STATE_CHANGED, modality, 0)
+ .sendToTarget();
mainExecutor.execute(() -> updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
FACE_AUTH_TRIGGERED_ENROLLMENTS_CHANGED));
}
@@ -3433,6 +3441,25 @@
return mIsFaceEnrolled;
}
+ private void notifyAboutEnrollmentChange(@BiometricAuthenticator.Modality int modality) {
+ BiometricSourceType biometricSourceType;
+ if (modality == TYPE_FINGERPRINT) {
+ biometricSourceType = FINGERPRINT;
+ } else if (modality == TYPE_FACE) {
+ biometricSourceType = FACE;
+ } else {
+ return;
+ }
+ mLogger.notifyAboutEnrollmentsChanged(biometricSourceType);
+ Assert.isMainThread();
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+ if (cb != null) {
+ cb.onBiometricEnrollmentStateChanged(biometricSourceType);
+ }
+ }
+ }
+
private void stopListeningForFingerprint() {
mLogger.v("stopListeningForFingerprint()");
if (mFingerprintRunningState == BIOMETRIC_STATE_RUNNING) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index 7394005..7b59632 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -327,4 +327,9 @@
* Called when the enabled trust agents associated with the specified user.
*/
public void onEnabledTrustAgentsChanged(int userId) { }
+
+ /**
+ * On biometric enrollment state changed
+ */
+ public void onBiometricEnrollmentStateChanged(BiometricSourceType biometricSourceType) { }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java b/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java
index 61af722..71f78c3 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java
@@ -23,7 +23,7 @@
import com.android.app.animation.Interpolators;
import com.android.systemui.log.LogBuffer;
-import com.android.systemui.log.LogLevel;
+import com.android.systemui.log.core.LogLevel;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.AnimatableProperty;
import com.android.systemui.statusbar.notification.PropertyAnimator;
diff --git a/packages/SystemUI/src/com/android/keyguard/ViewMediatorCallback.java b/packages/SystemUI/src/com/android/keyguard/ViewMediatorCallback.java
index 50f8f7e..14ec27a 100644
--- a/packages/SystemUI/src/com/android/keyguard/ViewMediatorCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/ViewMediatorCallback.java
@@ -104,4 +104,9 @@
* Call when cancel button is pressed in bouncer.
*/
void onCancelClicked();
+
+ /**
+ * Determines if bouncer has swiped down.
+ */
+ void onBouncerSwipeDown();
}
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/BiometricMessageDeferralLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/BiometricMessageDeferralLogger.kt
index e7295ef..54738c6 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/BiometricMessageDeferralLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/BiometricMessageDeferralLogger.kt
@@ -18,7 +18,7 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel.DEBUG
+import com.android.systemui.log.core.LogLevel.DEBUG
import com.android.systemui.log.dagger.BiometricLog
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/BiometricUnlockLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/BiometricUnlockLogger.kt
index c00b2c6..cfad614 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/BiometricUnlockLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/BiometricUnlockLogger.kt
@@ -19,9 +19,9 @@
import android.hardware.biometrics.BiometricSourceType
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
-import com.android.systemui.log.LogLevel.DEBUG
-import com.android.systemui.log.LogLevel.INFO
+import com.android.systemui.log.core.LogLevel
+import com.android.systemui.log.core.LogLevel.DEBUG
+import com.android.systemui.log.core.LogLevel.INFO
import com.android.systemui.log.dagger.BiometricLog
import com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_DISMISS_BOUNCER
import com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_NONE
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/CarrierTextManagerLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/CarrierTextManagerLogger.kt
index 1978715..d02b72f 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/CarrierTextManagerLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/CarrierTextManagerLogger.kt
@@ -19,7 +19,7 @@
import androidx.annotation.IntDef
import com.android.keyguard.CarrierTextManager.CarrierTextCallbackInfo
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.log.core.LogLevel
import com.android.systemui.log.dagger.CarrierTextManagerLog
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt
index 8b925b1..bddf3b0 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt
@@ -19,7 +19,7 @@
import com.android.systemui.biometrics.AuthRippleController
import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.log.core.LogLevel
import com.android.systemui.log.dagger.KeyguardLog
import com.android.systemui.statusbar.KeyguardIndicationController
import com.google.errorprone.annotations.CompileTimeConstant
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
index a192803..eec5b3e 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
@@ -18,6 +18,7 @@
import android.content.Intent
import android.hardware.biometrics.BiometricConstants.LockoutMode
+import android.hardware.biometrics.BiometricSourceType
import android.os.PowerManager
import android.os.PowerManager.WakeReason
import android.telephony.ServiceState
@@ -32,12 +33,12 @@
import com.android.keyguard.TrustGrantFlags
import com.android.settingslib.fuelgauge.BatteryStatus
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
-import com.android.systemui.log.LogLevel.DEBUG
-import com.android.systemui.log.LogLevel.ERROR
-import com.android.systemui.log.LogLevel.INFO
-import com.android.systemui.log.LogLevel.VERBOSE
-import com.android.systemui.log.LogLevel.WARNING
+import com.android.systemui.log.core.LogLevel
+import com.android.systemui.log.core.LogLevel.DEBUG
+import com.android.systemui.log.core.LogLevel.ERROR
+import com.android.systemui.log.core.LogLevel.INFO
+import com.android.systemui.log.core.LogLevel.VERBOSE
+import com.android.systemui.log.core.LogLevel.WARNING
import com.android.systemui.log.dagger.KeyguardUpdateMonitorLog
import com.google.errorprone.annotations.CompileTimeConstant
import javax.inject.Inject
@@ -370,16 +371,14 @@
fun logServiceProvidersUpdated(intent: Intent) {
logBuffer.log(
- TAG,
- VERBOSE,
- {
- int1 = intent.getIntExtra(EXTRA_SUBSCRIPTION_INDEX, INVALID_SUBSCRIPTION_ID)
- str1 = intent.getStringExtra(TelephonyManager.EXTRA_SPN)
- str2 = intent.getStringExtra(TelephonyManager.EXTRA_PLMN)
- },
- {
- "action SERVICE_PROVIDERS_UPDATED subId=$int1 spn=$str1 plmn=$str2"
- }
+ TAG,
+ VERBOSE,
+ {
+ int1 = intent.getIntExtra(EXTRA_SUBSCRIPTION_INDEX, INVALID_SUBSCRIPTION_ID)
+ str1 = intent.getStringExtra(TelephonyManager.EXTRA_SPN)
+ str2 = intent.getStringExtra(TelephonyManager.EXTRA_PLMN)
+ },
+ { "action SERVICE_PROVIDERS_UPDATED subId=$int1 spn=$str1 plmn=$str2" }
)
}
@@ -719,4 +718,13 @@
fun scheduleWatchdog(@CompileTimeConstant watchdogType: String) {
logBuffer.log(TAG, DEBUG, "Scheduling biometric watchdog for $watchdogType")
}
+
+ fun notifyAboutEnrollmentsChanged(biometricSourceType: BiometricSourceType) {
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ { str1 = "$biometricSourceType" },
+ { "notifying about enrollments changed: $str1" }
+ )
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/TrustRepositoryLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/TrustRepositoryLogger.kt
index cb764a8..57b5db1 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/TrustRepositoryLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/TrustRepositoryLogger.kt
@@ -21,8 +21,8 @@
import com.android.systemui.keyguard.shared.model.TrustManagedModel
import com.android.systemui.keyguard.shared.model.TrustModel
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
-import com.android.systemui.log.LogLevel.DEBUG
+import com.android.systemui.log.core.LogLevel
+import com.android.systemui.log.core.LogLevel.DEBUG
import com.android.systemui.log.dagger.KeyguardUpdateMonitorLog
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/authentication/AuthenticationModule.kt b/packages/SystemUI/src/com/android/systemui/authentication/AuthenticationModule.kt
index 7c394a6..6128d91 100644
--- a/packages/SystemUI/src/com/android/systemui/authentication/AuthenticationModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/authentication/AuthenticationModule.kt
@@ -16,8 +16,11 @@
package com.android.systemui.authentication
+import com.android.keyguard.KeyguardSecurityModel
import com.android.systemui.authentication.data.repository.AuthenticationRepositoryModule
import dagger.Module
+import dagger.Provides
+import java.util.function.Function
@Module(
includes =
@@ -25,4 +28,12 @@
AuthenticationRepositoryModule::class,
],
)
-object AuthenticationModule
+object AuthenticationModule {
+
+ @Provides
+ fun getSecurityMode(
+ model: KeyguardSecurityModel,
+ ): Function<Int, KeyguardSecurityModel.SecurityMode> {
+ return Function { userId -> model.getSecurityMode(userId) }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt b/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt
index 0530aed..0b25184 100644
--- a/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt
@@ -16,13 +16,25 @@
package com.android.systemui.authentication.data.repository
+import com.android.internal.widget.LockPatternUtils
+import com.android.keyguard.KeyguardSecurityModel
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.keyguard.data.repository.KeyguardRepository
+import com.android.systemui.user.data.repository.UserRepository
import dagger.Binds
import dagger.Module
+import java.util.function.Function
import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.withContext
/** Defines interface for classes that can access authentication-related application state. */
interface AuthenticationRepository {
@@ -38,12 +50,6 @@
val isUnlocked: StateFlow<Boolean>
/**
- * The currently-configured authentication method. This determines how the authentication
- * challenge is completed in order to unlock an otherwise locked device.
- */
- val authenticationMethod: StateFlow<AuthenticationMethodModel>
-
- /**
* Whether lock screen bypass is enabled. When enabled, the lock screen will be automatically
* dismisses once the authentication challenge is completed. For example, completing a biometric
* authentication challenge via face unlock or fingerprint sensor can automatically bypass the
@@ -57,11 +63,11 @@
*/
val failedAuthenticationAttempts: StateFlow<Int>
- /** See [isUnlocked]. */
- fun setUnlocked(isUnlocked: Boolean)
-
- /** See [authenticationMethod]. */
- fun setAuthenticationMethod(authenticationMethod: AuthenticationMethodModel)
+ /**
+ * Returns the currently-configured authentication method. This determines how the
+ * authentication challenge is completed in order to unlock an otherwise locked device.
+ */
+ suspend fun getAuthenticationMethod(): AuthenticationMethodModel
/** See [isBypassEnabled]. */
fun setBypassEnabled(isBypassEnabled: Boolean)
@@ -70,18 +76,23 @@
fun setFailedAuthenticationAttempts(failedAuthenticationAttempts: Int)
}
-class AuthenticationRepositoryImpl @Inject constructor() : AuthenticationRepository {
- // TODO(b/280883900): get data from real data sources in SysUI.
+class AuthenticationRepositoryImpl
+@Inject
+constructor(
+ @Application private val applicationScope: CoroutineScope,
+ private val getSecurityMode: Function<Int, KeyguardSecurityModel.SecurityMode>,
+ @Background private val backgroundDispatcher: CoroutineDispatcher,
+ private val userRepository: UserRepository,
+ private val lockPatternUtils: LockPatternUtils,
+ keyguardRepository: KeyguardRepository,
+) : AuthenticationRepository {
- private val _isUnlocked = MutableStateFlow(false)
- override val isUnlocked: StateFlow<Boolean> = _isUnlocked.asStateFlow()
-
- private val _authenticationMethod =
- MutableStateFlow<AuthenticationMethodModel>(
- AuthenticationMethodModel.Pin(listOf(1, 2, 3, 4), autoConfirm = false)
+ override val isUnlocked: StateFlow<Boolean> =
+ keyguardRepository.isKeyguardUnlocked.stateIn(
+ scope = applicationScope,
+ started = SharingStarted.WhileSubscribed(),
+ initialValue = false,
)
- override val authenticationMethod: StateFlow<AuthenticationMethodModel> =
- _authenticationMethod.asStateFlow()
private val _isBypassEnabled = MutableStateFlow(false)
override val isBypassEnabled: StateFlow<Boolean> = _isBypassEnabled.asStateFlow()
@@ -90,18 +101,45 @@
override val failedAuthenticationAttempts: StateFlow<Int> =
_failedAuthenticationAttempts.asStateFlow()
- override fun setUnlocked(isUnlocked: Boolean) {
- _isUnlocked.value = isUnlocked
+ override suspend fun getAuthenticationMethod(): AuthenticationMethodModel {
+ return withContext(backgroundDispatcher) {
+ val selectedUserId = userRepository.getSelectedUserInfo().id
+ when (getSecurityMode.apply(selectedUserId)) {
+ KeyguardSecurityModel.SecurityMode.PIN,
+ KeyguardSecurityModel.SecurityMode.SimPin ->
+ AuthenticationMethodModel.Pin(
+ code = listOf(1, 2, 3, 4), // TODO(b/280883900): remove this
+ autoConfirm = lockPatternUtils.isAutoPinConfirmEnabled(selectedUserId),
+ )
+ KeyguardSecurityModel.SecurityMode.Password,
+ KeyguardSecurityModel.SecurityMode.SimPuk ->
+ AuthenticationMethodModel.Password(
+ password = "password", // TODO(b/280883900): remove this
+ )
+ KeyguardSecurityModel.SecurityMode.Pattern ->
+ AuthenticationMethodModel.Pattern(
+ coordinates =
+ listOf(
+ AuthenticationMethodModel.Pattern.PatternCoordinate(2, 0),
+ AuthenticationMethodModel.Pattern.PatternCoordinate(2, 1),
+ AuthenticationMethodModel.Pattern.PatternCoordinate(2, 2),
+ AuthenticationMethodModel.Pattern.PatternCoordinate(1, 1),
+ AuthenticationMethodModel.Pattern.PatternCoordinate(0, 0),
+ AuthenticationMethodModel.Pattern.PatternCoordinate(0, 1),
+ AuthenticationMethodModel.Pattern.PatternCoordinate(0, 2),
+ ), // TODO(b/280883900): remove this
+ )
+ KeyguardSecurityModel.SecurityMode.None -> AuthenticationMethodModel.None
+ KeyguardSecurityModel.SecurityMode.Invalid -> error("Invalid security mode!")
+ null -> error("Invalid security is null!")
+ }
+ }
}
override fun setBypassEnabled(isBypassEnabled: Boolean) {
_isBypassEnabled.value = isBypassEnabled
}
- override fun setAuthenticationMethod(authenticationMethod: AuthenticationMethodModel) {
- _authenticationMethod.value = authenticationMethod
- }
-
override fun setFailedAuthenticationAttempts(failedAuthenticationAttempts: Int) {
_failedAuthenticationAttempts.value = failedAuthenticationAttempts
}
diff --git a/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt b/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
index 20e82f7..15e579d 100644
--- a/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
@@ -25,9 +25,8 @@
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
-import kotlinx.coroutines.launch
/** Hosts application business logic related to authentication. */
@SysUISingleton
@@ -38,12 +37,6 @@
private val repository: AuthenticationRepository,
) {
/**
- * The currently-configured authentication method. This determines how the authentication
- * challenge is completed in order to unlock an otherwise locked device.
- */
- val authenticationMethod: StateFlow<AuthenticationMethodModel> = repository.authenticationMethod
-
- /**
* Whether the device is unlocked.
*
* A device that is not yet unlocked requires unlocking by completing an authentication
@@ -52,20 +45,18 @@
* Note that this state has no real bearing on whether the lock screen is showing or dismissed.
*/
val isUnlocked: StateFlow<Boolean> =
- combine(authenticationMethod, repository.isUnlocked) { authMethod, isUnlocked ->
- isUnlockedWithAuthMethod(
- isUnlocked = isUnlocked,
- authMethod = authMethod,
- )
+ repository.isUnlocked
+ .map { isUnlocked ->
+ if (getAuthenticationMethod() is AuthenticationMethodModel.None) {
+ true
+ } else {
+ isUnlocked
+ }
}
.stateIn(
scope = applicationScope,
started = SharingStarted.Eagerly,
- initialValue =
- isUnlockedWithAuthMethod(
- isUnlocked = repository.isUnlocked.value,
- authMethod = repository.authenticationMethod.value,
- )
+ initialValue = true,
)
/**
@@ -82,41 +73,20 @@
*/
val failedAuthenticationAttempts: StateFlow<Int> = repository.failedAuthenticationAttempts
- init {
- // UNLOCKS WHEN AUTH METHOD REMOVED.
- //
- // Unlocks the device if the auth method becomes None.
- applicationScope.launch {
- repository.authenticationMethod.collect {
- if (it is AuthenticationMethodModel.None) {
- unlockDevice()
- }
- }
- }
+ /**
+ * Returns the currently-configured authentication method. This determines how the
+ * authentication challenge is completed in order to unlock an otherwise locked device.
+ */
+ suspend fun getAuthenticationMethod(): AuthenticationMethodModel {
+ return repository.getAuthenticationMethod()
}
/**
* Returns `true` if the device currently requires authentication before content can be viewed;
* `false` if content can be displayed without unlocking first.
*/
- fun isAuthenticationRequired(): Boolean {
- return !isUnlocked.value && authenticationMethod.value.isSecure
- }
-
- /**
- * Unlocks the device, assuming that the authentication challenge has been completed
- * successfully.
- */
- fun unlockDevice() {
- repository.setUnlocked(true)
- }
-
- /**
- * Locks the device. From now on, the device will remain locked until [authenticate] is called
- * with the correct input.
- */
- fun lockDevice() {
- repository.setUnlocked(false)
+ suspend fun isAuthenticationRequired(): Boolean {
+ return !isUnlocked.value && getAuthenticationMethod().isSecure
}
/**
@@ -133,8 +103,8 @@
* @return `true` if the authentication succeeded and the device is now unlocked; `false` when
* authentication failed, `null` if the check was not performed.
*/
- fun authenticate(input: List<Any>, tryAutoConfirm: Boolean = false): Boolean? {
- val authMethod = this.authenticationMethod.value
+ suspend fun authenticate(input: List<Any>, tryAutoConfirm: Boolean = false): Boolean? {
+ val authMethod = getAuthenticationMethod()
if (tryAutoConfirm) {
if ((authMethod as? AuthenticationMethodModel.Pin)?.autoConfirm != true) {
// Do not attempt to authenticate unless the PIN lock is set to auto-confirm.
@@ -160,7 +130,6 @@
if (isSuccessful) {
repository.setFailedAuthenticationAttempts(0)
- repository.setUnlocked(true)
} else {
repository.setFailedAuthenticationAttempts(
repository.failedAuthenticationAttempts.value + 1
@@ -170,34 +139,12 @@
return isSuccessful
}
- /** Triggers a biometric-powered unlock of the device. */
- fun biometricUnlock() {
- // TODO(b/280883900): only allow this if the biometric is enabled and there's a match.
- repository.setUnlocked(true)
- }
-
- /** See [authenticationMethod]. */
- fun setAuthenticationMethod(authenticationMethod: AuthenticationMethodModel) {
- repository.setAuthenticationMethod(authenticationMethod)
- }
-
/** See [isBypassEnabled]. */
fun toggleBypassEnabled() {
repository.setBypassEnabled(!repository.isBypassEnabled.value)
}
companion object {
- private fun isUnlockedWithAuthMethod(
- isUnlocked: Boolean,
- authMethod: AuthenticationMethodModel,
- ): Boolean {
- return if (authMethod is AuthenticationMethodModel.None) {
- true
- } else {
- isUnlocked
- }
- }
-
/**
* Returns a PIN code from the given list. It's assumed the given list elements are all
* [Int] in the range [0-9].
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
index 6f0f633..946ddba 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
@@ -37,7 +37,7 @@
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.WakefulnessLifecycle
-import com.android.systemui.log.LogLevel
+import com.android.systemui.log.core.LogLevel
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.CircleReveal
import com.android.systemui.statusbar.LiftReveal
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 0dc7974..dc9ba87 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -75,6 +75,8 @@
import com.android.systemui.biometrics.udfps.SinglePointerTouchProcessor;
import com.android.systemui.biometrics.udfps.TouchProcessor;
import com.android.systemui.biometrics.udfps.TouchProcessorResult;
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.doze.DozeReceiver;
@@ -82,9 +84,7 @@
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.ScreenLifecycle;
-import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor;
-import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
import com.android.systemui.log.SessionTracker;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -189,6 +189,8 @@
@Nullable private VelocityTracker mVelocityTracker;
// The ID of the pointer for which ACTION_DOWN has occurred. -1 means no pointer is active.
private int mActivePointerId = -1;
+ // Whether a pointer has been pilfered for current gesture
+ private boolean mPointerPilfered = false;
// The timestamp of the most recent touch log.
private long mTouchLogTime;
// The timestamp of the most recent log of a touch InteractionEvent.
@@ -258,10 +260,6 @@
@Override
public void showUdfpsOverlay(long requestId, int sensorId, int reason,
@NonNull IUdfpsOverlayControllerCallback callback) {
- if (mFeatureFlags.isEnabled(Flags.NEW_UDFPS_OVERLAY)) {
- return;
- }
-
mFgExecutor.execute(() -> UdfpsController.this.showUdfpsOverlay(
new UdfpsControllerOverlay(mContext, mFingerprintManager, mInflater,
mWindowManager, mAccessibilityManager, mStatusBarStateController,
@@ -279,10 +277,6 @@
@Override
public void hideUdfpsOverlay(int sensorId) {
- if (mFeatureFlags.isEnabled(Flags.NEW_UDFPS_OVERLAY)) {
- return;
- }
-
mFgExecutor.execute(() -> {
if (mKeyguardUpdateMonitor.isFingerprintDetectionRunning()) {
// if we get here, we expect keyguardUpdateMonitor's fingerprintRunningState
@@ -560,6 +554,11 @@
|| mPrimaryBouncerInteractor.isInTransit()) {
return false;
}
+ if (event.getAction() == MotionEvent.ACTION_DOWN
+ || event.getAction() == MotionEvent.ACTION_HOVER_ENTER) {
+ // Reset on ACTION_DOWN, start of new gesture
+ mPointerPilfered = false;
+ }
final TouchProcessorResult result = mTouchProcessor.processTouch(event, mActivePointerId,
mOverlayParams);
@@ -633,10 +632,11 @@
shouldPilfer = true;
}
- // Execute the pilfer
- if (shouldPilfer) {
+ // Pilfer only once per gesture
+ if (shouldPilfer && !mPointerPilfered) {
mInputManager.pilferPointers(
mOverlay.getOverlayView().getViewRootImpl().getInputToken());
+ mPointerPilfered = true;
}
return processedTouch.getTouchData().isWithinBounds(mOverlayParams.getNativeSensorBounds());
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsLogger.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsLogger.kt
index 39199d1..2102a1f 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsLogger.kt
@@ -17,10 +17,10 @@
package com.android.systemui.biometrics
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
-import com.android.systemui.log.LogLevel.ERROR
-import com.android.systemui.log.LogLevel.VERBOSE
-import com.android.systemui.log.LogLevel.WARNING
+import com.android.systemui.log.core.LogLevel
+import com.android.systemui.log.core.LogLevel.ERROR
+import com.android.systemui.log.core.LogLevel.VERBOSE
+import com.android.systemui.log.core.LogLevel.WARNING
import com.android.systemui.log.dagger.UdfpsLog
import com.google.errorprone.annotations.CompileTimeConstant
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/BluetoothLogger.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/BluetoothLogger.kt
index 96af42b..2a457eb 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/BluetoothLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/BluetoothLogger.kt
@@ -18,7 +18,7 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.log.core.LogLevel
import com.android.systemui.log.dagger.BluetoothLog
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt
index 256c635..5dd24b2 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt
@@ -35,6 +35,9 @@
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
@@ -68,44 +71,44 @@
)
)
- /**
- * The currently-configured authentication method. This determines how the authentication
- * challenge is completed in order to unlock an otherwise locked device.
- */
- val authenticationMethod: StateFlow<AuthenticationMethodModel> =
- authenticationInteractor.authenticationMethod
-
/** The current authentication throttling state. If `null`, there's no throttling. */
val throttling: StateFlow<AuthenticationThrottledModel?> = repository.throttling
init {
+ // UNLOCKING SHOWS Gone.
+ //
+ // Move to the gone scene if the device becomes unlocked while on the bouncer scene.
applicationScope.launch {
- combine(
- sceneInteractor.currentScene(containerName),
- authenticationInteractor.authenticationMethod,
- ::Pair,
- )
- .collect { (currentScene, authMethod) ->
+ sceneInteractor
+ .currentScene(containerName)
+ .flatMapLatest { currentScene ->
if (currentScene.key == SceneKey.Bouncer) {
- when (authMethod) {
- is AuthenticationMethodModel.None ->
- sceneInteractor.setCurrentScene(
- containerName,
- SceneModel(SceneKey.Gone),
- )
- is AuthenticationMethodModel.Swipe ->
- sceneInteractor.setCurrentScene(
- containerName,
- SceneModel(SceneKey.Lockscreen),
- )
- else -> Unit
- }
+ authenticationInteractor.isUnlocked
+ } else {
+ flowOf(false)
+ }
+ }
+ .distinctUntilChanged()
+ .collect { isUnlocked ->
+ if (isUnlocked) {
+ sceneInteractor.setCurrentScene(
+ containerName = containerName,
+ scene = SceneModel(SceneKey.Gone),
+ )
}
}
}
}
/**
+ * Returns the currently-configured authentication method. This determines how the
+ * authentication challenge is completed in order to unlock an otherwise locked device.
+ */
+ suspend fun getAuthenticationMethod(): AuthenticationMethodModel {
+ return authenticationInteractor.getAuthenticationMethod()
+ }
+
+ /**
* Either shows the bouncer or unlocks the device, if the bouncer doesn't need to be shown.
*
* @param containerName The name of the scene container to show the bouncer in.
@@ -115,18 +118,19 @@
containerName: String,
message: String? = null,
) {
- if (authenticationInteractor.isAuthenticationRequired()) {
- repository.setMessage(message ?: promptMessage(authenticationMethod.value))
- sceneInteractor.setCurrentScene(
- containerName = containerName,
- scene = SceneModel(SceneKey.Bouncer),
- )
- } else {
- authenticationInteractor.unlockDevice()
- sceneInteractor.setCurrentScene(
- containerName = containerName,
- scene = SceneModel(SceneKey.Gone),
- )
+ applicationScope.launch {
+ if (authenticationInteractor.isAuthenticationRequired()) {
+ repository.setMessage(message ?: promptMessage(getAuthenticationMethod()))
+ sceneInteractor.setCurrentScene(
+ containerName = containerName,
+ scene = SceneModel(SceneKey.Bouncer),
+ )
+ } else {
+ sceneInteractor.setCurrentScene(
+ containerName = containerName,
+ scene = SceneModel(SceneKey.Gone),
+ )
+ }
}
}
@@ -135,7 +139,7 @@
* method.
*/
fun resetMessage() {
- repository.setMessage(promptMessage(authenticationMethod.value))
+ applicationScope.launch { repository.setMessage(promptMessage(getAuthenticationMethod())) }
}
/** Removes the user-facing message. */
@@ -160,7 +164,7 @@
* @return `true` if the authentication succeeded and the device is now unlocked; `false` when
* authentication failed, `null` if the check was not performed.
*/
- fun authenticate(
+ suspend fun authenticate(
input: List<Any>,
tryAutoConfirm: Boolean = false,
): Boolean? {
@@ -198,7 +202,7 @@
repository.setThrottling(null)
clearMessage()
}
- else -> repository.setMessage(errorMessage(authenticationMethod.value))
+ else -> repository.setMessage(errorMessage(getAuthenticationMethod()))
}
return isAuthenticated
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt
index 527fe6e..b293ea6 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt
@@ -22,10 +22,13 @@
import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
import com.android.systemui.bouncer.shared.model.AuthenticationThrottledModel
import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.util.kotlin.pairwise
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.channels.BufferOverflow
+import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
@@ -66,6 +69,7 @@
private val password: PasswordBouncerViewModel by lazy {
PasswordBouncerViewModel(
+ applicationScope = applicationScope,
interactor = interactor,
isInputEnabled = isInputEnabled,
)
@@ -81,14 +85,30 @@
}
/** View-model for the current UI, based on the current authentication method. */
+ private val _authMethod =
+ MutableSharedFlow<AuthMethodBouncerViewModel?>(
+ replay = 1,
+ onBufferOverflow = BufferOverflow.DROP_OLDEST,
+ )
val authMethod: StateFlow<AuthMethodBouncerViewModel?> =
- interactor.authenticationMethod
- .map { authMethod -> toViewModel(authMethod) }
- .stateIn(
- scope = applicationScope,
- started = SharingStarted.WhileSubscribed(),
- initialValue = toViewModel(interactor.authenticationMethod.value),
- )
+ _authMethod.stateIn(
+ scope = applicationScope,
+ started = SharingStarted.WhileSubscribed(),
+ initialValue = null,
+ )
+
+ init {
+ applicationScope.launch {
+ _authMethod.subscriptionCount
+ .pairwise()
+ .map { (previousCount, currentCount) -> currentCount > previousCount }
+ .collect { subscriberAdded ->
+ if (subscriberAdded) {
+ reloadAuthMethod()
+ }
+ }
+ }
+ }
/** The user-facing message to show in the bouncer. */
val message: StateFlow<MessageViewModel> =
@@ -125,7 +145,7 @@
interactor.throttling
.map { model ->
model?.let {
- when (interactor.authenticationMethod.value) {
+ when (interactor.getAuthenticationMethod()) {
is AuthenticationMethodModel.Pin ->
R.string.kg_too_many_failed_pin_attempts_dialog_message
is AuthenticationMethodModel.Password ->
@@ -161,17 +181,6 @@
_throttlingDialogMessage.value = null
}
- private fun toViewModel(
- authMethod: AuthenticationMethodModel,
- ): AuthMethodBouncerViewModel? {
- return when (authMethod) {
- is AuthenticationMethodModel.Pin -> pin
- is AuthenticationMethodModel.Password -> password
- is AuthenticationMethodModel.Pattern -> pattern
- else -> null
- }
- }
-
private fun toMessageViewModel(
message: String?,
throttling: AuthenticationThrottledModel?,
@@ -182,6 +191,17 @@
)
}
+ private suspend fun reloadAuthMethod() {
+ _authMethod.tryEmit(
+ when (interactor.getAuthenticationMethod()) {
+ is AuthenticationMethodModel.Pin -> pin
+ is AuthenticationMethodModel.Password -> password
+ is AuthenticationMethodModel.Pattern -> pattern
+ else -> null
+ }
+ )
+ }
+
data class MessageViewModel(
val text: String,
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt
index 0146e40..ca15f4e 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt
@@ -17,12 +17,15 @@
package com.android.systemui.bouncer.ui.viewmodel
import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
+import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.launch
/** Holds UI state and handles user input for the password bouncer UI. */
class PasswordBouncerViewModel(
+ private val applicationScope: CoroutineScope,
private val interactor: BouncerInteractor,
isInputEnabled: StateFlow<Boolean>,
) :
@@ -50,10 +53,13 @@
/** Notifies that the user has pressed the key for attempting to authenticate the password. */
fun onAuthenticateKeyPressed() {
- if (interactor.authenticate(password.value.toCharArray().toList()) != true) {
- showFailureAnimation()
- }
-
+ val password = _password.value.toCharArray().toList()
_password.value = ""
+
+ applicationScope.launch {
+ if (interactor.authenticate(password) != true) {
+ showFailureAnimation()
+ }
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModel.kt
index 700703e..5efa6f0 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModel.kt
@@ -29,13 +29,15 @@
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.launch
/** Holds UI state and handles user input for the pattern bouncer UI. */
class PatternBouncerViewModel(
private val applicationContext: Context,
- applicationScope: CoroutineScope,
+ private val applicationScope: CoroutineScope,
private val interactor: BouncerInteractor,
isInputEnabled: StateFlow<Boolean>,
) :
@@ -69,12 +71,17 @@
/** Whether the pattern itself should be rendered visibly. */
val isPatternVisible: StateFlow<Boolean> =
- interactor.authenticationMethod
- .map { authMethod -> isPatternVisible(authMethod) }
+ flow {
+ emit(null)
+ emit(interactor.getAuthenticationMethod())
+ }
+ .map { authMethod ->
+ (authMethod as? AuthenticationMethodModel.Pattern)?.isPatternVisible ?: false
+ }
.stateIn(
scope = applicationScope,
started = SharingStarted.Eagerly,
- initialValue = isPatternVisible(interactor.authenticationMethod.value),
+ initialValue = false,
)
/** Notifies that the UI has been shown to the user. */
@@ -154,17 +161,15 @@
/** Notifies that the user has ended the drag gesture across the dot grid. */
fun onDragEnd() {
val pattern = _selectedDots.value.map { it.toCoordinate() }
- if (interactor.authenticate(pattern) != true) {
- showFailureAnimation()
- }
-
_dots.value = defaultDots()
_currentDot.value = null
_selectedDots.value = linkedSetOf()
- }
- private fun isPatternVisible(authMethodModel: AuthenticationMethodModel): Boolean {
- return (authMethodModel as? AuthenticationMethodModel.Pattern)?.isPatternVisible ?: false
+ applicationScope.launch {
+ if (interactor.authenticate(pattern) != true) {
+ showFailureAnimation()
+ }
+ }
}
private fun defaultDots(): List<PatternDotViewModel> {
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
index 1944c74..014ebc3 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
@@ -22,13 +22,14 @@
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.launch
/** Holds UI state and handles user input for the PIN code bouncer UI. */
class PinBouncerViewModel(
- applicationScope: CoroutineScope,
+ private val applicationScope: CoroutineScope,
private val interactor: BouncerInteractor,
isInputEnabled: StateFlow<Boolean>,
) :
@@ -39,40 +40,45 @@
private val mutablePinEntries = MutableStateFlow<List<EnteredKey>>(emptyList())
val pinEntries: StateFlow<List<EnteredKey>> = mutablePinEntries
- /** The length of the hinted PIN, or null if pin length hint should not be shown. */
+ /** The length of the hinted PIN, or `null` if pin length hint should not be shown. */
val hintedPinLength: StateFlow<Int?> =
- interactor.authenticationMethod
- .map { authMethod -> computeHintedPinLength(authMethod) }
- .stateIn(
- scope = applicationScope,
- started = SharingStarted.Eagerly,
- initialValue = computeHintedPinLength(interactor.authenticationMethod.value),
- )
-
- /** Appearance of the backspace button. */
- val backspaceButtonAppearance: StateFlow<ActionButtonAppearance> =
- combine(interactor.authenticationMethod, mutablePinEntries) { authMethod, enteredPin ->
- computeBackspaceButtonAppearance(authMethod, enteredPin)
+ flow { emit(interactor.getAuthenticationMethod()) }
+ .map { authMethod ->
+ // Hinting is enabled for 6-digit codes only
+ autoConfirmPinLength(authMethod).takeIf { it == HINTING_PASSCODE_LENGTH }
}
.stateIn(
scope = applicationScope,
started = SharingStarted.Eagerly,
- initialValue =
- computeBackspaceButtonAppearance(
- interactor.authenticationMethod.value,
- mutablePinEntries.value
- ),
+ initialValue = null,
+ )
+
+ /** Appearance of the backspace button. */
+ val backspaceButtonAppearance: StateFlow<ActionButtonAppearance> =
+ mutablePinEntries
+ .map { mutablePinEntries ->
+ computeBackspaceButtonAppearance(
+ interactor.getAuthenticationMethod(),
+ mutablePinEntries
+ )
+ }
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.Eagerly,
+ initialValue = ActionButtonAppearance.Hidden,
)
/** Appearance of the confirm button. */
val confirmButtonAppearance: StateFlow<ActionButtonAppearance> =
- interactor.authenticationMethod
+ flow {
+ emit(null)
+ emit(interactor.getAuthenticationMethod())
+ }
.map { authMethod -> computeConfirmButtonAppearance(authMethod) }
.stateIn(
scope = applicationScope,
started = SharingStarted.Eagerly,
- initialValue =
- computeConfirmButtonAppearance(interactor.authenticationMethod.value),
+ initialValue = ActionButtonAppearance.Hidden,
)
/** Notifies that the UI has been shown to the user. */
@@ -111,30 +117,28 @@
private fun tryAuthenticate(useAutoConfirm: Boolean) {
val pinCode = mutablePinEntries.value.map { it.input }
- val isSuccess = interactor.authenticate(pinCode, useAutoConfirm) ?: return
- if (!isSuccess) {
- showFailureAnimation()
+ applicationScope.launch {
+ val isSuccess = interactor.authenticate(pinCode, useAutoConfirm) ?: return@launch
+
+ if (!isSuccess) {
+ showFailureAnimation()
+ }
+
+ mutablePinEntries.value = emptyList()
}
-
- mutablePinEntries.value = emptyList()
}
- private fun isAutoConfirmEnabled(authMethodModel: AuthenticationMethodModel): Boolean {
+ private fun isAutoConfirmEnabled(authMethodModel: AuthenticationMethodModel?): Boolean {
return (authMethodModel as? AuthenticationMethodModel.Pin)?.autoConfirm == true
}
- private fun autoConfirmPinLength(authMethodModel: AuthenticationMethodModel): Int? {
+ private fun autoConfirmPinLength(authMethodModel: AuthenticationMethodModel?): Int? {
if (!isAutoConfirmEnabled(authMethodModel)) return null
return (authMethodModel as? AuthenticationMethodModel.Pin)?.code?.size
}
- private fun computeHintedPinLength(authMethodModel: AuthenticationMethodModel): Int? {
- // Hinting is enabled for 6-digit codes only
- return autoConfirmPinLength(authMethodModel).takeIf { it == HINTING_PASSCODE_LENGTH }
- }
-
private fun computeBackspaceButtonAppearance(
authMethodModel: AuthenticationMethodModel,
enteredPin: List<EnteredKey>
@@ -149,7 +153,7 @@
}
}
private fun computeConfirmButtonAppearance(
- authMethodModel: AuthenticationMethodModel
+ authMethodModel: AuthenticationMethodModel?
): ActionButtonAppearance {
return if (isAutoConfirmEnabled(authMethodModel)) {
ActionButtonAppearance.Hidden
diff --git a/packages/SystemUI/src/com/android/systemui/broadcast/logging/BroadcastDispatcherLogger.kt b/packages/SystemUI/src/com/android/systemui/broadcast/logging/BroadcastDispatcherLogger.kt
index 5b3a982..068f329 100644
--- a/packages/SystemUI/src/com/android/systemui/broadcast/logging/BroadcastDispatcherLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/broadcast/logging/BroadcastDispatcherLogger.kt
@@ -21,10 +21,10 @@
import android.content.Intent
import android.content.IntentFilter
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
-import com.android.systemui.log.LogLevel.DEBUG
-import com.android.systemui.log.LogLevel.INFO
-import com.android.systemui.log.LogMessage
+import com.android.systemui.log.core.LogLevel
+import com.android.systemui.log.core.LogLevel.DEBUG
+import com.android.systemui.log.core.LogLevel.INFO
+import com.android.systemui.log.core.LogMessage
import com.android.systemui.log.dagger.BroadcastDispatcherLog
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt
index d629e3e..8e41974 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt
@@ -154,7 +154,7 @@
private fun bindViews() {
setContentView(R.layout.controls_management)
- getLifecycle().addObserver(
+ lifecycle.addObserver(
ControlsAnimations.observerForAnimations(
requireViewById<ViewGroup>(R.id.controls_management_root),
window,
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
index d3ffc95..d3aa449 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
@@ -268,7 +268,7 @@
private fun bindViews() {
setContentView(R.layout.controls_management)
- getLifecycle().addObserver(
+ lifecycle.addObserver(
ControlsAnimations.observerForAnimations(
requireViewById<ViewGroup>(R.id.controls_management_root),
window,
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt
index fb19ac9..d5b8693 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt
@@ -91,7 +91,7 @@
setContentView(R.layout.controls_management)
- getLifecycle().addObserver(
+ lifecycle.addObserver(
ControlsAnimations.observerForAnimations(
requireViewById<ViewGroup>(R.id.controls_management_root),
window,
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt
index 4a22e4e..557dcf4 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt
@@ -72,7 +72,7 @@
setContentView(R.layout.controls_fullscreen)
- getLifecycle().addObserver(
+ lifecycle.addObserver(
ControlsAnimations.observerForAnimations(
requireViewById(R.id.control_detail_root),
window,
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 9ab9e7a..8f3c3d6 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -47,6 +47,7 @@
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dagger.qualifiers.SystemUser;
import com.android.systemui.demomode.dagger.DemoModeModule;
+import com.android.systemui.display.DisplayModule;
import com.android.systemui.doze.dagger.DozeComponent;
import com.android.systemui.dreams.dagger.DreamModule;
import com.android.systemui.dump.DumpManager;
@@ -163,6 +164,7 @@
ClipboardOverlayModule.class,
ClockRegistryModule.class,
CommonRepositoryModule.class,
+ DisplayModule.class,
ConnectivityModule.class,
CoroutinesModule.class,
DreamModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/display/DisplayModule.kt b/packages/SystemUI/src/com/android/systemui/display/DisplayModule.kt
new file mode 100644
index 0000000..65cd84b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/display/DisplayModule.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.display
+
+import com.android.systemui.display.data.repository.DisplayRepository
+import com.android.systemui.display.data.repository.DisplayRepositoryImpl
+import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor
+import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractorImpl
+import dagger.Binds
+import dagger.Module
+
+/** Module binding display related classes. */
+@Module
+interface DisplayModule {
+ @Binds
+ fun bindConnectedDisplayInteractor(
+ provider: ConnectedDisplayInteractorImpl
+ ): ConnectedDisplayInteractor
+
+ @Binds fun bindsDisplayRepository(displayRepository: DisplayRepositoryImpl): DisplayRepository
+}
diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayMetricsRepository.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayMetricsRepository.kt
new file mode 100644
index 0000000..bcfeeb9e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayMetricsRepository.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.display.data.repository
+
+import android.content.Context
+import android.content.res.Configuration
+import android.util.DisplayMetrics
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.core.LogLevel
+import com.android.systemui.log.dagger.DisplayMetricsRepoLog
+import com.android.systemui.statusbar.policy.ConfigurationController
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.stateIn
+
+/** Repository tracking display-related metrics like display height and width. */
+@SysUISingleton
+class DisplayMetricsRepository
+@Inject
+constructor(
+ @Application scope: CoroutineScope,
+ configurationController: ConfigurationController,
+ displayMetricsHolder: DisplayMetrics,
+ context: Context,
+ @DisplayMetricsRepoLog logBuffer: LogBuffer,
+) {
+
+ private val displayMetrics: StateFlow<DisplayMetrics> =
+ conflatedCallbackFlow {
+ val callback =
+ object : ConfigurationController.ConfigurationListener {
+ override fun onConfigChanged(newConfig: Configuration?) {
+ context.display.getMetrics(displayMetricsHolder)
+ trySend(displayMetricsHolder)
+ }
+ }
+ configurationController.addCallback(callback)
+ awaitClose { configurationController.removeCallback(callback) }
+ }
+ .onEach {
+ logBuffer.log(
+ "DisplayMetrics",
+ LogLevel.INFO,
+ { str1 = it.toString() },
+ { "New metrics: $str1" },
+ )
+ }
+ .stateIn(scope, SharingStarted.Eagerly, displayMetricsHolder)
+
+ /** Returns the current display height in pixels. */
+ val heightPixels: Int
+ get() = displayMetrics.value.heightPixels
+}
diff --git a/packages/SystemUI/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractor.kt b/packages/SystemUI/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractor.kt
new file mode 100644
index 0000000..4b957c7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractor.kt
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.display.domain.interactor
+
+import android.view.Display
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.display.data.repository.DisplayRepository
+import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor.State
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.map
+
+/** Provides information about an external connected display. */
+interface ConnectedDisplayInteractor {
+ /**
+ * Provides the current external display state.
+ *
+ * The state is:
+ * - [State.CONNECTED] when there is at least one display with [TYPE_EXTERNAL].
+ * - [State.CONNECTED_SECURE] when is at least one display with both [TYPE_EXTERNAL] AND
+ * [Display.FLAG_SECURE] set
+ */
+ val connectedDisplayState: Flow<State>
+
+ /** Possible connected display state. */
+ enum class State {
+ DISCONNECTED,
+ CONNECTED,
+ CONNECTED_SECURE,
+ }
+}
+
+@SysUISingleton
+class ConnectedDisplayInteractorImpl
+@Inject
+constructor(
+ displayRepository: DisplayRepository,
+) : ConnectedDisplayInteractor {
+
+ override val connectedDisplayState: Flow<State> =
+ displayRepository.displays
+ .map { displays ->
+ val externalDisplays =
+ displays.filter { display -> display.type == Display.TYPE_EXTERNAL }
+
+ val secureExternalDisplays =
+ externalDisplays.filter { it.flags and Display.FLAG_SECURE != 0 }
+
+ if (externalDisplays.isEmpty()) {
+ State.DISCONNECTED
+ } else if (!secureExternalDisplays.isEmpty()) {
+ State.CONNECTED_SECURE
+ } else {
+ State.CONNECTED
+ }
+ }
+ .distinctUntilChanged()
+}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt b/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt
index 5369780..75b8e51 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt
@@ -20,9 +20,9 @@
import com.android.systemui.doze.DozeLog.Reason
import com.android.systemui.doze.DozeLog.reasonToString
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel.DEBUG
-import com.android.systemui.log.LogLevel.ERROR
-import com.android.systemui.log.LogLevel.INFO
+import com.android.systemui.log.core.LogLevel.DEBUG
+import com.android.systemui.log.core.LogLevel.ERROR
+import com.android.systemui.log.core.LogLevel.INFO
import com.android.systemui.log.dagger.DozeLog
import com.android.systemui.statusbar.policy.DevicePostureController
import com.google.errorprone.annotations.CompileTimeConstant
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamLogger.kt b/packages/SystemUI/src/com/android/systemui/dreams/DreamLogger.kt
index fdb7651..0e22406 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamLogger.kt
@@ -17,7 +17,7 @@
package com.android.systemui.dreams
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.log.core.LogLevel
import com.android.systemui.log.dagger.DreamLog
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayLifecycleOwner.kt b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayLifecycleOwner.kt
index 8325356..003d2c7 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayLifecycleOwner.kt
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayLifecycleOwner.kt
@@ -28,7 +28,8 @@
class DreamOverlayLifecycleOwner @Inject constructor() : LifecycleOwner {
val registry: LifecycleRegistry = LifecycleRegistry(this)
- override fun getLifecycle(): Lifecycle {
- return registry
- }
+ override val lifecycle: Lifecycle
+ get() {
+ return registry
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 6242492..db5f546 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -151,12 +151,6 @@
// TODO(b/255607168): Tracking Bug
@JvmField val DOZING_MIGRATION_1 = unreleasedFlag(213, "dozing_migration_1")
- // TODO(b/252897742): Tracking Bug
- @JvmField val NEW_ELLIPSE_DETECTION = unreleasedFlag(214, "new_ellipse_detection")
-
- // TODO(b/252897742): Tracking Bug
- @JvmField val NEW_UDFPS_OVERLAY = unreleasedFlag(215, "new_udfps_overlay")
-
/**
* Whether to enable the code powering customizable lock screen quick affordances.
*
@@ -730,6 +724,11 @@
val SPLIT_SHADE_SUBPIXEL_OPTIMIZATION =
releasedFlag(2805, "split_shade_subpixel_optimization")
+ // TODO(b/288868056): Tracking Bug
+ @JvmField
+ val PARTIAL_SCREEN_SHARING_TASK_SWITCHER =
+ unreleasedFlag(288868056, "pss_task_switcher")
+
// TODO(b/278761837): Tracking Bug
@JvmField
val USE_NEW_ACTIVITY_STARTER = releasedFlag(2801, name = "use_new_activity_starter")
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
index e8881a4..df83aaf 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
@@ -59,7 +59,7 @@
// At startup, 2 views with the ID `R.id.keyguard_indication_area` will be available.
// Disable one of them
if (featureFlags.isEnabled(Flags.MIGRATE_INDICATION_AREA)) {
- legacyParent.requireViewById<View>(R.id.keyguard_indication_area).let {
+ legacyParent.findViewById<View>(R.id.keyguard_indication_area)?.let {
legacyParent.removeView(it)
}
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index c629ebf..155e023 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -835,6 +835,11 @@
}
@Override
+ public void onBouncerSwipeDown() {
+ mKeyguardViewControllerLazy.get().reset(/* hideBouncerWhenShowing= */ true);
+ }
+
+ @Override
public void playTrustedSound() {
KeyguardViewMediator.this.playTrustedSound();
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
index 128057a..3d8f6fd 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
@@ -254,13 +254,17 @@
private fun observeFaceDetectGatingChecks() {
// Face detection can run only when lockscreen bypass is enabled
- // & detection is supported & biometric unlock is not allowed.
+ // & detection is supported
+ // & biometric unlock is not allowed
+ // or user is trusted by trust manager & we want to run face detect to dismiss keyguard
listOf(
canFaceAuthOrDetectRun(faceDetectLog),
logAndObserve(isBypassEnabled, "isBypassEnabled", faceDetectLog),
logAndObserve(
- biometricSettingsRepository.isNonStrongBiometricAllowed.isFalse(),
- "nonStrongBiometricIsNotAllowed",
+ biometricSettingsRepository.isNonStrongBiometricAllowed
+ .isFalse()
+ .or(trustRepository.isCurrentUserTrusted),
+ "nonStrongBiometricIsNotAllowedOrCurrentUserIsTrusted",
faceDetectLog
),
// We don't want to run face detect if fingerprint can be used to unlock the device
@@ -312,18 +316,19 @@
tableLogBuffer
),
logAndObserve(
- keyguardRepository.wakefulness.map { it.isStartingToSleepOrAsleep() }.isFalse(),
- "deviceNotSleepingOrNotStartingToSleep",
+ keyguardRepository.wakefulness.map { it.isStartingToSleep() }.isFalse(),
+ "deviceNotStartingToSleep",
tableLogBuffer
),
logAndObserve(
- combine(
- keyguardInteractor.isSecureCameraActive,
- alternateBouncerInteractor.isVisible
- ) { a, b ->
- !a || b
- },
- "secureCameraNotActiveOrAltBouncerIsShowing",
+ keyguardInteractor.isSecureCameraActive
+ .isFalse()
+ .or(
+ alternateBouncerInteractor.isVisible.or(
+ keyguardInteractor.primaryBouncerShowing
+ )
+ ),
+ "secureCameraNotActiveOrAnyBouncerIsShowing",
tableLogBuffer
),
logAndObserve(
@@ -365,6 +370,7 @@
"nonStrongBiometricIsAllowed",
faceAuthLog
),
+ logAndObserve(isAuthenticated.isFalse(), "faceNotAuthenticated", faceAuthLog),
)
.reduce(::and)
.distinctUntilChanged()
@@ -639,6 +645,10 @@
private fun and(flow: Flow<Boolean>, anotherFlow: Flow<Boolean>) =
flow.combine(anotherFlow) { a, b -> a && b }
+/** Combine two boolean flows by or-ing both of them */
+private fun Flow<Boolean>.or(anotherFlow: Flow<Boolean>) =
+ this.combine(anotherFlow) { a, b -> a || b }
+
/** "Not" the given flow. The return [Flow] will be true when [this] flow is false. */
private fun Flow<Boolean>.isFalse(): Flow<Boolean> {
return this.map { !it }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
index 81f62b6..edc0b45 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
@@ -302,7 +302,15 @@
trySendWithFailureLogging(
keyguardStateController.isUnlocked,
TAG,
- "updated isKeyguardUnlocked"
+ "updated isKeyguardUnlocked due to onUnlockedChanged"
+ )
+ }
+
+ override fun onKeyguardShowingChanged() {
+ trySendWithFailureLogging(
+ keyguardStateController.isUnlocked,
+ TAG,
+ "updated isKeyguardUnlocked due to onKeyguardShowingChanged"
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
index 38eacce..8f0b91b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
@@ -22,7 +22,6 @@
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
-import com.android.systemui.keyguard.shared.model.TransitionInfo
import com.android.systemui.keyguard.shared.model.WakefulnessState
import com.android.systemui.util.kotlin.Utils.Companion.toQuad
import com.android.systemui.util.kotlin.Utils.Companion.toQuint
@@ -38,11 +37,14 @@
class FromAlternateBouncerTransitionInteractor
@Inject
constructor(
+ override val transitionRepository: KeyguardTransitionRepository,
+ override val transitionInteractor: KeyguardTransitionInteractor,
@Application private val scope: CoroutineScope,
private val keyguardInteractor: KeyguardInteractor,
- private val keyguardTransitionRepository: KeyguardTransitionRepository,
- private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
-) : TransitionInteractor(FromAlternateBouncerTransitionInteractor::class.simpleName!!) {
+) :
+ TransitionInteractor(
+ fromState = KeyguardState.ALTERNATE_BOUNCER,
+ ) {
override fun start() {
listenForAlternateBouncerToGone()
@@ -60,7 +62,7 @@
.sample(
combine(
keyguardInteractor.primaryBouncerShowing,
- keyguardTransitionInteractor.startedKeyguardTransitionStep,
+ transitionInteractor.startedKeyguardTransitionStep,
keyguardInteractor.wakefulnessModel,
keyguardInteractor.isAodAvailable,
::toQuad
@@ -92,14 +94,7 @@
} else {
KeyguardState.LOCKSCREEN
}
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- ownerName = name,
- from = KeyguardState.ALTERNATE_BOUNCER,
- to = to,
- animator = getAnimator(),
- )
- )
+ startTransitionTo(to)
}
}
}
@@ -108,17 +103,10 @@
private fun listenForAlternateBouncerToGone() {
scope.launch {
keyguardInteractor.isKeyguardGoingAway
- .sample(keyguardTransitionInteractor.finishedKeyguardState, ::Pair)
+ .sample(transitionInteractor.finishedKeyguardState, ::Pair)
.collect { (isKeyguardGoingAway, keyguardState) ->
if (isKeyguardGoingAway && keyguardState == KeyguardState.ALTERNATE_BOUNCER) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- ownerName = name,
- from = KeyguardState.ALTERNATE_BOUNCER,
- to = KeyguardState.GONE,
- animator = getAnimator(),
- )
- )
+ startTransitionTo(KeyguardState.GONE)
}
}
}
@@ -127,26 +115,19 @@
private fun listenForAlternateBouncerToPrimaryBouncer() {
scope.launch {
keyguardInteractor.primaryBouncerShowing
- .sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
.collect { (isPrimaryBouncerShowing, startedKeyguardState) ->
if (
isPrimaryBouncerShowing &&
startedKeyguardState.to == KeyguardState.ALTERNATE_BOUNCER
) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- ownerName = name,
- from = KeyguardState.ALTERNATE_BOUNCER,
- to = KeyguardState.PRIMARY_BOUNCER,
- animator = getAnimator(),
- )
- )
+ startTransitionTo(KeyguardState.PRIMARY_BOUNCER)
}
}
}
}
- private fun getAnimator(): ValueAnimator {
+ override fun getDefaultAnimatorForTransitionsToState(toState: KeyguardState): ValueAnimator {
return ValueAnimator().apply {
interpolator = Interpolators.LINEAR
duration = TRANSITION_DURATION_MS
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
index 7e9cbc1..2085c87 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
@@ -24,7 +24,6 @@
import com.android.systemui.keyguard.shared.model.BiometricUnlockModel.Companion.isWakeAndUnlock
import com.android.systemui.keyguard.shared.model.DozeStateModel
import com.android.systemui.keyguard.shared.model.KeyguardState
-import com.android.systemui.keyguard.shared.model.TransitionInfo
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -34,11 +33,14 @@
class FromAodTransitionInteractor
@Inject
constructor(
+ override val transitionRepository: KeyguardTransitionRepository,
+ override val transitionInteractor: KeyguardTransitionInteractor,
@Application private val scope: CoroutineScope,
private val keyguardInteractor: KeyguardInteractor,
- private val keyguardTransitionRepository: KeyguardTransitionRepository,
- private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
-) : TransitionInteractor(FromAodTransitionInteractor::class.simpleName!!) {
+) :
+ TransitionInteractor(
+ fromState = KeyguardState.AOD,
+ ) {
override fun start() {
listenForAodToLockscreen()
@@ -49,18 +51,11 @@
scope.launch {
keyguardInteractor
.dozeTransitionTo(DozeStateModel.FINISH)
- .sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
.collect { pair ->
val (dozeToAod, lastStartedStep) = pair
if (lastStartedStep.to == KeyguardState.AOD) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- name,
- KeyguardState.AOD,
- KeyguardState.LOCKSCREEN,
- getAnimator(),
- )
- )
+ startTransitionTo(KeyguardState.LOCKSCREEN)
}
}
}
@@ -69,29 +64,22 @@
private fun listenForAodToGone() {
scope.launch {
keyguardInteractor.biometricUnlockState
- .sample(keyguardTransitionInteractor.finishedKeyguardState, ::Pair)
+ .sample(transitionInteractor.finishedKeyguardState, ::Pair)
.collect { pair ->
val (biometricUnlockState, keyguardState) = pair
if (
keyguardState == KeyguardState.AOD && isWakeAndUnlock(biometricUnlockState)
) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- name,
- KeyguardState.AOD,
- KeyguardState.GONE,
- getAnimator(),
- )
- )
+ startTransitionTo(KeyguardState.GONE)
}
}
}
}
- private fun getAnimator(): ValueAnimator {
+ override fun getDefaultAnimatorForTransitionsToState(toState: KeyguardState): ValueAnimator {
return ValueAnimator().apply {
- setInterpolator(Interpolators.LINEAR)
- setDuration(TRANSITION_DURATION_MS)
+ interpolator = Interpolators.LINEAR
+ duration = TRANSITION_DURATION_MS
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
index ee2c2df..c867c43 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
@@ -23,10 +23,8 @@
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.BiometricUnlockModel.Companion.isWakeAndUnlock
import com.android.systemui.keyguard.shared.model.KeyguardState
-import com.android.systemui.keyguard.shared.model.TransitionInfo
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
-import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
@@ -35,11 +33,14 @@
class FromDozingTransitionInteractor
@Inject
constructor(
+ override val transitionRepository: KeyguardTransitionRepository,
+ override val transitionInteractor: KeyguardTransitionInteractor,
@Application private val scope: CoroutineScope,
private val keyguardInteractor: KeyguardInteractor,
- private val keyguardTransitionRepository: KeyguardTransitionRepository,
- private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
-) : TransitionInteractor(FromDozingTransitionInteractor::class.simpleName!!) {
+) :
+ TransitionInteractor(
+ fromState = KeyguardState.DOZING,
+ ) {
override fun start() {
listenForDozingToLockscreen()
@@ -49,20 +50,13 @@
private fun listenForDozingToLockscreen() {
scope.launch {
keyguardInteractor.wakefulnessModel
- .sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
.collect { (wakefulnessModel, lastStartedTransition) ->
if (
wakefulnessModel.isStartingToWakeOrAwake() &&
lastStartedTransition.to == KeyguardState.DOZING
) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- name,
- KeyguardState.DOZING,
- KeyguardState.LOCKSCREEN,
- getAnimator(),
- )
- )
+ startTransitionTo(KeyguardState.LOCKSCREEN)
}
}
}
@@ -71,29 +65,22 @@
private fun listenForDozingToGone() {
scope.launch {
keyguardInteractor.biometricUnlockState
- .sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
.collect { (biometricUnlockState, lastStartedTransition) ->
if (
lastStartedTransition.to == KeyguardState.DOZING &&
isWakeAndUnlock(biometricUnlockState)
) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- name,
- KeyguardState.DOZING,
- KeyguardState.GONE,
- getAnimator(),
- )
- )
+ startTransitionTo(KeyguardState.GONE)
}
}
}
}
- private fun getAnimator(duration: Duration = DEFAULT_DURATION): ValueAnimator {
+ override fun getDefaultAnimatorForTransitionsToState(toState: KeyguardState): ValueAnimator {
return ValueAnimator().apply {
- setInterpolator(Interpolators.LINEAR)
- setDuration(duration.inWholeMilliseconds)
+ interpolator = Interpolators.LINEAR
+ duration = DEFAULT_DURATION.inWholeMilliseconds
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
index ccf4bc1..98d7434 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
@@ -24,11 +24,9 @@
import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
import com.android.systemui.keyguard.shared.model.DozeStateModel
import com.android.systemui.keyguard.shared.model.KeyguardState
-import com.android.systemui.keyguard.shared.model.TransitionInfo
import com.android.systemui.util.kotlin.Utils.Companion.toTriple
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
-import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
@@ -40,11 +38,14 @@
class FromDreamingTransitionInteractor
@Inject
constructor(
+ override val transitionRepository: KeyguardTransitionRepository,
+ override val transitionInteractor: KeyguardTransitionInteractor,
@Application private val scope: CoroutineScope,
private val keyguardInteractor: KeyguardInteractor,
- private val keyguardTransitionRepository: KeyguardTransitionRepository,
- private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
-) : TransitionInteractor(FromDreamingTransitionInteractor::class.simpleName!!) {
+) :
+ TransitionInteractor(
+ fromState = KeyguardState.DREAMING,
+ ) {
override fun start() {
listenForDreamingToOccluded()
@@ -54,15 +55,8 @@
fun startToLockscreenTransition() {
scope.launch {
- if (keyguardTransitionInteractor.startedKeyguardState.value == KeyguardState.DREAMING) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- name,
- KeyguardState.DREAMING,
- KeyguardState.LOCKSCREEN,
- getAnimator(TO_LOCKSCREEN_DURATION),
- )
- )
+ if (transitionInteractor.startedKeyguardState.value == KeyguardState.DREAMING) {
+ startTransitionTo(KeyguardState.LOCKSCREEN)
}
}
}
@@ -76,7 +70,7 @@
.sample(
combine(
keyguardInteractor.isKeyguardOccluded,
- keyguardTransitionInteractor.startedKeyguardTransitionStep,
+ transitionInteractor.startedKeyguardTransitionStep,
::Pair,
),
::toTriple
@@ -92,14 +86,7 @@
// action. There's no great signal to determine when the dream is ending
// and a transition to OCCLUDED is beginning directly. For now, the solution
// is DREAMING->LOCKSCREEN->OCCLUDED
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- name,
- lastStartedTransition.to,
- KeyguardState.OCCLUDED,
- getAnimator(),
- )
- )
+ startTransitionTo(KeyguardState.OCCLUDED)
}
}
}
@@ -109,14 +96,7 @@
scope.launch {
keyguardInteractor.biometricUnlockState.collect { biometricUnlockState ->
if (biometricUnlockState == BiometricUnlockModel.WAKE_AND_UNLOCK_FROM_DREAM) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- name,
- KeyguardState.DREAMING,
- KeyguardState.GONE,
- getAnimator(),
- )
- )
+ startTransitionTo(KeyguardState.GONE)
}
}
}
@@ -126,7 +106,7 @@
scope.launch {
combine(
keyguardInteractor.dozeTransitionModel,
- keyguardTransitionInteractor.finishedKeyguardState,
+ transitionInteractor.finishedKeyguardState,
::Pair
)
.collect { (dozeTransitionModel, keyguardState) ->
@@ -134,23 +114,18 @@
dozeTransitionModel.to == DozeStateModel.DOZE &&
keyguardState == KeyguardState.DREAMING
) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- name,
- KeyguardState.DREAMING,
- KeyguardState.DOZING,
- getAnimator(),
- )
- )
+ startTransitionTo(KeyguardState.DOZING)
}
}
}
}
- private fun getAnimator(duration: Duration = DEFAULT_DURATION): ValueAnimator {
+ override fun getDefaultAnimatorForTransitionsToState(toState: KeyguardState): ValueAnimator {
return ValueAnimator().apply {
- setInterpolator(Interpolators.LINEAR)
- setDuration(duration.inWholeMilliseconds)
+ interpolator = Interpolators.LINEAR
+ duration =
+ if (toState == KeyguardState.LOCKSCREEN) TO_LOCKSCREEN_DURATION.inWholeMilliseconds
+ else DEFAULT_DURATION.inWholeMilliseconds
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
index cfcb654..f82633f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
@@ -22,12 +22,10 @@
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
-import com.android.systemui.keyguard.shared.model.TransitionInfo
import com.android.systemui.keyguard.shared.model.WakefulnessState
import com.android.systemui.util.kotlin.Utils.Companion.toTriple
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
-import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.combine
@@ -37,11 +35,14 @@
class FromGoneTransitionInteractor
@Inject
constructor(
+ override val transitionRepository: KeyguardTransitionRepository,
+ override val transitionInteractor: KeyguardTransitionInteractor,
@Application private val scope: CoroutineScope,
private val keyguardInteractor: KeyguardInteractor,
- private val keyguardTransitionRepository: KeyguardTransitionRepository,
- private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
-) : TransitionInteractor(FromGoneTransitionInteractor::class.simpleName!!) {
+) :
+ TransitionInteractor(
+ fromState = KeyguardState.GONE,
+ ) {
override fun start() {
listenForGoneToAodOrDozing()
@@ -53,17 +54,10 @@
private fun listenForGoneToLockscreen() {
scope.launch {
keyguardInteractor.isKeyguardShowing
- .sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
.collect { (isKeyguardShowing, lastStartedStep) ->
if (isKeyguardShowing && lastStartedStep.to == KeyguardState.GONE) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- name,
- KeyguardState.GONE,
- KeyguardState.LOCKSCREEN,
- getAnimator(),
- )
- )
+ startTransitionTo(KeyguardState.LOCKSCREEN)
}
}
}
@@ -72,17 +66,10 @@
private fun listenForGoneToDreaming() {
scope.launch {
keyguardInteractor.isAbleToDream
- .sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
.collect { (isAbleToDream, lastStartedStep) ->
if (isAbleToDream && lastStartedStep.to == KeyguardState.GONE) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- name,
- KeyguardState.GONE,
- KeyguardState.DREAMING,
- getAnimator(TO_DREAMING_DURATION),
- )
- )
+ startTransitionTo(KeyguardState.DREAMING)
}
}
}
@@ -93,7 +80,7 @@
keyguardInteractor.wakefulnessModel
.sample(
combine(
- keyguardTransitionInteractor.startedKeyguardTransitionStep,
+ transitionInteractor.startedKeyguardTransitionStep,
keyguardInteractor.isAodAvailable,
::Pair
),
@@ -104,30 +91,24 @@
lastStartedStep.to == KeyguardState.GONE &&
wakefulnessState.state == WakefulnessState.STARTING_TO_SLEEP
) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- name,
- KeyguardState.GONE,
- if (isAodAvailable) {
- KeyguardState.AOD
- } else {
- KeyguardState.DOZING
- },
- getAnimator(),
- )
+ startTransitionTo(
+ if (isAodAvailable) KeyguardState.AOD else KeyguardState.DOZING
)
}
}
}
}
- private fun getAnimator(duration: Duration = DEFAULT_DURATION): ValueAnimator {
+ override fun getDefaultAnimatorForTransitionsToState(toState: KeyguardState): ValueAnimator {
return ValueAnimator().apply {
- setInterpolator(Interpolators.LINEAR)
- setDuration(duration.inWholeMilliseconds)
+ interpolator = Interpolators.LINEAR
+ duration =
+ when (toState) {
+ KeyguardState.DREAMING -> TO_DREAMING_DURATION
+ else -> DEFAULT_DURATION
+ }.inWholeMilliseconds
}
}
-
companion object {
private val DEFAULT_DURATION = 500.milliseconds
val TO_DREAMING_DURATION = 933.milliseconds
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
index b5e289f..b796334 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
@@ -32,7 +32,6 @@
import com.android.systemui.util.kotlin.sample
import java.util.UUID
import javax.inject.Inject
-import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.combine
@@ -42,12 +41,15 @@
class FromLockscreenTransitionInteractor
@Inject
constructor(
+ override val transitionRepository: KeyguardTransitionRepository,
+ override val transitionInteractor: KeyguardTransitionInteractor,
@Application private val scope: CoroutineScope,
private val keyguardInteractor: KeyguardInteractor,
private val shadeRepository: ShadeRepository,
- private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
- private val keyguardTransitionRepository: KeyguardTransitionRepository,
-) : TransitionInteractor(FromLockscreenTransitionInteractor::class.simpleName!!) {
+) :
+ TransitionInteractor(
+ fromState = KeyguardState.LOCKSCREEN,
+ ) {
override fun start() {
listenForLockscreenToGone()
@@ -66,8 +68,8 @@
keyguardInteractor.isAbleToDream
.sample(
combine(
- keyguardTransitionInteractor.startedKeyguardTransitionStep,
- keyguardTransitionInteractor.finishedKeyguardState,
+ transitionInteractor.startedKeyguardTransitionStep,
+ transitionInteractor.finishedKeyguardState,
::Pair
),
::toTriple
@@ -78,14 +80,7 @@
lastStartedTransition.to == KeyguardState.LOCKSCREEN &&
!invalidFromStates.contains(lastStartedTransition.from)
if (isAbleToDream && (isOnLockscreen || isTransitionInterruptible)) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- name,
- KeyguardState.LOCKSCREEN,
- KeyguardState.DREAMING,
- getAnimator(TO_DREAMING_DURATION),
- )
- )
+ startTransitionTo(KeyguardState.DREAMING)
}
}
}
@@ -94,20 +89,13 @@
private fun listenForLockscreenToPrimaryBouncer() {
scope.launch {
keyguardInteractor.primaryBouncerShowing
- .sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
.collect { pair ->
val (isBouncerShowing, lastStartedTransitionStep) = pair
if (
isBouncerShowing && lastStartedTransitionStep.to == KeyguardState.LOCKSCREEN
) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- ownerName = name,
- from = KeyguardState.LOCKSCREEN,
- to = KeyguardState.PRIMARY_BOUNCER,
- animator = getAnimator(),
- )
- )
+ startTransitionTo(KeyguardState.PRIMARY_BOUNCER)
}
}
}
@@ -116,21 +104,14 @@
private fun listenForLockscreenToAlternateBouncer() {
scope.launch {
keyguardInteractor.alternateBouncerShowing
- .sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
.collect { pair ->
val (isAlternateBouncerShowing, lastStartedTransitionStep) = pair
if (
isAlternateBouncerShowing &&
lastStartedTransitionStep.to == KeyguardState.LOCKSCREEN
) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- ownerName = name,
- from = KeyguardState.LOCKSCREEN,
- to = KeyguardState.ALTERNATE_BOUNCER,
- animator = getAnimator(),
- )
- )
+ startTransitionTo(KeyguardState.ALTERNATE_BOUNCER)
}
}
}
@@ -143,7 +124,7 @@
shadeRepository.shadeModel
.sample(
combine(
- keyguardTransitionInteractor.startedKeyguardTransitionStep,
+ transitionInteractor.startedKeyguardTransitionStep,
keyguardInteractor.statusBarState,
keyguardInteractor.isKeyguardUnlocked,
::Triple
@@ -164,7 +145,7 @@
} else {
TransitionState.RUNNING
}
- keyguardTransitionRepository.updateTransition(
+ transitionRepository.updateTransition(
id,
1f - shadeModel.expansionAmount,
nextState,
@@ -178,13 +159,17 @@
}
// If canceled, just put the state back
+ // TODO: This logic should happen in FromPrimaryBouncerInteractor.
if (nextState == TransitionState.CANCELED) {
- keyguardTransitionRepository.startTransition(
+ transitionRepository.startTransition(
TransitionInfo(
ownerName = name,
from = KeyguardState.PRIMARY_BOUNCER,
to = KeyguardState.LOCKSCREEN,
- animator = getAnimator(0.milliseconds)
+ animator =
+ getDefaultAnimatorForTransitionsToState(KeyguardState.LOCKSCREEN).apply {
+ duration = 0
+ }
)
)
}
@@ -198,15 +183,7 @@
!isKeyguardUnlocked &&
statusBarState == KEYGUARD
) {
- transitionId =
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- ownerName = name,
- from = KeyguardState.LOCKSCREEN,
- to = KeyguardState.PRIMARY_BOUNCER,
- animator = null,
- )
- )
+ transitionId = startTransitionTo(KeyguardState.PRIMARY_BOUNCER)
}
}
}
@@ -216,18 +193,11 @@
private fun listenForLockscreenToGone() {
scope.launch {
keyguardInteractor.isKeyguardGoingAway
- .sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
.collect { pair ->
val (isKeyguardGoingAway, lastStartedStep) = pair
if (isKeyguardGoingAway && lastStartedStep.to == KeyguardState.LOCKSCREEN) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- name,
- KeyguardState.LOCKSCREEN,
- KeyguardState.GONE,
- getAnimator(),
- )
- )
+ startTransitionTo(KeyguardState.GONE)
}
}
}
@@ -238,7 +208,7 @@
keyguardInteractor.isKeyguardOccluded
.sample(
combine(
- keyguardTransitionInteractor.finishedKeyguardState,
+ transitionInteractor.finishedKeyguardState,
keyguardInteractor.isDreaming,
::Pair
),
@@ -246,14 +216,7 @@
)
.collect { (isOccluded, keyguardState, isDreaming) ->
if (isOccluded && !isDreaming && keyguardState == KeyguardState.LOCKSCREEN) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- name,
- keyguardState,
- KeyguardState.OCCLUDED,
- getAnimator(TO_OCCLUDED_DURATION),
- )
- )
+ startTransitionTo(KeyguardState.OCCLUDED)
}
}
}
@@ -263,7 +226,7 @@
private fun listenForLockscreenToCamera() {
scope.launch {
keyguardInteractor.onCameraLaunchDetected
- .sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
.collect { (_, lastStartedStep) ->
// DREAMING/AOD/OFF may trigger on the first power button push, so include this
// state in order to cancel and correct the transition
@@ -274,14 +237,7 @@
lastStartedStep.to == KeyguardState.AOD ||
lastStartedStep.to == KeyguardState.OFF
) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- name,
- KeyguardState.LOCKSCREEN,
- KeyguardState.OCCLUDED,
- getAnimator(TO_OCCLUDED_DURATION),
- )
- )
+ startTransitionTo(KeyguardState.OCCLUDED)
}
}
}
@@ -292,7 +248,7 @@
keyguardInteractor.wakefulnessModel
.sample(
combine(
- keyguardTransitionInteractor.startedKeyguardTransitionStep,
+ transitionInteractor.startedKeyguardTransitionStep,
keyguardInteractor.isAodAvailable,
::Pair
),
@@ -303,27 +259,23 @@
lastStartedStep.to == KeyguardState.LOCKSCREEN &&
wakefulnessState.state == WakefulnessState.STARTING_TO_SLEEP
) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- name,
- KeyguardState.LOCKSCREEN,
- if (isAodAvailable) {
- KeyguardState.AOD
- } else {
- KeyguardState.DOZING
- },
- getAnimator(),
- )
+ startTransitionTo(
+ if (isAodAvailable) KeyguardState.AOD else KeyguardState.DOZING
)
}
}
}
}
- private fun getAnimator(duration: Duration = DEFAULT_DURATION): ValueAnimator {
+ override fun getDefaultAnimatorForTransitionsToState(toState: KeyguardState): ValueAnimator {
return ValueAnimator().apply {
- setInterpolator(Interpolators.LINEAR)
- setDuration(duration.inWholeMilliseconds)
+ interpolator = Interpolators.LINEAR
+ duration =
+ when (toState) {
+ KeyguardState.DREAMING -> TO_DREAMING_DURATION
+ KeyguardState.OCCLUDED -> TO_OCCLUDED_DURATION
+ else -> DEFAULT_DURATION
+ }.inWholeMilliseconds
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
index b0dbc59..a8147d0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
@@ -22,12 +22,10 @@
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
-import com.android.systemui.keyguard.shared.model.TransitionInfo
import com.android.systemui.keyguard.shared.model.WakefulnessState
import com.android.systemui.util.kotlin.Utils.Companion.toTriple
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
-import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.combine
@@ -37,11 +35,14 @@
class FromOccludedTransitionInteractor
@Inject
constructor(
+ override val transitionRepository: KeyguardTransitionRepository,
+ override val transitionInteractor: KeyguardTransitionInteractor,
@Application private val scope: CoroutineScope,
private val keyguardInteractor: KeyguardInteractor,
- private val keyguardTransitionRepository: KeyguardTransitionRepository,
- private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
-) : TransitionInteractor(FromOccludedTransitionInteractor::class.simpleName!!) {
+) :
+ TransitionInteractor(
+ fromState = KeyguardState.OCCLUDED,
+ ) {
override fun start() {
listenForOccludedToLockscreen()
@@ -54,18 +55,11 @@
private fun listenForOccludedToDreaming() {
scope.launch {
keyguardInteractor.isAbleToDream
- .sample(keyguardTransitionInteractor.finishedKeyguardState, ::Pair)
+ .sample(transitionInteractor.finishedKeyguardState, ::Pair)
.collect { pair ->
val (isAbleToDream, keyguardState) = pair
if (isAbleToDream && keyguardState == KeyguardState.OCCLUDED) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- name,
- KeyguardState.OCCLUDED,
- KeyguardState.DREAMING,
- getAnimator(),
- )
- )
+ startTransitionTo(KeyguardState.DREAMING)
}
}
}
@@ -77,7 +71,7 @@
.sample(
combine(
keyguardInteractor.isKeyguardShowing,
- keyguardTransitionInteractor.startedKeyguardTransitionStep,
+ transitionInteractor.startedKeyguardTransitionStep,
::Pair
),
::toTriple
@@ -90,14 +84,7 @@
isShowing &&
lastStartedKeyguardState.to == KeyguardState.OCCLUDED
) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- name,
- KeyguardState.OCCLUDED,
- KeyguardState.LOCKSCREEN,
- getAnimator(TO_LOCKSCREEN_DURATION),
- )
- )
+ startTransitionTo(KeyguardState.LOCKSCREEN)
}
}
}
@@ -109,7 +96,7 @@
.sample(
combine(
keyguardInteractor.isKeyguardShowing,
- keyguardTransitionInteractor.startedKeyguardTransitionStep,
+ transitionInteractor.startedKeyguardTransitionStep,
::Pair
),
::toTriple
@@ -122,14 +109,7 @@
!isShowing &&
lastStartedKeyguardState.to == KeyguardState.OCCLUDED
) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- name,
- KeyguardState.OCCLUDED,
- KeyguardState.GONE,
- getAnimator(),
- )
- )
+ startTransitionTo(KeyguardState.GONE)
}
}
}
@@ -140,7 +120,7 @@
keyguardInteractor.wakefulnessModel
.sample(
combine(
- keyguardTransitionInteractor.startedKeyguardTransitionStep,
+ transitionInteractor.startedKeyguardTransitionStep,
keyguardInteractor.isAodAvailable,
::Pair
),
@@ -151,17 +131,8 @@
lastStartedStep.to == KeyguardState.OCCLUDED &&
wakefulnessState.state == WakefulnessState.STARTING_TO_SLEEP
) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- name,
- KeyguardState.OCCLUDED,
- if (isAodAvailable) {
- KeyguardState.AOD
- } else {
- KeyguardState.DOZING
- },
- getAnimator(),
- )
+ startTransitionTo(
+ if (isAodAvailable) KeyguardState.AOD else KeyguardState.DOZING
)
}
}
@@ -171,29 +142,26 @@
private fun listenForOccludedToAlternateBouncer() {
scope.launch {
keyguardInteractor.alternateBouncerShowing
- .sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
.collect { (isAlternateBouncerShowing, lastStartedTransitionStep) ->
if (
isAlternateBouncerShowing &&
lastStartedTransitionStep.to == KeyguardState.OCCLUDED
) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- ownerName = name,
- from = KeyguardState.OCCLUDED,
- to = KeyguardState.ALTERNATE_BOUNCER,
- animator = getAnimator(),
- )
- )
+ startTransitionTo(KeyguardState.ALTERNATE_BOUNCER)
}
}
}
}
- private fun getAnimator(duration: Duration = DEFAULT_DURATION): ValueAnimator {
+ override fun getDefaultAnimatorForTransitionsToState(toState: KeyguardState): ValueAnimator {
return ValueAnimator().apply {
- setInterpolator(Interpolators.LINEAR)
- setDuration(duration.inWholeMilliseconds)
+ interpolator = Interpolators.LINEAR
+ duration =
+ when (toState) {
+ KeyguardState.LOCKSCREEN -> TO_LOCKSCREEN_DURATION
+ else -> DEFAULT_DURATION
+ }.inWholeMilliseconds
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
index da09e1f..e1754f5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
@@ -25,12 +25,10 @@
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
-import com.android.systemui.keyguard.shared.model.TransitionInfo
import com.android.systemui.keyguard.shared.model.WakefulnessState
import com.android.systemui.util.kotlin.Utils.Companion.toQuad
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
-import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.combine
@@ -40,12 +38,15 @@
class FromPrimaryBouncerTransitionInteractor
@Inject
constructor(
+ override val transitionRepository: KeyguardTransitionRepository,
+ override val transitionInteractor: KeyguardTransitionInteractor,
@Application private val scope: CoroutineScope,
private val keyguardInteractor: KeyguardInteractor,
- private val keyguardTransitionRepository: KeyguardTransitionRepository,
- private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
private val keyguardSecurityModel: KeyguardSecurityModel,
-) : TransitionInteractor(FromPrimaryBouncerTransitionInteractor::class.simpleName!!) {
+) :
+ TransitionInteractor(
+ fromState = KeyguardState.PRIMARY_BOUNCER,
+ ) {
override fun start() {
listenForPrimaryBouncerToGone()
@@ -59,7 +60,7 @@
.sample(
combine(
keyguardInteractor.wakefulnessModel,
- keyguardTransitionInteractor.startedKeyguardTransitionStep,
+ transitionInteractor.startedKeyguardTransitionStep,
keyguardInteractor.isKeyguardOccluded,
::Triple
),
@@ -73,20 +74,8 @@
(wakefulnessState.state == WakefulnessState.AWAKE ||
wakefulnessState.state == WakefulnessState.STARTING_TO_WAKE)
) {
- val to =
- if (occluded) {
- KeyguardState.OCCLUDED
- } else {
- KeyguardState.LOCKSCREEN
- }
-
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- ownerName = name,
- from = KeyguardState.PRIMARY_BOUNCER,
- to = to,
- animator = getAnimator(),
- )
+ startTransitionTo(
+ if (occluded) KeyguardState.OCCLUDED else KeyguardState.LOCKSCREEN
)
}
}
@@ -99,7 +88,7 @@
.sample(
combine(
keyguardInteractor.wakefulnessModel,
- keyguardTransitionInteractor.startedKeyguardTransitionStep,
+ transitionInteractor.startedKeyguardTransitionStep,
keyguardInteractor.isAodAvailable,
::Triple
),
@@ -114,20 +103,8 @@
(wakefulnessState.state == WakefulnessState.STARTING_TO_SLEEP ||
wakefulnessState.state == WakefulnessState.ASLEEP)
) {
- val to =
- if (isAodAvailable) {
- KeyguardState.AOD
- } else {
- KeyguardState.DOZING
- }
-
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- ownerName = name,
- from = KeyguardState.PRIMARY_BOUNCER,
- to = to,
- animator = getAnimator(),
- )
+ startTransitionTo(
+ if (isAodAvailable) KeyguardState.AOD else KeyguardState.DOZING
)
}
}
@@ -137,7 +114,7 @@
private fun listenForPrimaryBouncerToGone() {
scope.launch {
keyguardInteractor.isKeyguardGoingAway
- .sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
.collect { (isKeyguardGoingAway, lastStartedTransitionStep) ->
if (
isKeyguardGoingAway &&
@@ -154,24 +131,24 @@
} else {
TO_GONE_DURATION
}
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- ownerName = name,
- from = KeyguardState.PRIMARY_BOUNCER,
- to = KeyguardState.GONE,
- animator = getAnimator(duration),
- ),
- resetIfCanceled = true,
+
+ startTransitionTo(
+ toState = KeyguardState.GONE,
+ animator =
+ getDefaultAnimatorForTransitionsToState(KeyguardState.GONE).apply {
+ this.duration = duration.inWholeMilliseconds
+ },
+ resetIfCancelled = true
)
}
}
}
}
- private fun getAnimator(duration: Duration = DEFAULT_DURATION): ValueAnimator {
+ override fun getDefaultAnimatorForTransitionsToState(toState: KeyguardState): ValueAnimator {
return ValueAnimator().apply {
- setInterpolator(Interpolators.LINEAR)
- setDuration(duration.inWholeMilliseconds)
+ interpolator = Interpolators.LINEAR
+ duration = DEFAULT_DURATION.inWholeMilliseconds
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
index 7c5641f..4f7abd4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
@@ -19,7 +19,7 @@
import com.android.keyguard.logging.KeyguardLogger
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.log.LogLevel.VERBOSE
+import com.android.systemui.log.core.LogLevel.VERBOSE
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
index 42f12f8..df7c79f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
@@ -47,6 +47,8 @@
private val repository: KeyguardTransitionRepository,
@Application val scope: CoroutineScope,
) {
+ private val TAG = this::class.simpleName
+
/** (any)->GONE transition information */
val anyStateToGoneTransition: Flow<TransitionStep> =
repository.transitions.filter { step -> step.to == KeyguardState.GONE }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractor.kt
index d0bc25f..c8f7efb 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractor.kt
@@ -23,7 +23,6 @@
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
-import com.android.systemui.util.kotlin.pairwise
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
@@ -61,23 +60,16 @@
/** Whether it's currently possible to swipe up to dismiss the lockscreen. */
val isSwipeToDismissEnabled: StateFlow<Boolean> =
- combine(
- authenticationInteractor.isUnlocked,
- authenticationInteractor.authenticationMethod,
- ) { isUnlocked, authMethod ->
- isSwipeToUnlockEnabled(
- isUnlocked = isUnlocked,
- authMethod = authMethod,
- )
+ authenticationInteractor.isUnlocked
+ .map { isUnlocked ->
+ !isUnlocked &&
+ authenticationInteractor.getAuthenticationMethod() is
+ AuthenticationMethodModel.Swipe
}
.stateIn(
scope = applicationScope,
started = SharingStarted.WhileSubscribed(),
- initialValue =
- isSwipeToUnlockEnabled(
- isUnlocked = authenticationInteractor.isUnlocked.value,
- authMethod = authenticationInteractor.authenticationMethod.value,
- ),
+ initialValue = false,
)
init {
@@ -118,51 +110,6 @@
}
}
}
-
- // SWIPE TO DISMISS Lockscreen.
- //
- // If switched from the lockscreen to the gone scene and the auth method was a swipe,
- // unlocks the device.
- applicationScope.launch {
- combine(
- authenticationInteractor.authenticationMethod,
- sceneInteractor.currentScene(containerName).pairwise(),
- ::Pair,
- )
- .collect { (authMethod, scenes) ->
- val (previousScene, currentScene) = scenes
- if (
- authMethod is AuthenticationMethodModel.Swipe &&
- previousScene.key == SceneKey.Lockscreen &&
- currentScene.key == SceneKey.Gone
- ) {
- authenticationInteractor.unlockDevice()
- }
- }
- }
-
- // DISMISS Lockscreen IF AUTH METHOD IS REMOVED.
- //
- // If the auth method becomes None while on the lockscreen scene, dismisses the lock
- // screen.
- applicationScope.launch {
- combine(
- authenticationInteractor.authenticationMethod,
- sceneInteractor.currentScene(containerName),
- ::Pair,
- )
- .collect { (authMethod, scene) ->
- if (
- scene.key == SceneKey.Lockscreen &&
- authMethod == AuthenticationMethodModel.None
- ) {
- sceneInteractor.setCurrentScene(
- containerName = containerName,
- scene = SceneModel(SceneKey.Gone),
- )
- }
- }
- }
}
/** Attempts to dismiss the lockscreen. This will cause the bouncer to show, if needed. */
@@ -170,13 +117,6 @@
bouncerInteractor.showOrUnlockDevice(containerName = containerName)
}
- private fun isSwipeToUnlockEnabled(
- isUnlocked: Boolean,
- authMethod: AuthenticationMethodModel,
- ): Boolean {
- return !isUnlocked && authMethod is AuthenticationMethodModel.Swipe
- }
-
@AssistedFactory
interface Factory {
fun create(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt
index 8b749f0..d467225 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt
@@ -16,9 +16,12 @@
package com.android.systemui.keyguard.domain.interactor
+import android.content.Context
+import android.hardware.biometrics.BiometricFaceConstants
import com.android.keyguard.FaceAuthUiEvent
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.CoreStartable
+import com.android.systemui.R
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.dagger.SysUISingleton
@@ -27,6 +30,8 @@
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.data.repository.DeviceEntryFaceAuthRepository
+import com.android.systemui.keyguard.shared.model.AuthenticationStatus
+import com.android.systemui.keyguard.shared.model.ErrorAuthenticationStatus
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.log.FaceAuthenticationLogger
import com.android.systemui.util.kotlin.pairwise
@@ -34,7 +39,9 @@
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
@@ -50,6 +57,7 @@
class SystemUIKeyguardFaceAuthInteractor
@Inject
constructor(
+ private val context: Context,
@Application private val applicationScope: CoroutineScope,
@Main private val mainDispatcher: CoroutineDispatcher,
private val repository: DeviceEntryFaceAuthRepository,
@@ -157,17 +165,28 @@
repository.cancel()
}
+ private val _authenticationStatusOverride = MutableStateFlow<AuthenticationStatus?>(null)
/** Provide the status of face authentication */
- override val authenticationStatus = repository.authenticationStatus
+ override val authenticationStatus =
+ merge(_authenticationStatusOverride.filterNotNull(), repository.authenticationStatus)
/** Provide the status of face detection */
override val detectionStatus = repository.detectionStatus
private fun runFaceAuth(uiEvent: FaceAuthUiEvent, fallbackToDetect: Boolean) {
if (featureFlags.isEnabled(Flags.FACE_AUTH_REFACTOR)) {
- applicationScope.launch {
- faceAuthenticationLogger.authRequested(uiEvent)
- repository.authenticate(uiEvent, fallbackToDetection = fallbackToDetect)
+ if (repository.isLockedOut.value) {
+ _authenticationStatusOverride.value =
+ ErrorAuthenticationStatus(
+ BiometricFaceConstants.FACE_ERROR_LOCKOUT_PERMANENT,
+ context.resources.getString(R.string.keyguard_face_unlock_unavailable)
+ )
+ } else {
+ _authenticationStatusOverride.value = null
+ applicationScope.launch {
+ faceAuthenticationLogger.authRequested(uiEvent)
+ repository.authenticate(uiEvent, fallbackToDetection = fallbackToDetect)
+ }
}
} else {
faceAuthenticationLogger.ignoredFaceAuthTrigger(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/TransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/TransitionInteractor.kt
index b7dd1a5..ae6fc9e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/TransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/TransitionInteractor.kt
@@ -15,6 +15,14 @@
*/
package com.android.systemui.keyguard.domain.interactor
+
+import android.animation.ValueAnimator
+import android.util.Log
+import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionInfo
+import java.util.UUID
+
/**
* Each TransitionInteractor is responsible for determining under which conditions to notify
* [KeyguardTransitionRepository] to signal a transition. When (and if) the transition occurs is
@@ -26,6 +34,50 @@
* MUST list implementing classes in dagger module [StartKeyguardTransitionModule] and also in the
* 'when' clause of [KeyguardTransitionCoreStartable]
*/
-sealed class TransitionInteractor(val name: String) {
+sealed class TransitionInteractor(
+ val fromState: KeyguardState,
+) {
+ val name = this::class.simpleName ?: "UnknownTransitionInteractor"
+
+ abstract val transitionRepository: KeyguardTransitionRepository
+ abstract val transitionInteractor: KeyguardTransitionInteractor
abstract fun start()
+
+ fun startTransitionTo(
+ toState: KeyguardState,
+ animator: ValueAnimator? = getDefaultAnimatorForTransitionsToState(toState),
+ resetIfCancelled: Boolean = false
+ ): UUID? {
+ if (
+ fromState != transitionInteractor.startedKeyguardState.value &&
+ fromState != transitionInteractor.finishedKeyguardState.value
+ ) {
+ Log.e(
+ name,
+ "startTransition: We were asked to transition from " +
+ "$fromState to $toState, however we last finished a transition to " +
+ "${transitionInteractor.finishedKeyguardState.value}, " +
+ "and last started a transition to " +
+ "${transitionInteractor.startedKeyguardState.value}. " +
+ "Ignoring startTransition, but this should never happen."
+ )
+ return null
+ }
+
+ return transitionRepository.startTransition(
+ TransitionInfo(
+ name,
+ fromState,
+ toState,
+ animator,
+ ),
+ resetIfCancelled
+ )
+ }
+
+ /**
+ * Returns a ValueAnimator to be used for transitions to [toState], if one is not explicitly
+ * passed to [startTransitionTo].
+ */
+ abstract fun getDefaultAnimatorForTransitionsToState(toState: KeyguardState): ValueAnimator?
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/FaceAuthenticationModels.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/FaceAuthenticationModels.kt
index 9e7dec4..b354cfd 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/FaceAuthenticationModels.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/FaceAuthenticationModels.kt
@@ -17,6 +17,7 @@
package com.android.systemui.keyguard.shared.model
import android.hardware.face.FaceManager
+import android.os.SystemClock.elapsedRealtime
/**
* Authentication status provided by
@@ -38,8 +39,12 @@
object FailedAuthenticationStatus : AuthenticationStatus()
/** Face authentication error message */
-data class ErrorAuthenticationStatus(val msgId: Int, val msg: String? = null) :
- AuthenticationStatus() {
+data class ErrorAuthenticationStatus(
+ val msgId: Int,
+ val msg: String? = null,
+ // present to break equality check if the same error occurs repeatedly.
+ val createdAt: Long = elapsedRealtime()
+) : AuthenticationStatus() {
/**
* Method that checks if [msgId] is a lockout error. A lockout error means that face
* authentication is locked out.
diff --git a/packages/SystemUI/src/com/android/systemui/lifecycle/RepeatWhenAttached.kt b/packages/SystemUI/src/com/android/systemui/lifecycle/RepeatWhenAttached.kt
index 34a6740..e064839 100644
--- a/packages/SystemUI/src/com/android/systemui/lifecycle/RepeatWhenAttached.kt
+++ b/packages/SystemUI/src/com/android/systemui/lifecycle/RepeatWhenAttached.kt
@@ -167,9 +167,10 @@
registry.currentState = Lifecycle.State.DESTROYED
}
- override fun getLifecycle(): Lifecycle {
- return registry
- }
+ override val lifecycle: Lifecycle
+ get() {
+ return registry
+ }
private fun updateState() {
registry.currentState =
diff --git a/packages/SystemUI/src/com/android/systemui/log/BouncerLogger.kt b/packages/SystemUI/src/com/android/systemui/log/BouncerLogger.kt
index 3226865..d4b799f 100644
--- a/packages/SystemUI/src/com/android/systemui/log/BouncerLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/BouncerLogger.kt
@@ -18,6 +18,7 @@
import com.android.systemui.bouncer.shared.model.BouncerMessageModel
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.log.core.LogLevel
import com.android.systemui.log.dagger.BouncerLog
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt b/packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt
index fefa1b2..68cdfb6 100644
--- a/packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/FaceAuthenticationLogger.kt
@@ -6,7 +6,7 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.shared.model.ErrorAuthenticationStatus
import com.android.systemui.keyguard.shared.model.TransitionStep
-import com.android.systemui.log.LogLevel.DEBUG
+import com.android.systemui.log.core.LogLevel.DEBUG
import com.android.systemui.log.dagger.FaceAuthLog
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/log/ScreenDecorationsLogger.kt b/packages/SystemUI/src/com/android/systemui/log/ScreenDecorationsLogger.kt
index 27301e9..150de26 100644
--- a/packages/SystemUI/src/com/android/systemui/log/ScreenDecorationsLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/ScreenDecorationsLogger.kt
@@ -21,9 +21,9 @@
import android.graphics.RectF
import androidx.core.graphics.toRectF
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.log.LogLevel.DEBUG
-import com.android.systemui.log.LogLevel.ERROR
-import com.android.systemui.log.LogLevel.INFO
+import com.android.systemui.log.core.LogLevel.DEBUG
+import com.android.systemui.log.core.LogLevel.ERROR
+import com.android.systemui.log.core.LogLevel.INFO
import com.android.systemui.log.dagger.ScreenDecorationsLog
import com.google.errorprone.annotations.CompileTimeConstant
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/DisplayMetricsRepoLog.kt b/packages/SystemUI/src/com/android/systemui/log/dagger/DisplayMetricsRepoLog.kt
new file mode 100644
index 0000000..fa9ec88
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/DisplayMetricsRepoLog.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.log.dagger
+
+import javax.inject.Qualifier
+
+/** A [com.android.systemui.log.LogBuffer] for display metrics related logging. */
+@Qualifier
+@MustBeDocumented
+@Retention(AnnotationRetention.RUNTIME)
+annotation class DisplayMetricsRepoLog
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
index 3497285..b5759e3 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -488,4 +488,12 @@
public static LogBuffer provideDreamLogBuffer(LogBufferFactory factory) {
return factory.create("DreamLog", 250);
}
+
+ /** Provides a {@link LogBuffer} for display metrics related logs. */
+ @Provides
+ @SysUISingleton
+ @DisplayMetricsRepoLog
+ public static LogBuffer provideDisplayMetricsRepoLogBuffer(LogBufferFactory factory) {
+ return factory.create("DisplayMetricsRepo", 50);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt b/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt
index 8d622ae..67a985e 100644
--- a/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt
@@ -21,8 +21,8 @@
import com.android.systemui.Dumpable
import com.android.systemui.common.buffer.RingBuffer
import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.log.LogLevel
import com.android.systemui.log.LogcatEchoTracker
+import com.android.systemui.log.core.LogLevel
import com.android.systemui.plugins.log.TableLogBufferBase
import com.android.systemui.util.time.SystemClock
import java.io.PrintWriter
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaTimeoutLogger.kt b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaTimeoutLogger.kt
index e2e269d..534241e 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaTimeoutLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaTimeoutLogger.kt
@@ -19,7 +19,7 @@
import android.media.session.PlaybackState
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.log.core.LogLevel
import com.android.systemui.log.dagger.MediaTimeoutListenerLog
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowserLogger.kt b/packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowserLogger.kt
index 9e53d77..888b9c7 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowserLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowserLogger.kt
@@ -19,7 +19,7 @@
import android.content.ComponentName
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.log.core.LogLevel
import com.android.systemui.log.dagger.MediaBrowserLog
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselControllerLogger.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselControllerLogger.kt
index 0ed2434..3dc0000 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselControllerLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselControllerLogger.kt
@@ -18,7 +18,7 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.log.core.LogLevel
import com.android.systemui.log.dagger.MediaCarouselControllerLog
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewLogger.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewLogger.kt
index c781b76..8f1595d 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewLogger.kt
@@ -18,7 +18,7 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.log.core.LogLevel
import com.android.systemui.log.dagger.MediaViewLog
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/media/muteawait/MediaMuteAwaitLogger.kt b/packages/SystemUI/src/com/android/systemui/media/muteawait/MediaMuteAwaitLogger.kt
index bbcf259..4171682 100644
--- a/packages/SystemUI/src/com/android/systemui/media/muteawait/MediaMuteAwaitLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/muteawait/MediaMuteAwaitLogger.kt
@@ -3,7 +3,7 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.dagger.MediaMuteAwaitLog
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.log.core.LogLevel
import javax.inject.Inject
/** Log messages for [MediaMuteAwaitConnectionManager]. */
diff --git a/packages/SystemUI/src/com/android/systemui/media/nearby/NearbyMediaDevicesLogger.kt b/packages/SystemUI/src/com/android/systemui/media/nearby/NearbyMediaDevicesLogger.kt
index 66399d5..46c0132 100644
--- a/packages/SystemUI/src/com/android/systemui/media/nearby/NearbyMediaDevicesLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/nearby/NearbyMediaDevicesLogger.kt
@@ -3,7 +3,7 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.dagger.NearbyMediaDevicesLog
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.log.core.LogLevel
import javax.inject.Inject
/** Log messages for [NearbyMediaDevicesManager]. */
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerUtils.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerUtils.kt
index eeda1027..3c2226f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerUtils.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerUtils.kt
@@ -17,7 +17,7 @@
package com.android.systemui.media.taptotransfer.common
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.log.core.LogLevel
/** A helper for logging media tap-to-transfer events. */
object MediaTttLoggerUtils {
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLogger.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLogger.kt
index 206e5e3..503afd3 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLogger.kt
@@ -20,7 +20,7 @@
import com.android.internal.logging.InstanceId
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.log.core.LogLevel
import com.android.systemui.media.taptotransfer.common.MediaTttLoggerUtils
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java
index 99c591f..8225c47 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java
@@ -462,7 +462,7 @@
* @return Whether the IME is shown on top of the screen given the {@code vis} flag of
* {@link InputMethodService} and the keyguard states.
*/
- public boolean isImeShown(@InputMethodService.ImeWindowVisibility int vis) {
+ public boolean isImeShown(int vis) {
View shadeWindowView = mNotificationShadeWindowController.getWindowRootView();
boolean isKeyguardShowing = mKeyguardStateController.isShowing();
boolean imeVisibleOnShade = shadeWindowView != null && shadeWindowView.isAttachedToWindow()
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index 5bae1cb..682335e 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -66,7 +66,6 @@
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
-import android.inputmethodservice.InputMethodService;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
@@ -1048,9 +1047,8 @@
// ----- CommandQueue Callbacks -----
@Override
- public void setImeWindowStatus(int displayId, IBinder token,
- @InputMethodService.ImeWindowVisibility int vis,
- @InputMethodService.BackDispositionMode int backDisposition, boolean showImeSwitcher) {
+ public void setImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition,
+ boolean showImeSwitcher) {
if (displayId != mDisplayId) {
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
index cecf043..3b32313e 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
@@ -338,9 +338,8 @@
}
@Override
- public void setImeWindowStatus(int displayId, IBinder token,
- @InputMethodService.ImeWindowVisibility int vis,
- @InputMethodService.BackDispositionMode int backDisposition, boolean showImeSwitcher) {
+ public void setImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition,
+ boolean showImeSwitcher) {
boolean imeShown = mNavBarHelper.isImeShown(vis);
if (!imeShown) {
// Count imperceptible changes as visible so we transition taskbar out quickly.
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/logging/PrivacyLogger.kt b/packages/SystemUI/src/com/android/systemui/privacy/logging/PrivacyLogger.kt
index e56106d..f934346 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/logging/PrivacyLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/logging/PrivacyLogger.kt
@@ -20,8 +20,8 @@
import android.permission.PermissionGroupUsage
import com.android.systemui.log.dagger.PrivacyLog
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
-import com.android.systemui.log.LogMessage
+import com.android.systemui.log.core.LogLevel
+import com.android.systemui.log.core.LogMessage
import com.android.systemui.privacy.PrivacyDialog
import com.android.systemui.privacy.PrivacyItem
import java.util.Locale
diff --git a/packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.kt b/packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.kt
index c70cce9..2fafba1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.kt
@@ -120,6 +120,7 @@
val tilesToRemove = restoredAutoAdded.filter { it !in restoredTiles }
if (tilesToRemove.isNotEmpty()) {
+ Log.d(TAG, "Removing tiles: $tilesToRemove")
qsHost.removeTiles(tilesToRemove)
}
val tiles = synchronized(autoAdded) {
@@ -255,6 +256,7 @@
override fun dump(pw: PrintWriter, args: Array<out String>) {
pw.println("Current user: $userId")
+ pw.println("Restored tiles: $restoredTiles")
pw.println("Added tiles: $autoAdded")
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragmentDisableFlagsLogger.kt b/packages/SystemUI/src/com/android/systemui/qs/QSFragmentDisableFlagsLogger.kt
index ac6aabb..6563e42 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragmentDisableFlagsLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragmentDisableFlagsLogger.kt
@@ -2,7 +2,7 @@
import com.android.systemui.log.dagger.QSFragmentDisableLog
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.log.core.LogLevel
import com.android.systemui.statusbar.disableflags.DisableFlagsLogger
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
index d2568ac..432147f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
@@ -152,6 +152,7 @@
mQsFactories.add(defaultFactory);
pluginManager.addPluginListener(this, QSFactory.class, true);
mUserTracker = userTracker;
+ mCurrentUser = userTracker.getUserId();
mSecureSettings = secureSettings;
mCustomTileStatePersister = customTileStatePersister;
@@ -161,7 +162,9 @@
// finishes before creating any tiles.
tunerService.addTunable(this, TILES_SETTING);
// AutoTileManager can modify mTiles so make sure mTiles has already been initialized.
- mAutoTiles = autoTiles.get();
+ if (!mFeatureFlags.isEnabled(Flags.QS_PIPELINE_AUTO_ADD)) {
+ mAutoTiles = autoTiles.get();
+ }
});
}
@@ -272,6 +275,13 @@
if (!TILES_SETTING.equals(key)) {
return;
}
+ int currentUser = mUserTracker.getUserId();
+ if (currentUser != mCurrentUser) {
+ mUserContext = mUserTracker.getUserContext();
+ if (mAutoTiles != null) {
+ mAutoTiles.changeUser(UserHandle.of(currentUser));
+ }
+ }
// Do not process tiles if the flag is enabled.
if (mFeatureFlags.isEnabled(Flags.QS_PIPELINE_NEW_HOST)) {
return;
@@ -280,13 +290,6 @@
newValue = mContext.getResources().getString(R.string.quick_settings_tiles_retail_mode);
}
final List<String> tileSpecs = loadTileSpecs(mContext, newValue);
- int currentUser = mUserTracker.getUserId();
- if (currentUser != mCurrentUser) {
- mUserContext = mUserTracker.getUserContext();
- if (mAutoTiles != null) {
- mAutoTiles.changeUser(UserHandle.of(currentUser));
- }
- }
if (tileSpecs.equals(mTileSpecs) && currentUser == mCurrentUser) return;
Log.d(TAG, "Recreating tiles: " + tileSpecs);
mTiles.entrySet().stream().filter(tile -> !tileSpecs.contains(tile.getKey())).forEach(
@@ -301,7 +304,7 @@
if (tile != null && (!(tile instanceof CustomTile)
|| ((CustomTile) tile).getUser() == currentUser)) {
if (tile.isAvailable()) {
- if (DEBUG) Log.d(TAG, "Adding " + tile);
+ Log.d(TAG, "Adding " + tile);
tile.removeCallbacks();
if (!(tile instanceof CustomTile) && mCurrentUser != currentUser) {
tile.userSwitch(currentUser);
@@ -420,6 +423,7 @@
// When calling this, you may want to modify mTilesListDirty accordingly.
@MainThread
private void saveTilesToSettings(List<String> tileSpecs) {
+ Log.d(TAG, "Saving tiles: " + tileSpecs + " for user: " + mCurrentUser);
mSecureSettings.putStringForUser(TILES_SETTING, TextUtils.join(",", tileSpecs),
null /* tag */, false /* default */, mCurrentUser,
true /* overrideable by restore */);
@@ -493,7 +497,7 @@
lifecycleManager.flushMessagesAndUnbind();
}
}
- if (DEBUG) Log.d(TAG, "saveCurrentTiles " + newTiles);
+ Log.d(TAG, "saveCurrentTiles " + newTiles);
mTilesListDirty = true;
saveTilesToSettings(newTiles);
}
@@ -564,9 +568,9 @@
if (TextUtils.isEmpty(tileList)) {
tileList = res.getString(R.string.quick_settings_tiles);
- if (DEBUG) Log.d(TAG, "Loaded tile specs from default config: " + tileList);
+ Log.d(TAG, "Loaded tile specs from default config: " + tileList);
} else {
- if (DEBUG) Log.d(TAG, "Loaded tile specs from setting: " + tileList);
+ Log.d(TAG, "Loaded tile specs from setting: " + tileList);
}
final ArrayList<String> tiles = new ArrayList<String>();
boolean addedDefault = false;
@@ -612,6 +616,10 @@
@Override
public void dump(PrintWriter pw, String[] args) {
pw.println("QSTileHost:");
+ pw.println("tile specs: " + mTileSpecs);
+ pw.println("current user: " + mCurrentUser);
+ pw.println("is dirty: " + mTilesListDirty);
+ pw.println("tiles:");
mTiles.values().stream().filter(obj -> obj instanceof Dumpable)
.forEach(o -> ((Dumpable) o).dump(pw, args));
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
index dffe7fd..03de3a0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
@@ -19,9 +19,9 @@
import static com.android.systemui.qs.dagger.QSFlagsModule.RBC_AVAILABLE;
import android.content.Context;
-import android.hardware.display.NightDisplayListener;
import android.os.Handler;
+import com.android.systemui.dagger.NightDisplayListenerModule;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.media.dagger.MediaModule;
@@ -41,14 +41,14 @@
import com.android.systemui.statusbar.policy.WalletController;
import com.android.systemui.util.settings.SecureSettings;
-import dagger.Module;
-import dagger.Provides;
-import dagger.multibindings.Multibinds;
-
import java.util.Map;
import javax.inject.Named;
+import dagger.Module;
+import dagger.Provides;
+import dagger.multibindings.Multibinds;
+
/**
* Module for QS dependencies
*/
@@ -79,7 +79,7 @@
HotspotController hotspotController,
DataSaverController dataSaverController,
ManagedProfileController managedProfileController,
- NightDisplayListener nightDisplayListener,
+ NightDisplayListenerModule.Builder nightDisplayListenerBuilder,
CastController castController,
ReduceBrightColorsController reduceBrightColorsController,
DeviceControlsController deviceControlsController,
@@ -95,7 +95,7 @@
hotspotController,
dataSaverController,
managedProfileController,
- nightDisplayListener,
+ nightDisplayListenerBuilder,
castController,
reduceBrightColorsController,
deviceControlsController,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileRequestDialog.kt b/packages/SystemUI/src/com/android/systemui/qs/external/TileRequestDialog.kt
index 6265b3c..3432628 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileRequestDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileRequestDialog.kt
@@ -18,6 +18,7 @@
import android.content.Context
import android.graphics.drawable.Icon
+import android.view.ContextThemeWrapper
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.TextView
@@ -66,7 +67,8 @@
}
private fun createTileView(tileData: TileData): QSTileView {
- val tile = QSTileViewImpl(context, QSIconViewImpl(context), true)
+ val themedContext = ContextThemeWrapper(context, R.style.Theme_SystemUI_QuickSettings)
+ val tile = QSTileViewImpl(themedContext, QSIconViewImpl(themedContext), true)
val state = QSTile.BooleanState().apply {
label = tileData.label
handlesLongClick = false
diff --git a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/binder/FooterActionsViewBinder.kt b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/binder/FooterActionsViewBinder.kt
index 9c9ad33..3c53d77 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/binder/FooterActionsViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/binder/FooterActionsViewBinder.kt
@@ -244,8 +244,8 @@
val backgroundResource =
when (model.backgroundColor) {
- R.attr.offStateColor -> R.drawable.qs_footer_action_circle
- com.android.internal.R.attr.colorAccent -> R.drawable.qs_footer_action_circle_color
+ R.attr.shadeInactive -> R.drawable.qs_footer_action_circle
+ R.attr.shadeActive -> R.drawable.qs_footer_action_circle_color
else -> error("Unsupported icon background resource ${model.backgroundColor}")
}
buttonView.setBackgroundResource(backgroundResource)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt
index b3596a2..32146b5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt
@@ -145,8 +145,12 @@
R.drawable.ic_settings,
ContentDescription.Resource(R.string.accessibility_quick_settings_settings)
),
- iconTint = null,
- backgroundColor = R.attr.offStateColor,
+ iconTint =
+ Utils.getColorAttrDefaultColor(
+ context,
+ R.attr.onShadeInactiveVariant,
+ ),
+ backgroundColor = R.attr.shadeInactive,
this::onSettingsButtonClicked,
)
@@ -162,9 +166,9 @@
iconTint =
Utils.getColorAttrDefaultColor(
context,
- com.android.internal.R.attr.textColorOnAccent,
+ R.attr.onShadeActive,
),
- backgroundColor = com.android.internal.R.attr.colorAccent,
+ backgroundColor = R.attr.shadeActive,
this::onPowerButtonClicked,
)
} else {
@@ -264,7 +268,7 @@
),
),
iconTint = null,
- backgroundColor = R.attr.offStateColor,
+ backgroundColor = R.attr.shadeInactive,
onClick = this::onUserSwitcherClicked,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt b/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt
index c00a81c..39745c8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt
@@ -24,9 +24,9 @@
import com.android.systemui.log.ConstantStringsLogger
import com.android.systemui.log.ConstantStringsLoggerImpl
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel.DEBUG
-import com.android.systemui.log.LogLevel.ERROR
-import com.android.systemui.log.LogLevel.VERBOSE
+import com.android.systemui.log.core.LogLevel.DEBUG
+import com.android.systemui.log.core.LogLevel.ERROR
+import com.android.systemui.log.core.LogLevel.VERBOSE
import com.android.systemui.log.dagger.QSConfigLog
import com.android.systemui.log.dagger.QSLog
import com.android.systemui.plugins.qs.QSTile
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/BaseAutoAddableModule.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/BaseAutoAddableModule.kt
new file mode 100644
index 0000000..adea26e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/BaseAutoAddableModule.kt
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.pipeline.dagger
+
+import android.content.res.Resources
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.qs.pipeline.domain.autoaddable.AutoAddableSetting
+import com.android.systemui.qs.pipeline.domain.autoaddable.AutoAddableSettingList
+import com.android.systemui.qs.pipeline.domain.autoaddable.CastAutoAddable
+import com.android.systemui.qs.pipeline.domain.autoaddable.DataSaverAutoAddable
+import com.android.systemui.qs.pipeline.domain.autoaddable.DeviceControlsAutoAddable
+import com.android.systemui.qs.pipeline.domain.autoaddable.HotspotAutoAddable
+import com.android.systemui.qs.pipeline.domain.autoaddable.NightDisplayAutoAddable
+import com.android.systemui.qs.pipeline.domain.autoaddable.ReduceBrightColorsAutoAddable
+import com.android.systemui.qs.pipeline.domain.autoaddable.WalletAutoAddable
+import com.android.systemui.qs.pipeline.domain.autoaddable.WorkTileAutoAddable
+import com.android.systemui.qs.pipeline.domain.model.AutoAddable
+import dagger.Binds
+import dagger.Module
+import dagger.Provides
+import dagger.multibindings.ElementsIntoSet
+import dagger.multibindings.IntoSet
+
+@Module
+interface BaseAutoAddableModule {
+
+ companion object {
+ @Provides
+ @ElementsIntoSet
+ fun providesAutoAddableSetting(
+ @Main resources: Resources,
+ autoAddableSettingFactory: AutoAddableSetting.Factory
+ ): Set<AutoAddable> {
+ return AutoAddableSettingList.parseSettingsResource(
+ resources,
+ autoAddableSettingFactory
+ )
+ .toSet()
+ }
+ }
+
+ @Binds @IntoSet fun bindCastAutoAddable(impl: CastAutoAddable): AutoAddable
+
+ @Binds @IntoSet fun bindDataSaverAutoAddable(impl: DataSaverAutoAddable): AutoAddable
+
+ @Binds @IntoSet fun bindDeviceControlsAutoAddable(impl: DeviceControlsAutoAddable): AutoAddable
+
+ @Binds @IntoSet fun bindHotspotAutoAddable(impl: HotspotAutoAddable): AutoAddable
+
+ @Binds @IntoSet fun bindNightDisplayAutoAddable(impl: NightDisplayAutoAddable): AutoAddable
+
+ @Binds
+ @IntoSet
+ fun bindReduceBrightColorsAutoAddable(impl: ReduceBrightColorsAutoAddable): AutoAddable
+
+ @Binds @IntoSet fun bindWalletAutoAddable(impl: WalletAutoAddable): AutoAddable
+
+ @Binds @IntoSet fun bindWorkModeAutoAddable(impl: WorkTileAutoAddable): AutoAddable
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/QSAutoAddLog.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/QSAutoAddLog.kt
new file mode 100644
index 0000000..91cb5bb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/QSAutoAddLog.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.pipeline.dagger
+
+import javax.inject.Qualifier
+
+/** A [LogBuffer] for the QS pipeline to track auto-added tiles */
+@Qualifier @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) annotation class QSAutoAddLog
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/QSAutoAddModule.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/QSAutoAddModule.kt
index 9979228..a010ac4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/QSAutoAddModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/QSAutoAddModule.kt
@@ -16,13 +16,40 @@
package com.android.systemui.qs.pipeline.dagger
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogBufferFactory
import com.android.systemui.qs.pipeline.data.repository.AutoAddRepository
import com.android.systemui.qs.pipeline.data.repository.AutoAddSettingRepository
+import com.android.systemui.qs.pipeline.domain.model.AutoAddable
+import com.android.systemui.qs.pipeline.shared.logging.QSPipelineLogger
import dagger.Binds
import dagger.Module
+import dagger.Provides
+import dagger.multibindings.Multibinds
-@Module
+@Module(
+ includes =
+ [
+ BaseAutoAddableModule::class,
+ ]
+)
abstract class QSAutoAddModule {
@Binds abstract fun bindAutoAddRepository(impl: AutoAddSettingRepository): AutoAddRepository
+
+ @Multibinds abstract fun providesAutoAddableSet(): Set<AutoAddable>
+
+ companion object {
+ /**
+ * Provides a logging buffer for all logs related to the new Quick Settings pipeline to log
+ * auto added tiles.
+ */
+ @Provides
+ @SysUISingleton
+ @QSAutoAddLog
+ fun provideQSAutoAddLogBuffer(factory: LogBufferFactory): LogBuffer {
+ return factory.create(QSPipelineLogger.AUTO_ADD_TAG, maxSize = 100, systrace = false)
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/QSPipelineModule.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/QSPipelineModule.kt
index d7ae575..a4600fb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/QSPipelineModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/QSPipelineModule.kt
@@ -26,7 +26,7 @@
import com.android.systemui.qs.pipeline.data.repository.TileSpecSettingsRepository
import com.android.systemui.qs.pipeline.domain.interactor.CurrentTilesInteractor
import com.android.systemui.qs.pipeline.domain.interactor.CurrentTilesInteractorImpl
-import com.android.systemui.qs.pipeline.prototyping.PrototypeCoreStartable
+import com.android.systemui.qs.pipeline.domain.startable.QSPipelineCoreStartable
import com.android.systemui.qs.pipeline.shared.logging.QSPipelineLogger
import dagger.Binds
import dagger.Module
@@ -53,8 +53,8 @@
@Binds
@IntoMap
- @ClassKey(PrototypeCoreStartable::class)
- abstract fun providePrototypeCoreStartable(startable: PrototypeCoreStartable): CoreStartable
+ @ClassKey(QSPipelineCoreStartable::class)
+ abstract fun provideCoreStartable(startable: QSPipelineCoreStartable): CoreStartable
companion object {
/**
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/QSTileListLog.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/QSTileListLog.kt
index ad8bfea..c56ca8c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/QSTileListLog.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/dagger/QSTileListLog.kt
@@ -19,5 +19,5 @@
import java.lang.annotation.RetentionPolicy
import javax.inject.Qualifier
-/** A {@link LogBuffer} for the new QS Pipeline for logging changes to the set of current tiles. */
+/** A [LogBuffer] for the new QS Pipeline for logging changes to the set of current tiles. */
@Qualifier @MustBeDocumented @Retention(RetentionPolicy.RUNTIME) annotation class QSTileListLog
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSetting.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSetting.kt
new file mode 100644
index 0000000..45129b9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSetting.kt
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.pipeline.domain.autoaddable
+
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
+import com.android.systemui.qs.pipeline.domain.model.AutoAddTracking
+import com.android.systemui.qs.pipeline.domain.model.AutoAddable
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.android.systemui.util.settings.SecureSettings
+import com.android.systemui.util.settings.SettingsProxyExt.observerFlow
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import java.util.Objects
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onStart
+
+/**
+ * It tracks a specific `Secure` int [setting] and when its value changes to non-zero, it will emit
+ * a [AutoAddSignal.Add] for [spec].
+ */
+class AutoAddableSetting
+@AssistedInject
+constructor(
+ private val secureSettings: SecureSettings,
+ @Background private val bgDispatcher: CoroutineDispatcher,
+ @Assisted private val setting: String,
+ @Assisted private val spec: TileSpec,
+) : AutoAddable {
+
+ override fun autoAddSignal(userId: Int): Flow<AutoAddSignal> {
+ return secureSettings
+ .observerFlow(userId, setting)
+ .onStart { emit(Unit) }
+ .map { secureSettings.getIntForUser(setting, 0, userId) != 0 }
+ .distinctUntilChanged()
+ .filter { it }
+ .map { AutoAddSignal.Add(spec) }
+ .flowOn(bgDispatcher)
+ }
+
+ override val autoAddTracking = AutoAddTracking.IfNotAdded(spec)
+
+ override val description = "AutoAddableSetting: $setting:$spec ($autoAddTracking)"
+
+ override fun equals(other: Any?): Boolean {
+ return other is AutoAddableSetting && spec == other.spec && setting == other.setting
+ }
+
+ override fun hashCode(): Int {
+ return Objects.hash(spec, setting)
+ }
+
+ override fun toString(): String {
+ return description
+ }
+
+ @AssistedFactory
+ interface Factory {
+ fun create(setting: String, spec: TileSpec): AutoAddableSetting
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSettingList.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSettingList.kt
new file mode 100644
index 0000000..b1c7433
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSettingList.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.pipeline.domain.autoaddable
+
+import android.content.res.Resources
+import android.util.Log
+import com.android.systemui.R
+import com.android.systemui.qs.pipeline.domain.model.AutoAddable
+import com.android.systemui.qs.pipeline.shared.TileSpec
+
+object AutoAddableSettingList {
+
+ /** Parses [R.array.config_quickSettingsAutoAdd] into a collection of [AutoAddableSetting]. */
+ fun parseSettingsResource(
+ resources: Resources,
+ autoAddableSettingFactory: AutoAddableSetting.Factory,
+ ): Iterable<AutoAddable> {
+ val autoAddList = resources.getStringArray(R.array.config_quickSettingsAutoAdd)
+ return autoAddList.mapNotNull {
+ val elements = it.split(SETTING_SEPARATOR, limit = 2)
+ if (elements.size == 2) {
+ val setting = elements[0]
+ val spec = elements[1]
+ val tileSpec = TileSpec.create(spec)
+ if (tileSpec == TileSpec.Invalid) {
+ Log.w(TAG, "Malformed item in array: $it")
+ null
+ } else {
+ autoAddableSettingFactory.create(setting, TileSpec.create(spec))
+ }
+ } else {
+ Log.w(TAG, "Malformed item in array: $it")
+ null
+ }
+ }
+ }
+
+ private const val SETTING_SEPARATOR = ":"
+ private const val TAG = "AutoAddableSettingList"
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/CallbackControllerAutoAddable.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/CallbackControllerAutoAddable.kt
new file mode 100644
index 0000000..88a49ee
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/CallbackControllerAutoAddable.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.pipeline.domain.autoaddable
+
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
+import com.android.systemui.qs.pipeline.domain.model.AutoAddTracking
+import com.android.systemui.qs.pipeline.domain.model.AutoAddable
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.android.systemui.statusbar.policy.CallbackController
+import kotlinx.coroutines.channels.ProducerScope
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+
+/** Generic [AutoAddable] for tiles that are added based on a signal from a [CallbackController]. */
+abstract class CallbackControllerAutoAddable<
+ Callback : Any, Controller : CallbackController<Callback>>(
+ private val controller: Controller,
+) : AutoAddable {
+
+ /** [TileSpec] for the tile to add. */
+ protected abstract val spec: TileSpec
+
+ /**
+ * Callback to be used to determine when to add the tile. When the callback determines that the
+ * feature has been enabled, it should call [sendAdd].
+ */
+ protected abstract fun ProducerScope<AutoAddSignal>.getCallback(): Callback
+
+ /** Sends an [AutoAddSignal.Add] for [spec]. */
+ protected fun ProducerScope<AutoAddSignal>.sendAdd() {
+ trySend(AutoAddSignal.Add(spec))
+ }
+
+ final override fun autoAddSignal(userId: Int): Flow<AutoAddSignal> {
+ return conflatedCallbackFlow {
+ val callback = getCallback()
+ controller.addCallback(callback)
+
+ awaitClose { controller.removeCallback(callback) }
+ }
+ }
+
+ override val autoAddTracking: AutoAddTracking
+ get() = AutoAddTracking.IfNotAdded(spec)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/CastAutoAddable.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/CastAutoAddable.kt
new file mode 100644
index 0000000..b5bef9f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/CastAutoAddable.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.pipeline.domain.autoaddable
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.android.systemui.qs.tiles.CastTile
+import com.android.systemui.statusbar.policy.CastController
+import javax.inject.Inject
+import kotlinx.coroutines.channels.ProducerScope
+
+/**
+ * [AutoAddable] for [CastTile.TILE_SPEC].
+ *
+ * It will send a signal to add the tile when there's a casting device connected or connecting.
+ */
+@SysUISingleton
+class CastAutoAddable
+@Inject
+constructor(
+ private val controller: CastController,
+) : CallbackControllerAutoAddable<CastController.Callback, CastController>(controller) {
+
+ override val spec: TileSpec
+ get() = TileSpec.create(CastTile.TILE_SPEC)
+
+ override fun ProducerScope<AutoAddSignal>.getCallback(): CastController.Callback {
+ return CastController.Callback {
+ val isCasting =
+ controller.castDevices.any {
+ it.state == CastController.CastDevice.STATE_CONNECTED ||
+ it.state == CastController.CastDevice.STATE_CONNECTING
+ }
+ if (isCasting) {
+ sendAdd()
+ }
+ }
+ }
+
+ override val description = "CastAutoAddable ($autoAddTracking)"
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/DataSaverAutoAddable.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/DataSaverAutoAddable.kt
new file mode 100644
index 0000000..a877aee
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/DataSaverAutoAddable.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.pipeline.domain.autoaddable
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.android.systemui.qs.tiles.DataSaverTile
+import com.android.systemui.statusbar.policy.DataSaverController
+import javax.inject.Inject
+import kotlinx.coroutines.channels.ProducerScope
+
+/**
+ * [AutoAddable] for [DataSaverTile.TILE_SPEC].
+ *
+ * It will send a signal to add the tile when data saver is enabled.
+ */
+@SysUISingleton
+class DataSaverAutoAddable
+@Inject
+constructor(
+ dataSaverController: DataSaverController,
+) :
+ CallbackControllerAutoAddable<DataSaverController.Listener, DataSaverController>(
+ dataSaverController
+ ) {
+
+ override val spec
+ get() = TileSpec.create(DataSaverTile.TILE_SPEC)
+
+ override fun ProducerScope<AutoAddSignal>.getCallback(): DataSaverController.Listener {
+ return DataSaverController.Listener { enabled ->
+ if (enabled) {
+ sendAdd()
+ }
+ }
+ }
+
+ override val description = "DataSaverAutoAddable ($autoAddTracking)"
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/DeviceControlsAutoAddable.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/DeviceControlsAutoAddable.kt
new file mode 100644
index 0000000..76bfad9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/DeviceControlsAutoAddable.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.pipeline.domain.autoaddable
+
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
+import com.android.systemui.qs.pipeline.domain.model.AutoAddTracking
+import com.android.systemui.qs.pipeline.domain.model.AutoAddable
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.android.systemui.qs.tiles.DeviceControlsTile
+import com.android.systemui.statusbar.policy.DeviceControlsController
+import javax.inject.Inject
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+
+/**
+ * [AutoAddable] for [DeviceControlsTile.TILE_SPEC].
+ *
+ * It will send a signal to add the tile when updating to a device that supports device controls. It
+ * will send a signal to remove the tile when the device does not support controls.
+ */
+@SysUISingleton
+class DeviceControlsAutoAddable
+@Inject
+constructor(
+ private val deviceControlsController: DeviceControlsController,
+) : AutoAddable {
+
+ private val spec = TileSpec.create(DeviceControlsTile.TILE_SPEC)
+
+ override fun autoAddSignal(userId: Int): Flow<AutoAddSignal> {
+ return conflatedCallbackFlow {
+ val callback =
+ object : DeviceControlsController.Callback {
+ override fun onControlsUpdate(position: Int?) {
+ position?.let { trySend(AutoAddSignal.Add(spec, position)) }
+ deviceControlsController.removeCallback()
+ }
+
+ override fun removeControlsAutoTracker() {
+ trySend(AutoAddSignal.Remove(spec))
+ }
+ }
+
+ deviceControlsController.setCallback(callback)
+
+ awaitClose { deviceControlsController.removeCallback() }
+ }
+ }
+
+ override val autoAddTracking: AutoAddTracking
+ get() = AutoAddTracking.Always
+
+ override val description = "DeviceControlsAutoAddable ($autoAddTracking)"
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/HotspotAutoAddable.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/HotspotAutoAddable.kt
new file mode 100644
index 0000000..9c59e12
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/HotspotAutoAddable.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.pipeline.domain.autoaddable
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.android.systemui.qs.tiles.HotspotTile
+import com.android.systemui.statusbar.policy.HotspotController
+import javax.inject.Inject
+import kotlinx.coroutines.channels.ProducerScope
+
+/**
+ * [AutoAddable] for [HotspotTile.TILE_SPEC].
+ *
+ * It will send a signal to add the tile when hotspot is enabled.
+ */
+@SysUISingleton
+class HotspotAutoAddable
+@Inject
+constructor(
+ hotspotController: HotspotController,
+) :
+ CallbackControllerAutoAddable<HotspotController.Callback, HotspotController>(
+ hotspotController
+ ) {
+
+ override val spec
+ get() = TileSpec.create(HotspotTile.TILE_SPEC)
+
+ override fun ProducerScope<AutoAddSignal>.getCallback(): HotspotController.Callback {
+ return HotspotController.Callback { enabled, _ ->
+ if (enabled) {
+ sendAdd()
+ }
+ }
+ }
+
+ override val description = "HotspotAutoAddable ($autoAddTracking)"
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/NightDisplayAutoAddable.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/NightDisplayAutoAddable.kt
new file mode 100644
index 0000000..31ea734
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/NightDisplayAutoAddable.kt
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.pipeline.domain.autoaddable
+
+import android.content.Context
+import android.hardware.display.ColorDisplayManager
+import android.hardware.display.NightDisplayListener
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.dagger.NightDisplayListenerModule
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
+import com.android.systemui.qs.pipeline.domain.model.AutoAddTracking
+import com.android.systemui.qs.pipeline.domain.model.AutoAddable
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.android.systemui.qs.tiles.NightDisplayTile
+import javax.inject.Inject
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+
+/**
+ * [AutoAddable] for [NightDisplayTile.TILE_SPEC].
+ *
+ * It will send a signal to add the tile when night display is enabled or when the auto mode changes
+ * to one that supports night display.
+ */
+@SysUISingleton
+class NightDisplayAutoAddable
+@Inject
+constructor(
+ private val nightDisplayListenerBuilder: NightDisplayListenerModule.Builder,
+ context: Context,
+) : AutoAddable {
+
+ private val enabled = ColorDisplayManager.isNightDisplayAvailable(context)
+ private val spec = TileSpec.create(NightDisplayTile.TILE_SPEC)
+
+ override fun autoAddSignal(userId: Int): Flow<AutoAddSignal> {
+ return conflatedCallbackFlow {
+ val nightDisplayListener = nightDisplayListenerBuilder.setUser(userId).build()
+
+ val callback =
+ object : NightDisplayListener.Callback {
+ override fun onActivated(activated: Boolean) {
+ if (activated) {
+ sendAdd()
+ }
+ }
+
+ override fun onAutoModeChanged(autoMode: Int) {
+ if (
+ autoMode == ColorDisplayManager.AUTO_MODE_CUSTOM_TIME ||
+ autoMode == ColorDisplayManager.AUTO_MODE_TWILIGHT
+ ) {
+ sendAdd()
+ }
+ }
+
+ private fun sendAdd() {
+ trySend(AutoAddSignal.Add(spec))
+ }
+ }
+
+ nightDisplayListener.setCallback(callback)
+
+ awaitClose { nightDisplayListener.setCallback(null) }
+ }
+ }
+
+ override val autoAddTracking =
+ if (enabled) {
+ AutoAddTracking.IfNotAdded(spec)
+ } else {
+ AutoAddTracking.Disabled
+ }
+
+ override val description = "NightDisplayAutoAddable ($autoAddTracking)"
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/ReduceBrightColorsAutoAddable.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/ReduceBrightColorsAutoAddable.kt
new file mode 100644
index 0000000..267e2b7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/ReduceBrightColorsAutoAddable.kt
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.pipeline.domain.autoaddable
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.qs.ReduceBrightColorsController
+import com.android.systemui.qs.dagger.QSFlagsModule.RBC_AVAILABLE
+import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
+import com.android.systemui.qs.pipeline.domain.model.AutoAddTracking
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.android.systemui.qs.tiles.ReduceBrightColorsTile
+import javax.inject.Inject
+import javax.inject.Named
+import kotlinx.coroutines.channels.ProducerScope
+
+/**
+ * [AutoAddable] for [ReduceBrightColorsTile.TILE_SPEC].
+ *
+ * It will send a signal to add the tile when reduce bright colors is enabled.
+ */
+@SysUISingleton
+class ReduceBrightColorsAutoAddable
+@Inject
+constructor(
+ controller: ReduceBrightColorsController,
+ @Named(RBC_AVAILABLE) private val available: Boolean,
+) :
+ CallbackControllerAutoAddable<
+ ReduceBrightColorsController.Listener, ReduceBrightColorsController
+ >(controller) {
+
+ override val spec: TileSpec
+ get() = TileSpec.create(ReduceBrightColorsTile.TILE_SPEC)
+
+ override fun ProducerScope<AutoAddSignal>.getCallback(): ReduceBrightColorsController.Listener {
+ return object : ReduceBrightColorsController.Listener {
+ override fun onActivated(activated: Boolean) {
+ if (activated) {
+ sendAdd()
+ }
+ }
+ }
+ }
+
+ override val autoAddTracking
+ get() =
+ if (available) {
+ super.autoAddTracking
+ } else {
+ AutoAddTracking.Disabled
+ }
+
+ override val description = "ReduceBrightColorsAutoAddable ($autoAddTracking)"
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/SafetyCenterAutoAddable.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/SafetyCenterAutoAddable.kt
new file mode 100644
index 0000000..58a31bc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/SafetyCenterAutoAddable.kt
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.pipeline.domain.autoaddable
+
+import android.content.ComponentName
+import android.content.pm.PackageManager
+import android.content.res.Resources
+import android.text.TextUtils
+import com.android.systemui.R
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
+import com.android.systemui.qs.pipeline.domain.model.AutoAddTracking
+import com.android.systemui.qs.pipeline.domain.model.AutoAddable
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.android.systemui.statusbar.policy.SafetyController
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.withContext
+
+/**
+ * [AutoAddable] for the safety tile.
+ *
+ * It will send a signal to add the tile when the feature is enabled, indicating the component
+ * corresponding to the tile. If the feature is disabled, it will send a signal to remove the tile.
+ */
+@SysUISingleton
+class SafetyCenterAutoAddable
+@Inject
+constructor(
+ private val safetyController: SafetyController,
+ private val packageManager: PackageManager,
+ @Main private val resources: Resources,
+ @Background private val bgDispatcher: CoroutineDispatcher,
+) : AutoAddable {
+
+ private suspend fun getSpec(): TileSpec? {
+ val specClass = resources.getString(R.string.safety_quick_settings_tile_class)
+ return if (TextUtils.isEmpty(specClass)) {
+ null
+ } else {
+ val packageName =
+ withContext(bgDispatcher) { packageManager.permissionControllerPackageName }
+ TileSpec.create(ComponentName(packageName, specClass))
+ }
+ }
+
+ override fun autoAddSignal(userId: Int): Flow<AutoAddSignal> {
+ return conflatedCallbackFlow {
+ val spec = getSpec()
+ if (spec != null) {
+ // If not added, we always try to add it
+ trySend(AutoAddSignal.Add(spec))
+ val listener =
+ SafetyController.Listener { isSafetyCenterEnabled ->
+ if (isSafetyCenterEnabled) {
+ trySend(AutoAddSignal.Add(spec))
+ } else {
+ trySend(AutoAddSignal.Remove(spec))
+ }
+ }
+
+ safetyController.addCallback(listener)
+
+ awaitClose { safetyController.removeCallback(listener) }
+ } else {
+ awaitClose {}
+ }
+ }
+ }
+
+ override val autoAddTracking: AutoAddTracking
+ get() = AutoAddTracking.Always
+
+ override val description = "SafetyCenterAutoAddable ($autoAddTracking)"
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/WalletAutoAddable.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/WalletAutoAddable.kt
new file mode 100644
index 0000000..b3bc25f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/WalletAutoAddable.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.pipeline.domain.autoaddable
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
+import com.android.systemui.qs.pipeline.domain.model.AutoAddTracking
+import com.android.systemui.qs.pipeline.domain.model.AutoAddable
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.android.systemui.qs.tiles.QuickAccessWalletTile
+import com.android.systemui.statusbar.policy.WalletController
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flow
+
+/**
+ * [AutoAddable] for [QuickAccessWalletTile.TILE_SPEC].
+ *
+ * It will always try to add the tile if [WalletController.getWalletPosition] is non-null.
+ */
+@SysUISingleton
+class WalletAutoAddable
+@Inject
+constructor(
+ private val walletController: WalletController,
+) : AutoAddable {
+
+ private val spec = TileSpec.create(QuickAccessWalletTile.TILE_SPEC)
+
+ override fun autoAddSignal(userId: Int): Flow<AutoAddSignal> {
+ return flow {
+ val position = walletController.getWalletPosition()
+ if (position != null) {
+ emit(AutoAddSignal.Add(spec, position))
+ }
+ }
+ }
+
+ override val autoAddTracking: AutoAddTracking
+ get() = AutoAddTracking.IfNotAdded(spec)
+
+ override val description = "WalletAutoAddable ($autoAddTracking)"
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/WorkTileAutoAddable.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/WorkTileAutoAddable.kt
new file mode 100644
index 0000000..5e3c348
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/WorkTileAutoAddable.kt
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.pipeline.domain.autoaddable
+
+import android.content.pm.UserInfo
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
+import com.android.systemui.qs.pipeline.domain.model.AutoAddTracking
+import com.android.systemui.qs.pipeline.domain.model.AutoAddable
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.android.systemui.qs.tiles.WorkModeTile
+import com.android.systemui.settings.UserTracker
+import javax.inject.Inject
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+
+/**
+ * [AutoAddable] for [WorkModeTile.TILE_SPEC].
+ *
+ * It will send a signal to add the tile when there is a managed profile for the current user, and a
+ * signal to remove it if there is not.
+ */
+@SysUISingleton
+class WorkTileAutoAddable @Inject constructor(private val userTracker: UserTracker) : AutoAddable {
+
+ private val spec = TileSpec.create(WorkModeTile.TILE_SPEC)
+
+ override fun autoAddSignal(userId: Int): Flow<AutoAddSignal> {
+ return conflatedCallbackFlow {
+ fun maybeSend(profiles: List<UserInfo>) {
+ if (profiles.any { it.id == userId }) {
+ // We are looking at the profiles of the correct user.
+ if (profiles.any { it.isManagedProfile }) {
+ trySend(AutoAddSignal.Add(spec))
+ } else {
+ trySend(AutoAddSignal.Remove(spec))
+ }
+ }
+ }
+
+ val callback =
+ object : UserTracker.Callback {
+ override fun onProfilesChanged(profiles: List<UserInfo>) {
+ maybeSend(profiles)
+ }
+ }
+
+ userTracker.addCallback(callback) { it.run() }
+ maybeSend(userTracker.userProfiles)
+
+ awaitClose { userTracker.removeCallback(callback) }
+ }
+ }
+
+ override val autoAddTracking = AutoAddTracking.Always
+
+ override val description = "WorkTileAutoAddable ($autoAddTracking)"
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractor.kt
new file mode 100644
index 0000000..b747393
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractor.kt
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.pipeline.domain.interactor
+
+import com.android.systemui.Dumpable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.qs.pipeline.data.repository.AutoAddRepository
+import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
+import com.android.systemui.qs.pipeline.domain.model.AutoAddTracking
+import com.android.systemui.qs.pipeline.domain.model.AutoAddable
+import com.android.systemui.qs.pipeline.shared.logging.QSPipelineLogger
+import com.android.systemui.util.asIndenting
+import com.android.systemui.util.indentIfPossible
+import java.io.PrintWriter
+import java.util.concurrent.atomic.AtomicBoolean
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.flow.collectLatest
+import kotlinx.coroutines.flow.emptyFlow
+import kotlinx.coroutines.flow.filterIsInstance
+import kotlinx.coroutines.flow.merge
+import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.flow.take
+import kotlinx.coroutines.launch
+
+/**
+ * Collects the signals coming from all registered [AutoAddable] and adds/removes tiles accordingly.
+ */
+@SysUISingleton
+class AutoAddInteractor
+@Inject
+constructor(
+ private val autoAddables: Set<@JvmSuppressWildcards AutoAddable>,
+ private val repository: AutoAddRepository,
+ private val dumpManager: DumpManager,
+ private val qsPipelineLogger: QSPipelineLogger,
+ @Application private val scope: CoroutineScope,
+) : Dumpable {
+
+ private val initialized = AtomicBoolean(false)
+
+ /** Start collection of signals following the user from [currentTilesInteractor]. */
+ fun init(currentTilesInteractor: CurrentTilesInteractor) {
+ if (!initialized.compareAndSet(false, true)) {
+ return
+ }
+
+ dumpManager.registerNormalDumpable(TAG, this)
+
+ scope.launch {
+ currentTilesInteractor.userId.collectLatest { userId ->
+ coroutineScope {
+ val previouslyAdded = repository.autoAddedTiles(userId).stateIn(this)
+
+ autoAddables
+ .map { addable ->
+ val autoAddSignal = addable.autoAddSignal(userId)
+ when (val lifecycle = addable.autoAddTracking) {
+ is AutoAddTracking.Always -> autoAddSignal
+ is AutoAddTracking.Disabled -> emptyFlow()
+ is AutoAddTracking.IfNotAdded -> {
+ if (lifecycle.spec !in previouslyAdded.value) {
+ autoAddSignal.filterIsInstance<AutoAddSignal.Add>().take(1)
+ } else {
+ emptyFlow()
+ }
+ }
+ }
+ }
+ .merge()
+ .collect { signal ->
+ when (signal) {
+ is AutoAddSignal.Add -> {
+ if (signal.spec !in previouslyAdded.value) {
+ currentTilesInteractor.addTile(signal.spec, signal.position)
+ qsPipelineLogger.logTileAutoAdded(
+ userId,
+ signal.spec,
+ signal.position
+ )
+ repository.markTileAdded(userId, signal.spec)
+ }
+ }
+ is AutoAddSignal.Remove -> {
+ currentTilesInteractor.removeTiles(setOf(signal.spec))
+ qsPipelineLogger.logTileAutoRemoved(userId, signal.spec)
+ repository.unmarkTileAdded(userId, signal.spec)
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ override fun dump(pw: PrintWriter, args: Array<out String>) {
+ with(pw.asIndenting()) {
+ println("AutoAddables:")
+ indentIfPossible { autoAddables.forEach { println(it.description) } }
+ }
+ }
+
+ companion object {
+ private const val TAG = "AutoAddInteractor"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/model/AutoAddSignal.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/model/AutoAddSignal.kt
new file mode 100644
index 0000000..ed7b8bd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/model/AutoAddSignal.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.pipeline.domain.model
+
+import com.android.systemui.qs.pipeline.data.repository.TileSpecRepository.Companion.POSITION_AT_END
+import com.android.systemui.qs.pipeline.shared.TileSpec
+
+/** Signal indicating when a tile needs to be auto-added or removed */
+sealed interface AutoAddSignal {
+ /** Tile for this object */
+ val spec: TileSpec
+
+ /** Signal for auto-adding a tile at [position]. */
+ data class Add(
+ override val spec: TileSpec,
+ val position: Int = POSITION_AT_END,
+ ) : AutoAddSignal
+
+ /** Signal for removing a tile. */
+ data class Remove(
+ override val spec: TileSpec,
+ ) : AutoAddSignal
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/model/AutoAddTracking.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/model/AutoAddTracking.kt
new file mode 100644
index 0000000..154d045
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/model/AutoAddTracking.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.pipeline.domain.model
+
+import com.android.systemui.qs.pipeline.shared.TileSpec
+
+/** Strategy for when to track a particular [AutoAddable]. */
+sealed interface AutoAddTracking {
+
+ /**
+ * Indicates that the signals from the associated [AutoAddable] should all be collected and
+ * reacted accordingly. It may have [AutoAddSignal.Add] and [AutoAddSignal.Remove].
+ */
+ object Always : AutoAddTracking {
+ override fun toString(): String {
+ return "Always"
+ }
+ }
+
+ /**
+ * Indicates that the associated [AutoAddable] is [Disabled] and doesn't need to be collected.
+ */
+ object Disabled : AutoAddTracking {
+ override fun toString(): String {
+ return "Disabled"
+ }
+ }
+
+ /**
+ * Only the first [AutoAddSignal.Add] for each flow of signals needs to be collected, and only
+ * if the tile hasn't been auto-added yet. The associated [AutoAddable] will only emit
+ * [AutoAddSignal.Add].
+ */
+ data class IfNotAdded(val spec: TileSpec) : AutoAddTracking
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/model/AutoAddable.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/model/AutoAddable.kt
new file mode 100644
index 0000000..61fe5b4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/model/AutoAddable.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.pipeline.domain.model
+
+import kotlinx.coroutines.flow.Flow
+
+/**
+ * Tracks conditions for auto-adding or removing specific tiles.
+ *
+ * When creating a new [AutoAddable], it needs to be registered in a [Module] like
+ * [BaseAutoAddableModule], for example:
+ * ```
+ * @Binds
+ * @IntoSet
+ * fun providesMyAutoAddable(autoAddable: MyAutoAddable): AutoAddable
+ * ```
+ */
+interface AutoAddable {
+
+ /**
+ * Signals associated with a particular user indicating whether a particular tile needs to be
+ * auto-added or auto-removed.
+ */
+ fun autoAddSignal(userId: Int): Flow<AutoAddSignal>
+
+ /**
+ * Lifecycle for this object. It indicates in which cases [autoAddSignal] should be collected
+ */
+ val autoAddTracking: AutoAddTracking
+
+ /** Human readable description */
+ val description: String
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/startable/QSPipelineCoreStartable.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/startable/QSPipelineCoreStartable.kt
new file mode 100644
index 0000000..224fc1a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/startable/QSPipelineCoreStartable.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.pipeline.domain.startable
+
+import com.android.systemui.CoreStartable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.qs.pipeline.domain.interactor.AutoAddInteractor
+import com.android.systemui.qs.pipeline.domain.interactor.CurrentTilesInteractor
+import javax.inject.Inject
+
+@SysUISingleton
+class QSPipelineCoreStartable
+@Inject
+constructor(
+ private val currentTilesInteractor: CurrentTilesInteractor,
+ private val autoAddInteractor: AutoAddInteractor,
+ private val featureFlags: FeatureFlags,
+) : CoreStartable {
+
+ override fun start() {
+ if (
+ featureFlags.isEnabled(Flags.QS_PIPELINE_NEW_HOST) &&
+ featureFlags.isEnabled(Flags.QS_PIPELINE_AUTO_ADD)
+ ) {
+ autoAddInteractor.init(currentTilesInteractor)
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/prototyping/PrototypeCoreStartable.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/prototyping/PrototypeCoreStartable.kt
deleted file mode 100644
index bbd7234..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/prototyping/PrototypeCoreStartable.kt
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.qs.pipeline.prototyping
-
-import android.util.Log
-import com.android.systemui.CoreStartable
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
-import com.android.systemui.qs.pipeline.data.repository.AutoAddRepository
-import com.android.systemui.qs.pipeline.data.repository.TileSpecRepository
-import com.android.systemui.qs.pipeline.shared.TileSpec
-import com.android.systemui.statusbar.commandline.Command
-import com.android.systemui.statusbar.commandline.CommandRegistry
-import com.android.systemui.user.data.repository.UserRepository
-import java.io.PrintWriter
-import javax.inject.Inject
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.flow.flatMapLatest
-import kotlinx.coroutines.launch
-
-/**
- * Class for observing results while prototyping.
- *
- * The flows do their own logging, so we just need to make sure that they collect.
- *
- * This will be torn down together with the last of the new pipeline flags remaining here.
- */
-// TODO(b/270385608)
-@SysUISingleton
-class PrototypeCoreStartable
-@Inject
-constructor(
- private val tileSpecRepository: TileSpecRepository,
- private val autoAddRepository: AutoAddRepository,
- private val userRepository: UserRepository,
- private val featureFlags: FeatureFlags,
- @Application private val scope: CoroutineScope,
- private val commandRegistry: CommandRegistry,
-) : CoreStartable {
-
- @OptIn(ExperimentalCoroutinesApi::class)
- override fun start() {
- if (featureFlags.isEnabled(Flags.QS_PIPELINE_NEW_HOST)) {
- scope.launch {
- userRepository.selectedUserInfo
- .flatMapLatest { user -> tileSpecRepository.tilesSpecs(user.id) }
- .collect {}
- }
- if (featureFlags.isEnabled(Flags.QS_PIPELINE_AUTO_ADD)) {
- scope.launch {
- userRepository.selectedUserInfo
- .flatMapLatest { user -> autoAddRepository.autoAddedTiles(user.id) }
- .collect { tiles -> Log.d(TAG, "Auto-added tiles: $tiles") }
- }
- }
- commandRegistry.registerCommand(COMMAND, ::CommandExecutor)
- }
- }
-
- private inner class CommandExecutor : Command {
- override fun execute(pw: PrintWriter, args: List<String>) {
- if (args.size < 2) {
- pw.println("Error: needs at least two arguments")
- return
- }
- val spec = TileSpec.create(args[1])
- if (spec == TileSpec.Invalid) {
- pw.println("Error: Invalid tile spec ${args[1]}")
- }
- if (args[0] == "add") {
- performAdd(args, spec)
- pw.println("Requested tile added")
- } else if (args[0] == "remove") {
- performRemove(args, spec)
- pw.println("Requested tile removed")
- } else {
- pw.println("Error: unknown command")
- }
- }
-
- private fun performAdd(args: List<String>, spec: TileSpec) {
- val position = args.getOrNull(2)?.toInt() ?: TileSpecRepository.POSITION_AT_END
- val user = args.getOrNull(3)?.toInt() ?: userRepository.getSelectedUserInfo().id
- scope.launch { tileSpecRepository.addTile(user, spec, position) }
- }
-
- private fun performRemove(args: List<String>, spec: TileSpec) {
- val user = args.getOrNull(2)?.toInt() ?: userRepository.getSelectedUserInfo().id
- scope.launch { tileSpecRepository.removeTiles(user, listOf(spec)) }
- }
-
- override fun help(pw: PrintWriter) {
- pw.println("Usage: adb shell cmd statusbar $COMMAND:")
- pw.println(" add <spec> [position] [user]")
- pw.println(" remove <spec> [user]")
- }
- }
-
- companion object {
- private const val COMMAND = "qs-pipeline"
- private const val TAG = "PrototypeCoreStartable"
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/TileSpec.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/TileSpec.kt
index af1cd09..11b5dd7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/TileSpec.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/TileSpec.kt
@@ -52,7 +52,11 @@
internal constructor(
override val spec: String,
val componentName: ComponentName,
- ) : TileSpec(spec)
+ ) : TileSpec(spec) {
+ override fun toString(): String {
+ return "CustomTileSpec(${componentName.toShortString()})"
+ }
+ }
companion object {
/** Create a [TileSpec] from the string [spec]. */
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLogger.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLogger.kt
index 8318ec9..573cb715 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLogger.kt
@@ -18,7 +18,8 @@
import android.annotation.UserIdInt
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.log.core.LogLevel
+import com.android.systemui.qs.pipeline.dagger.QSAutoAddLog
import com.android.systemui.qs.pipeline.dagger.QSTileListLog
import com.android.systemui.qs.pipeline.shared.TileSpec
import javax.inject.Inject
@@ -32,10 +33,12 @@
@Inject
constructor(
@QSTileListLog private val tileListLogBuffer: LogBuffer,
+ @QSAutoAddLog private val tileAutoAddLogBuffer: LogBuffer,
) {
companion object {
const val TILE_LIST_TAG = "QSTileListLog"
+ const val AUTO_ADD_TAG = "QSAutoAddableLog"
}
/**
@@ -136,6 +139,31 @@
)
}
+ fun logTileAutoAdded(userId: Int, spec: TileSpec, position: Int) {
+ tileAutoAddLogBuffer.log(
+ AUTO_ADD_TAG,
+ LogLevel.DEBUG,
+ {
+ int1 = userId
+ int2 = position
+ str1 = spec.toString()
+ },
+ { "Tile $str1 auto added for user $int1 at position $int2" }
+ )
+ }
+
+ fun logTileAutoRemoved(userId: Int, spec: TileSpec) {
+ tileAutoAddLogBuffer.log(
+ AUTO_ADD_TAG,
+ LogLevel.DEBUG,
+ {
+ int1 = userId
+ str1 = spec.toString()
+ },
+ { "Tile $str1 auto removed for user $int1" }
+ )
+ }
+
/** Reasons for destroying an existing tile. */
enum class TileDestroyedReason(val readable: String) {
TILE_REMOVED("Tile removed from current set"),
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
index e541681..7e45491 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
@@ -248,13 +248,11 @@
*/
private static int getIconColorForState(Context context, QSTile.State state) {
if (state.disabledByPolicy || state.state == Tile.STATE_UNAVAILABLE) {
- return Utils.getColorAttrDefaultColor(
- context, com.android.internal.R.attr.textColorTertiary);
+ return Utils.getColorAttrDefaultColor(context, R.attr.outline);
} else if (state.state == Tile.STATE_INACTIVE) {
- return Utils.getColorAttrDefaultColor(context, android.R.attr.textColorPrimary);
+ return Utils.getColorAttrDefaultColor(context, R.attr.onShadeInactiveVariant);
} else if (state.state == Tile.STATE_ACTIVE) {
- return Utils.getColorAttrDefaultColor(context,
- com.android.internal.R.attr.textColorOnAccent);
+ return Utils.getColorAttrDefaultColor(context, R.attr.onShadeActive);
} else {
Log.e("QSIconView", "Invalid state " + state);
return 0;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
index b806683..d81e4c2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
@@ -29,6 +29,7 @@
import android.service.quicksettings.Tile
import android.text.TextUtils
import android.util.Log
+import android.util.TypedValue
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
@@ -92,24 +93,21 @@
updateHeight()
}
- private val colorActive = Utils.getColorAttrDefaultColor(context,
- com.android.internal.R.attr.colorAccentPrimary)
- private val colorInactive = Utils.getColorAttrDefaultColor(context, R.attr.offStateColor)
- private val colorUnavailable = Utils.applyAlpha(UNAVAILABLE_ALPHA, colorInactive)
+ private val colorActive = Utils.getColorAttrDefaultColor(context, R.attr.shadeActive)
+ private val colorInactive = Utils.getColorAttrDefaultColor(context, R.attr.shadeInactive)
+ private val colorUnavailable = Utils.getColorAttrDefaultColor(context, R.attr.shadeDisabled)
- private val colorLabelActive =
- Utils.getColorAttrDefaultColor(context, com.android.internal.R.attr.textColorOnAccent)
- private val colorLabelInactive =
- Utils.getColorAttrDefaultColor(context, android.R.attr.textColorPrimary)
+ private val colorLabelActive = Utils.getColorAttrDefaultColor(context, R.attr.onShadeActive)
+ private val colorLabelInactive = Utils.getColorAttrDefaultColor(context, R.attr.onShadeInactive)
private val colorLabelUnavailable =
- Utils.getColorAttrDefaultColor(context, com.android.internal.R.attr.textColorTertiary)
+ Utils.getColorAttrDefaultColor(context, R.attr.outline)
private val colorSecondaryLabelActive =
- Utils.getColorAttrDefaultColor(context, android.R.attr.textColorSecondaryInverse)
+ Utils.getColorAttrDefaultColor(context, R.attr.onShadeActiveVariant)
private val colorSecondaryLabelInactive =
- Utils.getColorAttrDefaultColor(context, android.R.attr.textColorSecondary)
+ Utils.getColorAttrDefaultColor(context, R.attr.onShadeInactiveVariant)
private val colorSecondaryLabelUnavailable =
- Utils.getColorAttrDefaultColor(context, com.android.internal.R.attr.textColorTertiary)
+ Utils.getColorAttrDefaultColor(context, R.attr.outline)
private lateinit var label: TextView
protected lateinit var secondaryLabel: TextView
@@ -151,6 +149,11 @@
private val locInScreen = IntArray(2)
init {
+ val typedValue = TypedValue()
+ if (!getContext().theme.resolveAttribute(R.attr.isQsTheme, typedValue, true)) {
+ throw IllegalStateException("QSViewImpl must be inflated with a theme that contains " +
+ "Theme.SystemUI.QuickSettings")
+ }
setId(generateViewId())
orientation = LinearLayout.HORIZONTAL
gravity = Gravity.CENTER_VERTICAL or Gravity.START
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootView.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootView.kt
index 9b5898f..2ad5429 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootView.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootView.kt
@@ -52,9 +52,8 @@
setOnBackInvokedDispatcher(viewRootImpl.onBackInvokedDispatcher)
}
- override fun getLifecycle(): Lifecycle {
- return this@repeatWhenAttached.lifecycle
- }
+ override val lifecycle: Lifecycle =
+ this@repeatWhenAttached.lifecycle
}
)
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 2ef9e07..44436b9 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -117,6 +117,7 @@
import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants;
import com.android.systemui.classifier.Classifier;
import com.android.systemui.classifier.FalsingCollector;
+import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.DisplayId;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.doze.DozeLog;
@@ -208,7 +209,6 @@
import com.android.systemui.statusbar.phone.StatusBarTouchableRegionManager;
import com.android.systemui.statusbar.phone.TapAgainViewController;
import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
-import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent;
import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardQsUserSwitchController;
@@ -238,7 +238,7 @@
import kotlinx.coroutines.CoroutineDispatcher;
-@CentralSurfacesComponent.CentralSurfacesScope
+@SysUISingleton
public final class NotificationPanelViewController implements ShadeSurface, Dumpable {
public static final String TAG = NotificationPanelView.class.getSimpleName();
@@ -1407,11 +1407,13 @@
mKeyguardBottomArea = keyguardBottomArea;
}
- void setOpenCloseListener(OpenCloseListener openCloseListener) {
+ @Override
+ public void setOpenCloseListener(OpenCloseListener openCloseListener) {
mOpenCloseListener = openCloseListener;
}
- void setTrackingStartedListener(TrackingStartedListener trackingStartedListener) {
+ @Override
+ public void setTrackingStartedListener(TrackingStartedListener trackingStartedListener) {
mTrackingStartedListener = trackingStartedListener;
}
@@ -3378,11 +3380,13 @@
ViewGroupFadeHelper.reset(mView);
}
- void addOnGlobalLayoutListener(ViewTreeObserver.OnGlobalLayoutListener listener) {
+ @Override
+ public void addOnGlobalLayoutListener(ViewTreeObserver.OnGlobalLayoutListener listener) {
mView.getViewTreeObserver().addOnGlobalLayoutListener(listener);
}
- void removeOnGlobalLayoutListener(ViewTreeObserver.OnGlobalLayoutListener listener) {
+ @Override
+ public void removeOnGlobalLayoutListener(ViewTreeObserver.OnGlobalLayoutListener listener) {
mView.getViewTreeObserver().removeOnGlobalLayoutListener(listener);
}
@@ -3565,6 +3569,7 @@
}
private void endMotionEvent(MotionEvent event, float x, float y, boolean forceCancel) {
+ mShadeLog.logEndMotionEvent("endMotionEvent called", forceCancel, false);
mTrackingPointer = -1;
mAmbientState.setSwipingUp(false);
if ((mTracking && mTouchSlopExceeded) || Math.abs(x - mInitialExpandX) > mTouchSlop
@@ -3586,15 +3591,19 @@
} else if (event.getActionMasked() == MotionEvent.ACTION_CANCEL || forceCancel) {
if (onKeyguard) {
expand = true;
+ mShadeLog.logEndMotionEvent("endMotionEvent: cancel while on keyguard",
+ forceCancel, expand);
} else if (mCentralSurfaces.isBouncerShowingOverDream()) {
expand = false;
} else {
// If we get a cancel, put the shade back to the state it was in when the
// gesture started
expand = !mPanelClosedOnDown;
+ mShadeLog.logEndMotionEvent("endMotionEvent: cancel", forceCancel, expand);
}
} else {
expand = flingExpands(vel, vectorVel, x, y);
+ mShadeLog.logEndMotionEvent("endMotionEvent: flingExpands", forceCancel, expand);
}
mDozeLog.traceFling(
@@ -3847,8 +3856,8 @@
return !isFullyCollapsed() && !mTracking && !mClosing;
}
- /** Collapses the shade instantly without animation. */
- void instantCollapse() {
+ @Override
+ public void instantCollapse() {
abortAnimations();
setExpandedFraction(0f);
if (mExpanding) {
@@ -4021,8 +4030,8 @@
mFixedDuration = NO_FIXED_DURATION;
}
- /** */
- boolean postToView(Runnable action) {
+ @Override
+ public boolean postToView(Runnable action) {
return mView.post(action);
}
@@ -4731,6 +4740,8 @@
mTouchSlopExceeded = mTouchSlopExceededBeforeDown;
mMotionAborted = false;
mPanelClosedOnDown = isFullyCollapsed();
+ mShadeLog.logPanelClosedOnDown("intercept down touch", mPanelClosedOnDown,
+ mExpandedFraction);
mCollapsedAndHeadsUpOnDown = false;
mHasLayoutedSinceDown = false;
mUpdateFlingOnLayout = false;
@@ -4948,6 +4959,8 @@
startExpandMotion(x, y, false /* startTracking */, mExpandedHeight);
mMinExpandHeight = 0.0f;
mPanelClosedOnDown = isFullyCollapsed();
+ mShadeLog.logPanelClosedOnDown("handle down touch", mPanelClosedOnDown,
+ mExpandedFraction);
mHasLayoutedSinceDown = false;
mUpdateFlingOnLayout = false;
mMotionAborted = false;
@@ -5113,18 +5126,5 @@
return super.performAccessibilityAction(host, action, args);
}
}
-
- /** Listens for when touch tracking begins. */
- interface TrackingStartedListener {
- void onTrackingStarted();
- }
-
- /** Listens for when shade begins opening of finishes closing. */
- interface OpenCloseListener {
- /** Called when the shade finishes closing. */
- void onClosingFinished();
- /** Called when the shade starts opening. */
- void onOpenStarted();
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
index 1361c9f..fe1b365 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
@@ -68,6 +68,7 @@
import com.android.systemui.R;
import com.android.systemui.classifier.Classifier;
import com.android.systemui.classifier.FalsingCollector;
+import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.fragments.FragmentHostManager;
@@ -98,7 +99,6 @@
import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.phone.StatusBarTouchableRegionManager;
-import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent;
import com.android.systemui.statusbar.policy.CastController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.LargeScreenUtils;
@@ -113,7 +113,7 @@
/** Handles QuickSettings touch handling, expansion and animation state
* TODO (b/264460656) make this dumpable
*/
-@CentralSurfacesComponent.CentralSurfacesScope
+@SysUISingleton
public class QuickSettingsController implements Dumpable {
public static final String TAG = "QuickSettingsController";
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java b/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java
index 9ed0e9a..317d885 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java
@@ -165,8 +165,7 @@
NotificationShadeWindowViewController notificationShadeWindowViewController);
/** */
- void setNotificationPanelViewController(
- NotificationPanelViewController notificationPanelViewController);
+ void setShadeViewController(ShadeViewController shadeViewController);
/** Listens for shade visibility changes. */
interface ShadeVisibilityListener {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
index c9338b3..b92afac 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
@@ -70,7 +70,8 @@
private boolean mExpandedVisible;
- private NotificationPanelViewController mNotificationPanelViewController;
+ // TODO(b/237661616): Rename this variable to mShadeViewController.
+ private ShadeViewController mNotificationPanelViewController;
private NotificationPresenter mPresenter;
private NotificationShadeWindowViewController mNotificationShadeWindowViewController;
private ShadeVisibilityListener mShadeVisibilityListener;
@@ -426,12 +427,11 @@
}
@Override
- public void setNotificationPanelViewController(
- NotificationPanelViewController notificationPanelViewController) {
- mNotificationPanelViewController = notificationPanelViewController;
+ public void setShadeViewController(ShadeViewController shadeViewController) {
+ mNotificationPanelViewController = shadeViewController;
mNotificationPanelViewController.setTrackingStartedListener(this::runPostCollapseRunnables);
mNotificationPanelViewController.setOpenCloseListener(
- new NotificationPanelViewController.OpenCloseListener() {
+ new OpenCloseListener() {
@Override
public void onClosingFinished() {
ShadeControllerImpl.this.onClosingFinished();
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt
index 3af75ce..8789a8b 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt
@@ -195,7 +195,9 @@
set(value) {
if (visible && field != value) {
field = value
+ iconContainer.setQsExpansionTransitioning(value > 0f && value < 1.0f)
updatePosition()
+ updateIgnoredSlots()
}
}
@@ -216,6 +218,8 @@
view.onApplyWindowInsets(insets)
}
+ private var singleCarrier = false
+
private val demoModeReceiver =
object : DemoMode {
override fun demoCommands() = listOf(DemoMode.COMMAND_CLOCK)
@@ -479,17 +483,20 @@
private fun updateListeners() {
mShadeCarrierGroupController.setListening(visible)
if (visible) {
- updateSingleCarrier(mShadeCarrierGroupController.isSingleCarrier)
+ singleCarrier = mShadeCarrierGroupController.isSingleCarrier
+ updateIgnoredSlots()
mShadeCarrierGroupController.setOnSingleCarrierChangedListener {
- updateSingleCarrier(it)
+ singleCarrier = it
+ updateIgnoredSlots()
}
} else {
mShadeCarrierGroupController.setOnSingleCarrierChangedListener(null)
}
}
- private fun updateSingleCarrier(singleCarrier: Boolean) {
- if (singleCarrier) {
+ private fun updateIgnoredSlots() {
+ // switching from QQS to QS state halfway through the transition
+ if (singleCarrier || qsExpandedFraction < 0.5) {
iconContainer.removeIgnoredSlots(carrierIconSlots)
} else {
iconContainer.addIgnoredSlots(carrierIconSlots)
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt
index 2da8d5f4..1c30bdd 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt
@@ -19,7 +19,7 @@
import android.view.MotionEvent
import com.android.systemui.log.dagger.ShadeLog
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.log.core.LogLevel
import com.android.systemui.shade.ShadeViewController.Companion.FLING_COLLAPSE
import com.android.systemui.shade.ShadeViewController.Companion.FLING_EXPAND
import com.android.systemui.shade.ShadeViewController.Companion.FLING_HIDE
@@ -90,7 +90,7 @@
double1 = event.y.toDouble()
},
{
- "$str1\neventTime=$long1,downTime=$long2,y=$double1,action=$int1,class=$int2"
+ "$str1: eventTime=$long1,downTime=$long2,y=$double1,action=$int1,class=$int2"
}
)
}
@@ -280,6 +280,42 @@
)
}
+ fun logEndMotionEvent(
+ msg: String,
+ forceCancel: Boolean,
+ expand: Boolean,
+ )
+ {
+ buffer.log(
+ TAG,
+ LogLevel.VERBOSE,
+ {
+ str1 = msg
+ bool1 = forceCancel
+ bool2 = expand
+ },
+ { "$str1; force=$bool1; expand=$bool2" }
+ )
+ }
+
+ fun logPanelClosedOnDown(
+ msg: String,
+ panelClosedOnDown: Boolean,
+ expandFraction: Float,
+ )
+ {
+ buffer.log(
+ TAG,
+ LogLevel.VERBOSE,
+ {
+ str1 = msg
+ bool1 = panelClosedOnDown
+ double1 = expandFraction.toDouble()
+ },
+ { "$str1; mPanelClosedOnDown=$bool1; mExpandedFraction=$double1" }
+ )
+ }
+
fun flingQs(flingType: Int, isClick: Boolean) {
buffer.log(
TAG,
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt
index a2b9351..0500a58 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt
@@ -49,6 +49,7 @@
import com.android.systemui.statusbar.notification.row.dagger.NotificationShelfComponent
import com.android.systemui.statusbar.notification.shelf.ui.viewbinder.NotificationShelfViewBinderWrapperControllerImpl
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
+import com.android.systemui.statusbar.phone.KeyguardBottomAreaView
import com.android.systemui.statusbar.phone.StatusIconContainer
import com.android.systemui.statusbar.phone.TapAgainView
import com.android.systemui.statusbar.policy.BatteryController
@@ -71,6 +72,12 @@
@ClassKey(AuthRippleController::class)
abstract fun bindAuthRippleController(controller: AuthRippleController): CoreStartable
+ @Binds
+ @SysUISingleton
+ abstract fun bindsShadeViewController(
+ notificationPanelViewController: NotificationPanelViewController
+ ): ShadeViewController
+
companion object {
const val SHADE_HEADER = "large_screen_shade_header"
@@ -165,6 +172,20 @@
return notificationShadeWindowView.findViewById(R.id.notification_panel)
}
+ /**
+ * Constructs a new, unattached [KeyguardBottomAreaView].
+ *
+ * Note that this is explicitly _not_ a singleton, as we want to be able to reinflate it
+ */
+ @Provides
+ fun providesKeyguardBottomAreaView(
+ npv: NotificationPanelView,
+ layoutInflater: LayoutInflater,
+ ): KeyguardBottomAreaView {
+ return layoutInflater.inflate(R.layout.keyguard_bottom_area, npv, false)
+ as KeyguardBottomAreaView
+ }
+
@Provides
@SysUISingleton
fun providesLightRevealScrim(
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
index 3d9fcf9..9aa5eb0 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
@@ -17,6 +17,7 @@
import android.view.MotionEvent
import android.view.ViewGroup
+import android.view.ViewTreeObserver
import com.android.systemui.keyguard.shared.model.WakefulnessModel
import com.android.systemui.statusbar.RemoteInputController
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
@@ -77,6 +78,9 @@
/** Collapses the shade with an animation duration in milliseconds. */
fun collapseWithDuration(animationDuration: Int)
+ /** Collapses the shade instantly without animation. */
+ fun instantCollapse()
+
/**
* Animate QS collapse by flinging it. If QS is expanded, it will collapse into QQS and stop. If
* in split shade, it will collapse the whole shade.
@@ -100,6 +104,9 @@
/** Returns whether the shade's top level view is enabled. */
val isViewEnabled: Boolean
+ /** Sets a listener to be notified when the shade starts opening or finishes closing. */
+ fun setOpenCloseListener(openCloseListener: OpenCloseListener)
+
/** Returns whether status bar icons should be hidden when the shade is expanded. */
fun shouldHideStatusBarIconsWhenExpanded(): Boolean
@@ -109,6 +116,9 @@
*/
fun blockExpansionForCurrentTouch()
+ /** Sets a listener to be notified when touch tracking begins. */
+ fun setTrackingStartedListener(trackingStartedListener: TrackingStartedListener)
+
/**
* Disables the shade header.
*
@@ -178,6 +188,15 @@
/** Ensures that the touchable region is updated. */
fun updateTouchableRegion()
+ /** Adds a global layout listener. */
+ fun addOnGlobalLayoutListener(listener: ViewTreeObserver.OnGlobalLayoutListener)
+
+ /** Removes a global layout listener. */
+ fun removeOnGlobalLayoutListener(listener: ViewTreeObserver.OnGlobalLayoutListener)
+
+ /** Posts the given runnable to the view. */
+ fun postToView(action: Runnable): Boolean
+
// ******* Begin Keyguard Section *********
/** Animate to expanded shade after a delay in ms. Used for lockscreen to shade transition. */
fun transitionToExpandedShade(delay: Long)
@@ -337,3 +356,17 @@
/** Return the fraction of the shade that's expanded, when in lockscreen. */
val lockscreenShadeDragProgress: Float
}
+
+/** Listens for when touch tracking begins. */
+interface TrackingStartedListener {
+ fun onTrackingStarted()
+}
+
+/** Listens for when shade begins opening or finishes closing. */
+interface OpenCloseListener {
+ /** Called when the shade finishes closing. */
+ fun onClosingFinished()
+
+ /** Called when the shade starts opening. */
+ fun onOpenStarted()
+}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeWindowLogger.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeWindowLogger.kt
index d06634b..51a27cf 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeWindowLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeWindowLogger.kt
@@ -21,9 +21,9 @@
import com.android.systemui.log.ConstantStringsLogger
import com.android.systemui.log.ConstantStringsLoggerImpl
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
-import com.android.systemui.log.LogLevel.DEBUG
-import com.android.systemui.log.LogMessage
+import com.android.systemui.log.core.LogLevel
+import com.android.systemui.log.core.LogLevel.DEBUG
+import com.android.systemui.log.core.LogMessage
import javax.inject.Inject
private const val TAG = "systemui.shadewindow"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActionClickLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/ActionClickLogger.kt
index e008ec0..d3c19b7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActionClickLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActionClickLogger.kt
@@ -19,7 +19,7 @@
import android.app.PendingIntent
import com.android.systemui.log.dagger.NotifInteractionLog
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.log.core.LogLevel
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 6c2c0cf..a532195 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -19,6 +19,7 @@
import static android.app.StatusBarManager.DISABLE2_NONE;
import static android.app.StatusBarManager.DISABLE_NONE;
import static android.inputmethodservice.InputMethodService.BACK_DISPOSITION_DEFAULT;
+import static android.inputmethodservice.InputMethodService.IME_INVISIBLE;
import static android.view.Display.INVALID_DISPLAY;
import android.annotation.Nullable;
@@ -36,7 +37,7 @@
import android.hardware.biometrics.IBiometricSysuiReceiver;
import android.hardware.biometrics.PromptInfo;
import android.hardware.fingerprint.IUdfpsRefreshRateRequestCallback;
-import android.inputmethodservice.InputMethodService;
+import android.inputmethodservice.InputMethodService.BackDispositionMode;
import android.media.INearbyMediaDevicesProvider;
import android.media.MediaRoute2Info;
import android.os.Binder;
@@ -225,10 +226,8 @@
* @param backDisposition Disposition mode of back button. It should be one of below flags:
* @param showImeSwitcher {@code true} to show IME switch button.
*/
- default void setImeWindowStatus(int displayId, IBinder token,
- @InputMethodService.ImeWindowVisibility int vis,
- @InputMethodService.BackDispositionMode int backDisposition,
- boolean showImeSwitcher) { }
+ default void setImeWindowStatus(int displayId, IBinder token, int vis,
+ @BackDispositionMode int backDisposition, boolean showImeSwitcher) { }
default void showRecentApps(boolean triggeredFromAltTab) { }
default void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) { }
default void toggleTaskbar() { }
@@ -679,9 +678,7 @@
}
@Override
- public void setImeWindowStatus(int displayId, IBinder token,
- @InputMethodService.ImeWindowVisibility int vis,
- @InputMethodService.BackDispositionMode int backDisposition,
+ public void setImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition,
boolean showImeSwitcher) {
synchronized (mLock) {
mHandler.removeMessages(MSG_SHOW_IME_BUTTON);
@@ -1095,9 +1092,7 @@
}
}
- private void handleShowImeButton(int displayId, IBinder token,
- @InputMethodService.ImeWindowVisibility int vis,
- @InputMethodService.BackDispositionMode int backDisposition,
+ private void handleShowImeButton(int displayId, IBinder token, int vis, int backDisposition,
boolean showImeSwitcher) {
if (displayId == INVALID_DISPLAY) return;
@@ -1117,7 +1112,7 @@
private void sendImeInvisibleStatusForPrevNavBar() {
for (int i = 0; i < mCallbacks.size(); i++) {
mCallbacks.get(i).setImeWindowStatus(mLastUpdatedImeDisplayId,
- null /* token */, 0 /* vis */, BACK_DISPOSITION_DEFAULT,
+ null /* token */, IME_INVISIBLE, BACK_DISPOSITION_DEFAULT,
false /* showImeSwitcher */);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java
index 3918144..ec66e99 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java
@@ -557,19 +557,7 @@
new ShortcutKeyGroupMultiMappingInfo(
context.getString(R.string.group_system_access_google_assistant),
Arrays.asList(
- Pair.create(KeyEvent.KEYCODE_A, KeyEvent.META_META_ON))),
- /* Lock screen: Meta + L */
- new ShortcutKeyGroupMultiMappingInfo(
- context.getString(R.string.group_system_lock_screen),
- Arrays.asList(
- Pair.create(KeyEvent.KEYCODE_L, KeyEvent.META_META_ON))),
- /* Pull up Notes app for quick memo: Meta + Ctrl + N */
- new ShortcutKeyGroupMultiMappingInfo(
- context.getString(R.string.group_system_quick_memo),
- Arrays.asList(
- Pair.create(
- KeyEvent.KEYCODE_N,
- KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON)))
+ Pair.create(KeyEvent.KEYCODE_A, KeyEvent.META_META_ON)))
);
for (ShortcutKeyGroupMultiMappingInfo info : infoList) {
systemGroup.addItem(info.getShortcutMultiMappingInfo());
@@ -611,21 +599,12 @@
new ArrayList<>());
// System multitasking shortcuts:
- // Enter Split screen with current app to RHS: Meta + Ctrl + Right arrow
- // Enter Split screen with current app to LHS: Meta + Ctrl + Left arrow
// Switch from Split screen to full screen: Meta + Ctrl + Up arrow
- // During Split screen: replace an app from one to another: Meta + Ctrl + Down arrow
String[] shortcutLabels = {
- context.getString(R.string.system_multitasking_rhs),
- context.getString(R.string.system_multitasking_lhs),
context.getString(R.string.system_multitasking_full_screen),
- context.getString(R.string.system_multitasking_replace)
};
int[] keyCodes = {
- KeyEvent.KEYCODE_DPAD_RIGHT,
- KeyEvent.KEYCODE_DPAD_LEFT,
KeyEvent.KEYCODE_DPAD_UP,
- KeyEvent.KEYCODE_DPAD_DOWN
};
for (int i = 0; i < shortcutLabels.length; i++) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 9692482..42ebaa3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -41,7 +41,7 @@
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_TRUST;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_USER_LOCKED;
import static com.android.systemui.keyguard.ScreenLifecycle.SCREEN_ON;
-import static com.android.systemui.log.LogLevel.ERROR;
+import static com.android.systemui.log.core.LogLevel.ERROR;
import static com.android.systemui.plugins.FalsingManager.LOW_PENALTY;
import android.app.AlarmManager;
@@ -97,7 +97,7 @@
import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.keyguard.util.IndicationHelper;
-import com.android.systemui.log.LogLevel;
+import com.android.systemui.log.core.LogLevel;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.settings.UserTracker;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/QsFrameTranslateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/QsFrameTranslateController.java
index 59afb18..9702bfc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/QsFrameTranslateController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/QsFrameTranslateController.java
@@ -18,19 +18,19 @@
import android.view.View;
+import com.android.systemui.display.data.repository.DisplayMetricsRepository;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
-import com.android.systemui.statusbar.phone.CentralSurfaces;
/**
* Calculates and moves the QS frame vertically.
*/
public abstract class QsFrameTranslateController {
- protected CentralSurfaces mCentralSurfaces;
+ protected DisplayMetricsRepository mDisplayMetricsRepository;
- public QsFrameTranslateController(CentralSurfaces centralSurfaces) {
- mCentralSurfaces = centralSurfaces;
+ public QsFrameTranslateController(DisplayMetricsRepository displayMetricsRepository) {
+ mDisplayMetricsRepository = displayMetricsRepository;
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/QsFrameTranslateImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/QsFrameTranslateImpl.java
index 85b522c..e429b8b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/QsFrameTranslateImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/QsFrameTranslateImpl.java
@@ -19,9 +19,9 @@
import android.view.View;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.display.data.repository.DisplayMetricsRepository;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
-import com.android.systemui.statusbar.phone.CentralSurfaces;
import javax.inject.Inject;
@@ -34,8 +34,8 @@
public class QsFrameTranslateImpl extends QsFrameTranslateController {
@Inject
- public QsFrameTranslateImpl(CentralSurfaces centralSurfaces) {
- super(centralSurfaces);
+ public QsFrameTranslateImpl(DisplayMetricsRepository displayMetricsRepository) {
+ super(displayMetricsRepository);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java
index 2465c21..73f181b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java
@@ -74,7 +74,7 @@
import com.android.systemui.demomode.DemoModeController;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.log.LogBuffer;
-import com.android.systemui.log.LogLevel;
+import com.android.systemui.log.core.LogLevel;
import com.android.systemui.log.dagger.StatusBarNetworkControllerLog;
import com.android.systemui.qs.tiles.dialog.InternetDialogFactory;
import com.android.systemui.settings.UserTracker;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
index 075b41b..035fa04 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
@@ -41,6 +41,8 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.power.domain.interactor.PowerInteractor;
import com.android.systemui.settings.DisplayTracker;
+import com.android.systemui.shade.NotificationPanelViewController;
+import com.android.systemui.shade.ShadeSurface;
import com.android.systemui.shade.carrier.ShadeCarrierGroupController;
import com.android.systemui.statusbar.ActionClickLogger;
import com.android.systemui.statusbar.CommandQueue;
@@ -273,6 +275,21 @@
return ongoingCallController;
}
+ /**
+ * {@link NotificationPanelViewController} implements two interfaces:
+ * - {@link com.android.systemui.shade.ShadeViewController}, which can be used by any class
+ * needing access to the shade.
+ * - {@link ShadeSurface}, which should *only* be used by {@link CentralSurfacesImpl}.
+ *
+ * Since {@link ShadeSurface} should only be accessible by {@link CentralSurfacesImpl}, it's
+ * *only* bound in this CentralSurfaces dependencies module.
+ * The {@link com.android.systemui.shade.ShadeViewController} interface is bound in
+ * {@link com.android.systemui.shade.ShadeModule} so others can access it.
+ */
+ @Binds
+ @SysUISingleton
+ ShadeSurface provideShadeSurface(NotificationPanelViewController impl);
+
/** */
@Binds
ShadeCarrierGroupController.SlotIndexResolver provideSlotIndexResolver(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/data/model/DisableFlagsModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/data/model/DisableFlagsModel.kt
index ac05248..2bb4765 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/data/model/DisableFlagsModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/data/model/DisableFlagsModel.kt
@@ -20,7 +20,7 @@
import android.app.StatusBarManager.DISABLE_NONE
import android.app.StatusBarManager.DISABLE_NOTIFICATION_ALERTS
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.log.core.LogLevel
import com.android.systemui.statusbar.disableflags.DisableFlagsLogger
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/StatusBarEventsModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/StatusBarEventsModule.kt
index 3d6d489..84796f9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/StatusBarEventsModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/StatusBarEventsModule.kt
@@ -22,6 +22,8 @@
import com.android.systemui.dump.DumpManager
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogBufferFactory
import com.android.systemui.statusbar.window.StatusBarWindowController
import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.time.SystemClock
@@ -36,6 +38,13 @@
@Provides
@SysUISingleton
+ @SystemStatusAnimationSchedulerLog
+ fun provideSystemStatusAnimationSchedulerLogBuffer(factory: LogBufferFactory): LogBuffer {
+ return factory.create("SystemStatusAnimationSchedulerLog", 60)
+ }
+
+ @Provides
+ @SysUISingleton
fun provideSystemStatusAnimationScheduler(
featureFlags: FeatureFlags,
coordinator: SystemEventCoordinator,
@@ -44,7 +53,8 @@
dumpManager: DumpManager,
systemClock: SystemClock,
@Application coroutineScope: CoroutineScope,
- @Main executor: DelayableExecutor
+ @Main executor: DelayableExecutor,
+ logger: SystemStatusAnimationSchedulerLogger
): SystemStatusAnimationScheduler {
return if (featureFlags.isEnabled(Flags.PLUG_IN_STATUS_BAR_CHIP)) {
SystemStatusAnimationSchedulerImpl(
@@ -53,7 +63,8 @@
statusBarWindowController,
dumpManager,
systemClock,
- coroutineScope
+ coroutineScope,
+ logger
)
} else {
SystemStatusAnimationSchedulerLegacyImpl(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImpl.kt
index 56ea703..6fc715a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImpl.kt
@@ -18,7 +18,6 @@
import android.os.Process
import android.provider.DeviceConfig
-import android.util.Log
import androidx.core.animation.Animator
import androidx.core.animation.AnimatorListenerAdapter
import androidx.core.animation.AnimatorSet
@@ -69,7 +68,8 @@
private val statusBarWindowController: StatusBarWindowController,
dumpManager: DumpManager,
private val systemClock: SystemClock,
- @Application private val coroutineScope: CoroutineScope
+ @Application private val coroutineScope: CoroutineScope,
+ private val logger: SystemStatusAnimationSchedulerLogger?
) : SystemStatusAnimationScheduler {
companion object {
@@ -121,6 +121,10 @@
}
}
}
+
+ coroutineScope.launch {
+ animationState.collect { logger?.logAnimationStateUpdate(it) }
+ }
}
@SystemAnimationState override fun getAnimationState(): Int = animationState.value
@@ -140,32 +144,17 @@
) {
// a event can only be scheduled if no other event is in progress or it has a higher
// priority. If a persistent dot is currently displayed, don't schedule the event.
- if (DEBUG) {
- Log.d(TAG, "scheduling event $event")
- }
-
+ logger?.logScheduleEvent(event)
scheduleEvent(event)
} else if (currentlyDisplayedEvent?.shouldUpdateFromEvent(event) == true) {
- if (DEBUG) {
- Log.d(
- TAG,
- "updating current event from: $event. animationState=${animationState.value}"
- )
- }
+ logger?.logUpdateEvent(event, animationState.value)
currentlyDisplayedEvent?.updateFromEvent(event)
if (event.forceVisible) hasPersistentDot = true
} else if (scheduledEvent.value?.shouldUpdateFromEvent(event) == true) {
- if (DEBUG) {
- Log.d(
- TAG,
- "updating scheduled event from: $event. animationState=${animationState.value}"
- )
- }
+ logger?.logUpdateEvent(event, animationState.value)
scheduledEvent.value?.updateFromEvent(event)
} else {
- if (DEBUG) {
- Log.d(TAG, "ignoring event $event")
- }
+ logger?.logIgnoreEvent(event)
}
}
@@ -356,6 +345,7 @@
}
private fun notifyTransitionToPersistentDot(): Animator? {
+ logger?.logTransitionToPersistentDotCallbackInvoked()
val anims: List<Animator> =
listeners.mapNotNull {
it.onSystemStatusAnimationTransitionToPersistentDot(
@@ -373,6 +363,7 @@
private fun notifyHidePersistentDot(): Animator? {
Assert.isMainThread()
+ logger?.logHidePersistentDotCallbackInvoked()
val anims: List<Animator> = listeners.mapNotNull { it.onHidePersistentDot() }
if (animationState.value == SHOWING_PERSISTENT_DOT) {
@@ -424,5 +415,4 @@
}
}
-private const val DEBUG = false
private const val TAG = "SystemStatusAnimationSchedulerImpl"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerLog.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerLog.kt
new file mode 100644
index 0000000..4ac94a6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerLog.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.events
+
+import javax.inject.Qualifier
+
+/** Logs for the SystemStatusAnimationScheduler. */
+@Qualifier
+@MustBeDocumented
+@kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
+annotation class SystemStatusAnimationSchedulerLog
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerLogger.kt
new file mode 100644
index 0000000..22b0b69
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerLogger.kt
@@ -0,0 +1,92 @@
+package com.android.systemui.statusbar.events
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.core.LogLevel
+import javax.inject.Inject
+
+/** Logs for the SystemStatusAnimationScheduler. */
+@SysUISingleton
+class SystemStatusAnimationSchedulerLogger
+@Inject
+constructor(
+ @SystemStatusAnimationSchedulerLog private val logBuffer: LogBuffer,
+) {
+
+ fun logScheduleEvent(event: StatusEvent) {
+ logBuffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ {
+ str1 = event.javaClass.simpleName
+ int1 = event.priority
+ bool1 = event.forceVisible
+ bool2 = event.showAnimation
+ },
+ { "Scheduling event: $str1(forceVisible=$bool1, priority=$int1, showAnimation=$bool2)" }
+ )
+ }
+
+ fun logUpdateEvent(event: StatusEvent, @SystemAnimationState animationState: Int) {
+ logBuffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ {
+ str1 = event.javaClass.simpleName
+ int1 = event.priority
+ bool1 = event.forceVisible
+ bool2 = event.showAnimation
+ int2 = animationState
+ },
+ {
+ "Updating current event from: $str1(forceVisible=$bool1, priority=$int1, " +
+ "showAnimation=$bool2), animationState=${animationState.name()}"
+ }
+ )
+ }
+
+ fun logIgnoreEvent(event: StatusEvent) {
+ logBuffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ {
+ str1 = event.javaClass.simpleName
+ int1 = event.priority
+ bool1 = event.forceVisible
+ bool2 = event.showAnimation
+ },
+ { "Ignore event: $str1(forceVisible=$bool1, priority=$int1, showAnimation=$bool2)" }
+ )
+ }
+
+ fun logHidePersistentDotCallbackInvoked() {
+ logBuffer.log(TAG, LogLevel.DEBUG, "Hide persistent dot callback invoked")
+ }
+
+ fun logTransitionToPersistentDotCallbackInvoked() {
+ logBuffer.log(TAG, LogLevel.DEBUG, "Transition to persistent dot callback invoked")
+ }
+
+ fun logAnimationStateUpdate(@SystemAnimationState animationState: Int) {
+ logBuffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ { int1 = animationState },
+ { "AnimationState update: ${int1.name()}" }
+ )
+ animationState.name()
+ }
+
+ private fun @receiver:SystemAnimationState Int.name() =
+ when (this) {
+ IDLE -> "IDLE"
+ ANIMATION_QUEUED -> "ANIMATION_QUEUED"
+ ANIMATING_IN -> "ANIMATING_IN"
+ RUNNING_CHIP_ANIM -> "RUNNING_CHIP_ANIM"
+ ANIMATING_OUT -> "ANIMATING_OUT"
+ SHOWING_PERSISTENT_DOT -> "SHOWING_PERSISTENT_DOT"
+ else -> "UNKNOWN_ANIMATION_STATE"
+ }
+}
+
+private const val TAG = "SystemStatusAnimationSchedulerLog"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeUpGestureLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeUpGestureLogger.kt
index a67c26c..96725fc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeUpGestureLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeUpGestureLogger.kt
@@ -19,7 +19,7 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.dagger.SwipeUpLog
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.log.core.LogLevel
import javax.inject.Inject
/** Log messages for [SwipeUpGestureHandler]. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClickerLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClickerLogger.kt
index a3a72d9..cea2b59 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClickerLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClickerLogger.kt
@@ -18,7 +18,7 @@
import com.android.systemui.log.dagger.NotifInteractionLog
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.log.core.LogLevel
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt
index f7679ed..502e1d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt
@@ -14,7 +14,7 @@
package com.android.systemui.statusbar.notification
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel.DEBUG
+import com.android.systemui.log.core.LogLevel.DEBUG
import com.android.systemui.log.dagger.NotificationLockscreenLog
import com.android.systemui.statusbar.StatusBarState
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/RemoteInputControllerLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/RemoteInputControllerLogger.kt
index 487a5f8..7809eaa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/RemoteInputControllerLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/RemoteInputControllerLogger.kt
@@ -18,7 +18,7 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel.DEBUG
+import com.android.systemui.log.core.LogLevel.DEBUG
import com.android.systemui.log.dagger.NotificationRemoteInputLog
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerLogger.kt
index 39d0833..0ab348d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerLogger.kt
@@ -18,7 +18,7 @@
import com.android.systemui.log.dagger.NotificationLog
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.log.core.LogLevel
import javax.inject.Inject
class GroupCoalescerLogger @Inject constructor(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorLogger.kt
index 79c63e6..bd1141e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorLogger.kt
@@ -2,7 +2,7 @@
import com.android.systemui.log.dagger.NotificationLog
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.log.core.LogLevel
import com.android.systemui.statusbar.notification.row.NotificationGuts
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorLogger.kt
index e17ce5c..496fb83 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorLogger.kt
@@ -4,7 +4,7 @@
import com.android.systemui.log.dagger.NotificationHeadsUpLog
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.log.core.LogLevel
import javax.inject.Inject
private const val TAG = "HeadsUpCoordinator"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorLogger.kt
index 1f8ec34..4c33524 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorLogger.kt
@@ -17,7 +17,7 @@
package com.android.systemui.statusbar.notification.collection.coordinator
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.log.core.LogLevel
import com.android.systemui.log.dagger.UnseenNotificationLog
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorLogger.kt
index 6271d38..bf65043 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorLogger.kt
@@ -18,7 +18,7 @@
import com.android.systemui.log.dagger.NotificationLog
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.log.core.LogLevel
import com.android.systemui.statusbar.notification.collection.GroupEntry
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.logKey
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorLogger.kt
index 1f4861a..0d9681f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorLogger.kt
@@ -18,7 +18,7 @@
import com.android.systemui.log.dagger.NotificationLog
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.log.core.LogLevel
import javax.inject.Inject
private const val TAG = "ShadeEventCoordinator"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt
index f13ff68..a8409d0c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt
@@ -18,9 +18,9 @@
import com.android.systemui.log.dagger.NotificationLog
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel.DEBUG
-import com.android.systemui.log.LogLevel.INFO
-import com.android.systemui.log.LogLevel.WARNING
+import com.android.systemui.log.core.LogLevel.DEBUG
+import com.android.systemui.log.core.LogLevel.INFO
+import com.android.systemui.log.core.LogLevel.WARNING
import com.android.systemui.statusbar.notification.NotifPipelineFlags
import com.android.systemui.statusbar.notification.collection.GroupEntry
import com.android.systemui.statusbar.notification.collection.ListEntry
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt
index 73227ab..014ac54 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt
@@ -22,11 +22,11 @@
import android.service.notification.StatusBarNotification
import com.android.systemui.log.dagger.NotificationLog
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel.DEBUG
-import com.android.systemui.log.LogLevel.ERROR
-import com.android.systemui.log.LogLevel.INFO
-import com.android.systemui.log.LogLevel.WARNING
-import com.android.systemui.log.LogLevel.WTF
+import com.android.systemui.log.core.LogLevel.DEBUG
+import com.android.systemui.log.core.LogLevel.ERROR
+import com.android.systemui.log.core.LogLevel.INFO
+import com.android.systemui.log.core.LogLevel.WARNING
+import com.android.systemui.log.core.LogLevel.WTF
import com.android.systemui.statusbar.notification.collection.NotifCollection
import com.android.systemui.statusbar.notification.collection.NotifCollection.CancellationReason
import com.android.systemui.statusbar.notification.collection.NotifCollection.FutureDismissal
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderLogger.kt
index 07fd349..e61f9bd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderLogger.kt
@@ -18,7 +18,7 @@
import com.android.systemui.log.dagger.NotificationLog
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.log.core.LogLevel
import com.android.systemui.statusbar.notification.NotifPipelineFlags
import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection
import com.android.systemui.util.Compile
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferLogger.kt
index a880b71..082f308 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferLogger.kt
@@ -18,7 +18,7 @@
import com.android.systemui.log.dagger.NotificationLog
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.log.core.LogLevel
import java.lang.RuntimeException
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderLogger.kt
index 0b31265..c6d2861 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderLogger.kt
@@ -2,7 +2,7 @@
import com.android.systemui.log.dagger.NotificationHeadsUpLog
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel.INFO
+import com.android.systemui.log.core.LogLevel.INFO
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.logKey
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt
index 5bac2a9..4a823a4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt
@@ -20,9 +20,9 @@
import com.android.systemui.log.dagger.NotificationInterruptLog
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel.DEBUG
-import com.android.systemui.log.LogLevel.INFO
-import com.android.systemui.log.LogLevel.WARNING
+import com.android.systemui.log.core.LogLevel.DEBUG
+import com.android.systemui.log.core.LogLevel.INFO
+import com.android.systemui.log.core.LogLevel.WARNING
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.logKey
import com.android.systemui.util.Compile
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationRoundnessLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationRoundnessLogger.kt
index fe03b2a..0e1f66f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationRoundnessLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationRoundnessLogger.kt
@@ -17,7 +17,7 @@
package com.android.systemui.statusbar.notification.logging
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel.INFO
+import com.android.systemui.log.core.LogLevel.INFO
import com.android.systemui.log.dagger.NotificationRenderLog
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.row.ExpandableView
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineLogger.kt
index 45be0b1..3856700 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineLogger.kt
@@ -18,7 +18,7 @@
import com.android.systemui.log.dagger.NotificationLog
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel.INFO
+import com.android.systemui.log.core.LogLevel.INFO
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.logKey
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowLogger.kt
index 89338f9..4f5a04f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowLogger.kt
@@ -19,7 +19,7 @@
import android.view.ViewGroup
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.log.core.LogLevel
import com.android.systemui.log.dagger.NotificationLog
import com.android.systemui.log.dagger.NotificationRenderLog
import com.android.systemui.statusbar.notification.collection.NotificationEntry
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStageLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStageLogger.kt
index 684a276..02627fd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStageLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStageLogger.kt
@@ -18,7 +18,7 @@
import com.android.systemui.log.dagger.NotificationLog
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel.INFO
+import com.android.systemui.log.core.LogLevel.INFO
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.logKey
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerLogger.kt
index 6be1ef8..4986b63 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerLogger.kt
@@ -17,7 +17,7 @@
package com.android.systemui.statusbar.notification.stack
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.log.core.LogLevel
import com.android.systemui.log.dagger.NotificationRenderLog
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.logKey
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsLogger.kt
index f953187..2da5582 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsLogger.kt
@@ -19,7 +19,7 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.dagger.NotificationSectionLog
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.log.core.LogLevel
import javax.inject.Inject
private const val TAG = "NotifSections"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLogger.kt
index 9c1bd17..2c38b8d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLogger.kt
@@ -1,11 +1,11 @@
package com.android.systemui.statusbar.notification.stack
import android.view.ViewGroup
-import com.android.systemui.log.dagger.NotificationHeadsUpLog
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel.DEBUG
-import com.android.systemui.log.LogLevel.INFO
-import com.android.systemui.log.LogLevel.ERROR
+import com.android.systemui.log.core.LogLevel.DEBUG
+import com.android.systemui.log.core.LogLevel.INFO
+import com.android.systemui.log.core.LogLevel.ERROR
+import com.android.systemui.log.dagger.NotificationHeadsUpLog
import com.android.systemui.log.dagger.NotificationRenderLog
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.logKey
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateLogger.kt
index c7f80f3..0b2c486 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateLogger.kt
@@ -1,8 +1,8 @@
package com.android.systemui.statusbar.notification.stack
-import com.android.systemui.log.dagger.NotificationHeadsUpLog
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.log.core.LogLevel
+import com.android.systemui.log.dagger.NotificationHeadsUpLog
import com.android.systemui.log.dagger.NotificationRenderLog
import com.android.systemui.statusbar.notification.logKey
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
index f6d53b3..5eafa9e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
@@ -20,6 +20,7 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.res.Resources;
+import android.database.ContentObserver;
import android.hardware.display.ColorDisplayManager;
import android.hardware.display.NightDisplayListener;
import android.os.Handler;
@@ -28,6 +29,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.R;
+import com.android.systemui.dagger.NightDisplayListenerModule;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.qs.AutoAddTracker;
@@ -82,7 +84,8 @@
private final HotspotController mHotspotController;
private final DataSaverController mDataSaverController;
private final ManagedProfileController mManagedProfileController;
- private final NightDisplayListener mNightDisplayListener;
+ private final NightDisplayListenerModule.Builder mNightDisplayListenerBuilder;
+ private NightDisplayListener mNightDisplayListener;
private final CastController mCastController;
private final DeviceControlsController mDeviceControlsController;
private final WalletController mWalletController;
@@ -98,7 +101,7 @@
HotspotController hotspotController,
DataSaverController dataSaverController,
ManagedProfileController managedProfileController,
- NightDisplayListener nightDisplayListener,
+ NightDisplayListenerModule.Builder nightDisplayListenerBuilder,
CastController castController,
ReduceBrightColorsController reduceBrightColorsController,
DeviceControlsController deviceControlsController,
@@ -114,7 +117,7 @@
mHotspotController = hotspotController;
mDataSaverController = dataSaverController;
mManagedProfileController = managedProfileController;
- mNightDisplayListener = nightDisplayListener;
+ mNightDisplayListenerBuilder = nightDisplayListenerBuilder;
mCastController = castController;
mReduceBrightColorsController = reduceBrightColorsController;
mIsReduceBrightColorsAvailable = isReduceBrightColorsAvailable;
@@ -157,6 +160,10 @@
mDataSaverController.addCallback(mDataSaverListener);
}
mManagedProfileController.addCallback(mProfileCallback);
+
+ mNightDisplayListener = mNightDisplayListenerBuilder
+ .setUser(mCurrentUser.getIdentifier())
+ .build();
if (!mAutoTracker.isAdded(NIGHT)
&& ColorDisplayManager.isNightDisplayAvailable(mContext)) {
mNightDisplayListener.setCallback(mNightDisplayCallback);
@@ -193,7 +200,8 @@
mHotspotController.removeCallback(mHotspotCallback);
mDataSaverController.removeCallback(mDataSaverListener);
mManagedProfileController.removeCallback(mProfileCallback);
- if (ColorDisplayManager.isNightDisplayAvailable(mContext)) {
+ if (ColorDisplayManager.isNightDisplayAvailable(mContext)
+ && mNightDisplayListener != null) {
mNightDisplayListener.setCallback(null);
}
if (mIsReduceBrightColorsAvailable) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
index 1754f0c..478baf2f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
@@ -40,6 +40,7 @@
import com.android.keyguard.AuthKeyguardMessageArea;
import com.android.systemui.Dumpable;
import com.android.systemui.animation.ActivityLaunchAnimator;
+import com.android.systemui.display.data.repository.DisplayMetricsRepository;
import com.android.systemui.navigationbar.NavigationBarView;
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
import com.android.systemui.qs.QSPanelController;
@@ -248,8 +249,12 @@
@Override
void dump(PrintWriter pwOriginal, String[] args);
+ /** @deprecated Use {@link DisplayMetricsRepository} instead. */
+ @Deprecated
float getDisplayWidth();
+ /** @deprecated Use {@link DisplayMetricsRepository} instead. */
+ @Deprecated
float getDisplayHeight();
void readyForKeyguardDone();
@@ -384,6 +389,9 @@
void setLaunchEmergencyActionOnFinishedWaking(boolean launch);
QSPanelController getQSPanelController();
+
+ /** @deprecated Use {@link DisplayMetricsRepository} instead. */
+ @Deprecated
float getDisplayDensity();
void extendDozePulse();
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 41f0c11..39b13d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -182,7 +182,6 @@
import com.android.systemui.settings.UserTracker;
import com.android.systemui.settings.brightness.BrightnessSliderController;
import com.android.systemui.shade.CameraLauncher;
-import com.android.systemui.shade.NotificationPanelViewController;
import com.android.systemui.shade.NotificationShadeWindowView;
import com.android.systemui.shade.NotificationShadeWindowViewController;
import com.android.systemui.shade.QuickSettingsController;
@@ -477,14 +476,12 @@
private final Lazy<LightRevealScrimViewModel> mLightRevealScrimViewModelLazy;
/** Controller for the Shade. */
- @VisibleForTesting
- ShadeSurface mShadeSurface;
+ private final ShadeSurface mShadeSurface;
private final ShadeLogger mShadeLogger;
// settings
private QSPanelController mQSPanelController;
- @VisibleForTesting
- QuickSettingsController mQsController;
+ private final QuickSettingsController mQsController;
KeyguardIndicationController mKeyguardIndicationController;
@@ -704,9 +701,11 @@
MetricsLogger metricsLogger,
ShadeLogger shadeLogger,
@UiBackground Executor uiBgExecutor,
+ ShadeSurface shadeSurface,
NotificationMediaManager notificationMediaManager,
NotificationLockscreenUserManager lockScreenUserManager,
NotificationRemoteInputManager remoteInputManager,
+ QuickSettingsController quickSettingsController,
UserSwitcherController userSwitcherController,
BatteryController batteryController,
SysuiColorExtractor colorExtractor,
@@ -805,9 +804,11 @@
mMetricsLogger = metricsLogger;
mShadeLogger = shadeLogger;
mUiBgExecutor = uiBgExecutor;
+ mShadeSurface = shadeSurface;
mMediaManager = notificationMediaManager;
mLockscreenUserManager = lockScreenUserManager;
mRemoteInputManager = remoteInputManager;
+ mQsController = quickSettingsController;
mUserSwitcherController = userSwitcherController;
mBatteryController = batteryController;
mColorExtractor = colorExtractor;
@@ -1611,13 +1612,9 @@
// (Right now, there's a circular dependency.)
mNotificationShadeWindowController.setWindowRootView(windowRootView);
mNotificationShadeWindowViewController.setupExpandedStatusBar();
- NotificationPanelViewController npvc =
- mCentralSurfacesComponent.getNotificationPanelViewController();
- mShadeSurface = npvc;
- mShadeController.setNotificationPanelViewController(npvc);
+ mShadeController.setShadeViewController(mShadeSurface);
mShadeController.setNotificationShadeWindowViewController(
mNotificationShadeWindowViewController);
- mQsController = mCentralSurfacesComponent.getQuickSettingsController();
mBackActionInteractor.setup(mQsController, mShadeSurface);
mPresenter = mCentralSurfacesComponent.getNotificationPresenter();
mNotificationActivityStarter = mCentralSurfacesComponent.getNotificationActivityStarter();
@@ -1813,7 +1810,7 @@
@Override
public void onStatusBarTrackpadEvent(MotionEvent event) {
- mCentralSurfacesComponent.getNotificationPanelViewController().handleExternalTouch(event);
+ mShadeSurface.handleExternalTouch(event);
}
private void onExpandedInvisible() {
@@ -2084,16 +2081,19 @@
}
@Override
+ @Deprecated
public float getDisplayDensity() {
return mDisplayMetrics.density;
}
@Override
+ @Deprecated
public float getDisplayWidth() {
return mDisplayMetrics.widthPixels;
}
@Override
+ @Deprecated
public float getDisplayHeight() {
return mDisplayMetrics.heightPixels;
}
@@ -2180,7 +2180,6 @@
if (mLockscreenWallpaper != null && !mWallpaperManager.isLockscreenLiveWallpaperEnabled()) {
mLockscreenWallpaper.setCurrentUser(newUserId);
}
- mScrimController.setCurrentUser(newUserId);
if (mWallpaperSupported) {
mWallpaperChangedReceiver.onReceive(mContext, null);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
index 4d716c2..680f19a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
@@ -45,7 +45,7 @@
import com.android.systemui.R;
import com.android.systemui.battery.BatteryMeterViewController;
import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.log.LogLevel;
+import com.android.systemui.log.core.LogLevel;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shade.ShadeViewStateProvider;
import com.android.systemui.statusbar.CommandQueue;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LSShadeTransitionLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LSShadeTransitionLogger.kt
index 5c357d7..686efb7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LSShadeTransitionLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LSShadeTransitionLogger.kt
@@ -21,7 +21,7 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent
import com.android.systemui.log.dagger.LSShadeTransitionLog
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.log.core.LogLevel
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.row.ExpandableView
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index e6b76ad..3b5aaea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -48,6 +48,7 @@
import com.android.systemui.dagger.qualifiers.DisplayId;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dagger.qualifiers.UiBackground;
+import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor;
import com.android.systemui.privacy.PrivacyItem;
import com.android.systemui.privacy.PrivacyItemController;
import com.android.systemui.privacy.PrivacyType;
@@ -74,6 +75,7 @@
import com.android.systemui.statusbar.policy.UserInfoController;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.util.RingerModeTracker;
+import com.android.systemui.util.kotlin.JavaAdapter;
import com.android.systemui.util.time.DateFormatUtil;
import java.io.PrintWriter;
@@ -121,9 +123,12 @@
private final String mSlotCamera;
private final String mSlotSensorsOff;
private final String mSlotScreenRecord;
+ private final String mSlotConnectedDisplay;
private final int mDisplayId;
private final SharedPreferences mSharedPreferences;
private final DateFormatUtil mDateFormatUtil;
+ private final JavaAdapter mJavaAdapter;
+ private final ConnectedDisplayInteractor mConnectedDisplayInteractor;
private final TelecomManager mTelecomManager;
private final Handler mHandler;
@@ -182,9 +187,13 @@
@Main SharedPreferences sharedPreferences, DateFormatUtil dateFormatUtil,
RingerModeTracker ringerModeTracker,
PrivacyItemController privacyItemController,
- PrivacyLogger privacyLogger) {
+ PrivacyLogger privacyLogger,
+ ConnectedDisplayInteractor connectedDisplayInteractor,
+ JavaAdapter javaAdapter
+ ) {
mIconController = iconController;
mCommandQueue = commandQueue;
+ mConnectedDisplayInteractor = connectedDisplayInteractor;
mBroadcastDispatcher = broadcastDispatcher;
mHandler = new Handler(looper);
mResources = resources;
@@ -211,8 +220,11 @@
mTelecomManager = telecomManager;
mRingerModeTracker = ringerModeTracker;
mPrivacyLogger = privacyLogger;
+ mJavaAdapter = javaAdapter;
mSlotCast = resources.getString(com.android.internal.R.string.status_bar_cast);
+ mSlotConnectedDisplay = resources.getString(
+ com.android.internal.R.string.status_bar_connected_display);
mSlotHotspot = resources.getString(com.android.internal.R.string.status_bar_hotspot);
mSlotBluetooth = resources.getString(com.android.internal.R.string.status_bar_bluetooth);
mSlotTty = resources.getString(com.android.internal.R.string.status_bar_tty);
@@ -285,6 +297,10 @@
mIconController.setIcon(mSlotCast, R.drawable.stat_sys_cast, null);
mIconController.setIconVisibility(mSlotCast, false);
+ // connected display
+ mIconController.setIcon(mSlotConnectedDisplay, R.drawable.stat_sys_connected_display, null);
+ mIconController.setIconVisibility(mSlotConnectedDisplay, false);
+
// hotspot
mIconController.setIcon(mSlotHotspot, R.drawable.stat_sys_hotspot,
mResources.getString(R.string.accessibility_status_bar_hotspot));
@@ -342,6 +358,8 @@
mSensorPrivacyController.addCallback(mSensorPrivacyListener);
mLocationController.addCallback(this);
mRecordingController.addCallback(this);
+ mJavaAdapter.alwaysCollectFlow(mConnectedDisplayInteractor.getConnectedDisplayState(),
+ this::onConnectedDisplayAvailabilityChanged);
mCommandQueue.addCallback(this);
}
@@ -800,4 +818,14 @@
if (DEBUG) Log.d(TAG, "screenrecord: hiding icon");
mHandler.post(() -> mIconController.setIconVisibility(mSlotScreenRecord, false));
}
+
+ private void onConnectedDisplayAvailabilityChanged(ConnectedDisplayInteractor.State state) {
+ boolean visible = state != ConnectedDisplayInteractor.State.DISCONNECTED;
+
+ if (DEBUG) {
+ Log.d(TAG, "connected_display: " + (visible ? "showing" : "hiding") + " icon");
+ }
+
+ mIconController.setIconVisibility(mSlotConnectedDisplay, visible);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 47c4023..c16e13c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -1476,10 +1476,6 @@
}
}
- public void setCurrentUser(int currentUser) {
- // Don't care in the base class.
- }
-
private void updateThemeColors() {
if (mScrimBehind == null) return;
int background = Utils.getColorAttr(mScrimBehind.getContext(),
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 e63875b..cb2a78d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -703,7 +703,7 @@
@Override
public void reset(boolean hideBouncerWhenShowing) {
- if (mKeyguardStateController.isShowing()) {
+ if (mKeyguardStateController.isShowing() && !bouncerIsAnimatingAway()) {
final boolean isOccluded = mKeyguardStateController.isOccluded();
// Hide quick settings.
mShadeViewController.resetViews(/* animate= */ !isOccluded);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterLogger.kt
index 12f023b..d07378e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterLogger.kt
@@ -19,10 +19,10 @@
import android.app.PendingIntent
import com.android.systemui.log.dagger.NotifInteractionLog
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel.DEBUG
-import com.android.systemui.log.LogLevel.ERROR
-import com.android.systemui.log.LogLevel.INFO
-import com.android.systemui.log.LogLevel.WARNING
+import com.android.systemui.log.core.LogLevel.DEBUG
+import com.android.systemui.log.core.LogLevel.ERROR
+import com.android.systemui.log.core.LogLevel.INFO
+import com.android.systemui.log.core.LogLevel.WARNING
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.logKey
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
index c332280..604b1f5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
@@ -64,6 +64,7 @@
private boolean mNeedsUnderflow;
// Individual StatusBarIconViews draw their etc dots centered in this width
private int mIconDotFrameWidth;
+ private boolean mQsExpansionTransitioning;
private boolean mShouldRestrictIcons = true;
// Used to count which states want to be visible during layout
private ArrayList<StatusIconState> mLayoutStates = new ArrayList<>();
@@ -87,6 +88,10 @@
super.onFinishInflate();
}
+ public void setQsExpansionTransitioning(boolean expansionTransitioning) {
+ mQsExpansionTransitioning = expansionTransitioning;
+ }
+
public void setShouldRestrictIcons(boolean should) {
mShouldRestrictIcons = should;
}
@@ -386,6 +391,7 @@
StatusIconState vs = getViewStateFromChild(child);
if (vs != null) {
vs.applyToView(child);
+ vs.qsExpansionTransitioning = mQsExpansionTransitioning;
}
}
}
@@ -420,6 +426,7 @@
/// StatusBarIconView.STATE_*
public int visibleState = STATE_ICON;
public boolean justAdded = true;
+ public boolean qsExpansionTransitioning = false;
// How far we are from the end of the view actually is the most relevant for animation
float distanceToViewEnd = -1;
@@ -462,12 +469,13 @@
}
icon.setVisibleState(visibleState, animateVisibility);
- if (animationProperties != null) {
+ if (animationProperties != null && !qsExpansionTransitioning) {
animateTo(view, animationProperties);
} else {
super.applyToView(view);
}
+ qsExpansionTransitioning = false;
justAdded = false;
distanceToViewEnd = currentDistanceToEnd;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java
index c618be8..4ae460a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java
@@ -21,10 +21,8 @@
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import com.android.systemui.scene.ui.view.WindowRootView;
-import com.android.systemui.shade.NotificationPanelViewController;
import com.android.systemui.shade.NotificationShadeWindowView;
import com.android.systemui.shade.NotificationShadeWindowViewController;
-import com.android.systemui.shade.QuickSettingsController;
import com.android.systemui.shade.ShadeHeaderController;
import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
@@ -89,14 +87,6 @@
NotificationShadeWindowViewController getNotificationShadeWindowViewController();
/**
- * Creates a NotificationPanelViewController.
- */
- NotificationPanelViewController getNotificationPanelViewController();
-
- /** Creates a QuickSettingsController. */
- QuickSettingsController getQuickSettingsController();
-
- /**
* Creates a StatusBarHeadsUpChangeListener.
*/
StatusBarHeadsUpChangeListener getStatusBarHeadsUpChangeListener();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
index 6b0746f..77381dd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
@@ -16,22 +16,16 @@
package com.android.systemui.statusbar.phone.dagger;
-import android.view.LayoutInflater;
-
import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.shade.NotificationPanelView;
-import com.android.systemui.shade.NotificationPanelViewController;
import com.android.systemui.shade.ShadeExpansionStateManager;
import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.OperatorNameViewController;
import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
-import com.android.systemui.statusbar.phone.KeyguardBottomAreaView;
import com.android.systemui.statusbar.phone.NotificationIconAreaController;
import com.android.systemui.statusbar.phone.StatusBarBoundsProvider;
import com.android.systemui.statusbar.phone.StatusBarHideIconsForBouncerManager;
@@ -70,12 +64,6 @@
public static final String STATUS_BAR_FRAGMENT = "status_bar_fragment";
- /** */
- @Binds
- @CentralSurfacesComponent.CentralSurfacesScope
- abstract ShadeViewController bindsShadeViewController(
- NotificationPanelViewController notificationPanelViewController);
-
@Binds
@IntoSet
abstract StatusBarBoundsProvider.BoundsChangeListener sysBarAttrsListenerAsBoundsListener(
@@ -145,17 +133,4 @@
statusBarWindowStateController,
keyguardUpdateMonitor);
}
-
- /**
- * Constructs a new, unattached {@link KeyguardBottomAreaView}.
- *
- * Note that this is explicitly _not_ a singleton, as we want to be able to reinflate it
- */
- @Provides
- public static KeyguardBottomAreaView providesKeyguardBottomAreaView(
- NotificationPanelView npv, LayoutInflater layoutInflater) {
- return (KeyguardBottomAreaView) layoutInflater.inflate(R
- .layout.keyguard_bottom_area, npv, false);
- }
-
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
index fcae23b..0d58079 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
@@ -14,9 +14,6 @@
package com.android.systemui.statusbar.phone.fragment;
-import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.IDLE;
-import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.SHOWING_PERSISTENT_DOT;
-
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.app.Fragment;
@@ -39,6 +36,7 @@
import androidx.core.animation.Animator;
import com.android.app.animation.Interpolators;
+import com.android.app.animation.InterpolatorsAndroidX;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
@@ -77,6 +75,8 @@
import com.android.systemui.util.CarrierConfigTracker.DefaultDataSubscriptionChangedListener;
import com.android.systemui.util.settings.SecureSettings;
+import kotlin.Unit;
+
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
@@ -99,12 +99,16 @@
private static final String EXTRA_PANEL_STATE = "panel_state";
public static final String STATUS_BAR_ICON_MANAGER_TAG = "status_bar_icon_manager";
public static final int FADE_IN_DURATION = 320;
+ public static final int FADE_OUT_DURATION = 160;
public static final int FADE_IN_DELAY = 50;
+ private static final int SOURCE_SYSTEM_EVENT_ANIMATOR = 1;
+ private static final int SOURCE_OTHER = 2;
private StatusBarFragmentComponent mStatusBarFragmentComponent;
private PhoneStatusBarView mStatusBar;
private final StatusBarStateController mStatusBarStateController;
private final KeyguardStateController mKeyguardStateController;
private final ShadeViewController mShadeViewController;
+ private MultiSourceMinAlphaController mEndSideAlphaController;
private LinearLayout mEndSideContent;
private View mClockView;
private View mOngoingCallChip;
@@ -149,7 +153,7 @@
}
};
private OperatorNameViewController mOperatorNameViewController;
- private StatusBarSystemEventAnimator mSystemEventAnimator;
+ private StatusBarSystemEventDefaultAnimator mSystemEventAnimator;
private final CarrierConfigChangedListener mCarrierConfigCallback =
new CarrierConfigChangedListener() {
@@ -297,14 +301,14 @@
updateBlockedIcons();
mStatusBarIconController.addIconGroup(mDarkIconManager);
mEndSideContent = mStatusBar.findViewById(R.id.status_bar_end_side_content);
+ mEndSideAlphaController = new MultiSourceMinAlphaController(mEndSideContent);
mClockView = mStatusBar.findViewById(R.id.clock);
mOngoingCallChip = mStatusBar.findViewById(R.id.ongoing_call_chip);
showEndSideContent(false);
showClock(false);
initOperatorName();
initNotificationIconArea();
- mSystemEventAnimator =
- new StatusBarSystemEventAnimator(mEndSideContent, getResources());
+ mSystemEventAnimator = getSystemEventAnimator();
mCarrierConfigTracker.addCallback(mCarrierConfigCallback);
mCarrierConfigTracker.addDefaultDataSubscriptionChangedListener(mDefaultDataListener);
@@ -593,18 +597,27 @@
}
private void hideEndSideContent(boolean animate) {
- animateHide(mEndSideContent, animate);
+ if (!animate) {
+ mEndSideAlphaController.setAlpha(/*alpha*/ 0f, SOURCE_OTHER);
+ } else {
+ mEndSideAlphaController.animateToAlpha(/*alpha*/ 0f, SOURCE_OTHER, FADE_OUT_DURATION,
+ InterpolatorsAndroidX.ALPHA_OUT, /*startDelay*/ 0);
+ }
}
private void showEndSideContent(boolean animate) {
- // Only show the system icon area if we are not currently animating
- int state = mAnimationScheduler.getAnimationState();
- if (state == IDLE || state == SHOWING_PERSISTENT_DOT) {
- animateShow(mEndSideContent, animate);
+ if (!animate) {
+ mEndSideAlphaController.setAlpha(1f, SOURCE_OTHER);
+ return;
+ }
+ if (mKeyguardStateController.isKeyguardFadingAway()) {
+ mEndSideAlphaController.animateToAlpha(/*alpha*/ 1f, SOURCE_OTHER,
+ mKeyguardStateController.getKeyguardFadingAwayDuration(),
+ InterpolatorsAndroidX.LINEAR_OUT_SLOW_IN,
+ mKeyguardStateController.getKeyguardFadingAwayDelay());
} else {
- // We are in the middle of a system status event animation, which will animate the
- // alpha (but not the visibility). Allow the view to become visible again
- mEndSideContent.setVisibility(View.VISIBLE);
+ mEndSideAlphaController.animateToAlpha(/*alpha*/ 1f, SOURCE_OTHER, FADE_IN_DURATION,
+ InterpolatorsAndroidX.ALPHA_IN, FADE_IN_DELAY);
}
}
@@ -671,7 +684,7 @@
v.animate()
.alpha(0f)
- .setDuration(160)
+ .setDuration(FADE_OUT_DURATION)
.setStartDelay(0)
.setInterpolator(Interpolators.ALPHA_OUT)
.withEndAction(() -> v.setVisibility(state));
@@ -754,6 +767,16 @@
return mSystemEventAnimator.onSystemEventAnimationFinish(hasPersistentDot);
}
+ private StatusBarSystemEventDefaultAnimator getSystemEventAnimator() {
+ return new StatusBarSystemEventDefaultAnimator(getResources(), (alpha) -> {
+ mEndSideAlphaController.setAlpha(alpha, SOURCE_SYSTEM_EVENT_ANIMATOR);
+ return Unit.INSTANCE;
+ }, (translationX) -> {
+ mEndSideContent.setTranslationX(translationX);
+ return Unit.INSTANCE;
+ }, /*isAnimationRunning*/ false);
+ }
+
private void updateStatusBarLocation(int left, int right) {
int leftMargin = left - mStatusBar.getLeft();
int rightMargin = mStatusBar.getRight() - right;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLogger.kt
index f4ab408..7cdb9c0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLogger.kt
@@ -18,7 +18,7 @@
import com.android.systemui.log.dagger.CollapsedSbFragmentLog
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.log.core.LogLevel
import com.android.systemui.statusbar.disableflags.DisableFlagsLogger
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/MultiSourceMinAlphaController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/MultiSourceMinAlphaController.kt
new file mode 100644
index 0000000..c8836e4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/MultiSourceMinAlphaController.kt
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone.fragment
+
+import android.view.View
+import androidx.core.animation.Interpolator
+import androidx.core.animation.ValueAnimator
+import com.android.app.animation.InterpolatorsAndroidX
+
+/**
+ * A controller that keeps track of multiple sources applying alpha value changes to a view. It will
+ * always apply the minimum alpha value of all sources.
+ */
+internal class MultiSourceMinAlphaController
+@JvmOverloads
+constructor(private val view: View, private val initialAlpha: Float = 1f) {
+
+ private val alphas = mutableMapOf<Int, Float>()
+ private val animators = mutableMapOf<Int, ValueAnimator>()
+
+ /**
+ * Sets the alpha of the provided source and applies it to the view (if no other source has set
+ * a lower alpha currently). If an animator of the same source is still running (i.e.
+ * [animateToAlpha] was called before), that animator is cancelled.
+ */
+ fun setAlpha(alpha: Float, sourceId: Int) {
+ animators[sourceId]?.cancel()
+ updateAlpha(alpha, sourceId)
+ }
+
+ /** Animates to the alpha of the provided source. */
+ fun animateToAlpha(
+ alpha: Float,
+ sourceId: Int,
+ duration: Long,
+ interpolator: Interpolator = InterpolatorsAndroidX.ALPHA_IN,
+ startDelay: Long = 0
+ ) {
+ animators[sourceId]?.cancel()
+ val animator = ValueAnimator.ofFloat(getMinAlpha(), alpha)
+ animator.duration = duration
+ animator.startDelay = startDelay
+ animator.interpolator = interpolator
+ animator.addUpdateListener { updateAlpha(animator.animatedValue as Float, sourceId) }
+ animator.start()
+ animators[sourceId] = animator
+ }
+
+ fun reset() {
+ alphas.clear()
+ animators.forEach { it.value.cancel() }
+ animators.clear()
+ applyAlphaToView()
+ }
+
+ private fun updateAlpha(alpha: Float, sourceId: Int) {
+ alphas[sourceId] = alpha
+ applyAlphaToView()
+ }
+
+ private fun applyAlphaToView() {
+ val minAlpha = getMinAlpha()
+ view.visibility = if (minAlpha != 0f) View.VISIBLE else View.INVISIBLE
+ view.alpha = minAlpha
+ }
+
+ private fun getMinAlpha() = alphas.minOfOrNull { it.value } ?: initialAlpha
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/MobileInputLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/MobileInputLogger.kt
index b3a1c40..051e88f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/MobileInputLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/MobileInputLogger.kt
@@ -23,7 +23,7 @@
import com.android.settingslib.mobile.MobileMappings
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.log.core.LogLevel
import com.android.systemui.statusbar.pipeline.dagger.MobileInputLog
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLogger.kt
index 7e0c145..cea6654 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLogger.kt
@@ -21,7 +21,7 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dump.DumpManager
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.log.core.LogLevel
import com.android.systemui.statusbar.pipeline.dagger.MobileViewLog
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.LocationBasedMobileViewModel
import java.io.PrintWriter
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/VerboseMobileViewLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/VerboseMobileViewLogger.kt
index 507549b..f4c5723 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/VerboseMobileViewLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/VerboseMobileViewLogger.kt
@@ -20,7 +20,7 @@
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.log.core.LogLevel
import com.android.systemui.statusbar.pipeline.dagger.VerboseMobileViewLog
import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger.Companion.getIdForLogging
import com.android.systemui.statusbar.pipeline.mobile.ui.model.SignalIconModel
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityInputLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityInputLogger.kt
index cac0ae3..8a4d14e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityInputLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityInputLogger.kt
@@ -20,7 +20,7 @@
import android.net.NetworkCapabilities
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.log.core.LogLevel
import com.android.systemui.statusbar.pipeline.dagger.SharedConnectivityInputLog
import com.android.systemui.statusbar.pipeline.shared.data.model.DefaultConnectionModel
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/LoggerHelper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/LoggerHelper.kt
index 328d901..4b9de85 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/LoggerHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/LoggerHelper.kt
@@ -19,7 +19,7 @@
import android.net.Network
import android.net.NetworkCapabilities
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.log.core.LogLevel
/** Helper object for logs that are shared between wifi and mobile. */
object LoggerHelper {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/model/DefaultConnectionModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/model/DefaultConnectionModel.kt
index 058eda4..9a504c9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/model/DefaultConnectionModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/data/model/DefaultConnectionModel.kt
@@ -17,7 +17,7 @@
package com.android.systemui.statusbar.pipeline.shared.data.model
import android.net.NetworkCapabilities
-import com.android.systemui.log.LogMessage
+import com.android.systemui.log.core.LogMessage
/**
* A model for all of the current default connections(s).
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiInputLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiInputLogger.kt
index 4a9ceac..f244376 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiInputLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiInputLogger.kt
@@ -20,7 +20,7 @@
import android.net.NetworkCapabilities
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.log.core.LogLevel
import com.android.systemui.statusbar.pipeline.dagger.WifiInputLog
import com.android.systemui.statusbar.pipeline.shared.LoggerHelper
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerLogger.kt
index 6ba2a81..096ad1f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerLogger.kt
@@ -22,7 +22,7 @@
import android.provider.Settings.Secure.DEVICE_STATE_ROTATION_LOCK_UNLOCKED
import com.android.internal.R
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel.VERBOSE
+import com.android.systemui.log.core.LogLevel.VERBOSE
import com.android.systemui.log.dagger.DeviceStateAutoRotationLog
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerLogger.kt
index 06ed1fd..175473f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerLogger.kt
@@ -18,8 +18,8 @@
import com.android.systemui.log.dagger.NotificationHeadsUpLog
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel.INFO
-import com.android.systemui.log.LogLevel.VERBOSE
+import com.android.systemui.log.core.LogLevel.INFO
+import com.android.systemui.log.core.LogLevel.VERBOSE
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.logKey
import javax.inject.Inject
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 a82646a..710588c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.policy;
+import static android.hardware.biometrics.BiometricSourceType.FACE;
+
import android.annotation.NonNull;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -199,6 +201,11 @@
Trace.endSection();
}
+ private void notifyKeyguardFaceAuthEnabledChanged() {
+ // Copy the list to allow removal during callback.
+ new ArrayList<>(mCallbacks).forEach(Callback::onFaceAuthEnabledChanged);
+ }
+
private void notifyUnlockedChanged() {
Trace.beginSection("KeyguardStateController#notifyUnlockedChanged");
// Copy the list to allow removal during callback.
@@ -419,6 +426,16 @@
}
@Override
+ public void onBiometricEnrollmentStateChanged(BiometricSourceType biometricSourceType) {
+ if (biometricSourceType == FACE) {
+ // We only care about enrollment state here. Keyguard face auth enabled is just
+ // same as face auth enrolled
+ update(false);
+ notifyKeyguardFaceAuthEnabledChanged();
+ }
+ }
+
+ @Override
public void onStartedWakingUp() {
update(false /* updateAlways */);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyStateInflater.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyStateInflater.kt
index 21d0338..cac5e32 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyStateInflater.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyStateInflater.kt
@@ -22,6 +22,13 @@
import android.app.RemoteInput
import android.content.Context
import android.content.Intent
+import android.graphics.Bitmap
+import android.graphics.ImageDecoder
+import android.graphics.drawable.AdaptiveIconDrawable
+import android.graphics.drawable.BitmapDrawable
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.GradientDrawable
+import android.graphics.drawable.Icon
import android.os.Build
import android.os.Bundle
import android.os.SystemClock
@@ -48,7 +55,13 @@
import com.android.systemui.statusbar.policy.SmartReplyView.SmartActions
import com.android.systemui.statusbar.policy.SmartReplyView.SmartButtonType
import com.android.systemui.statusbar.policy.SmartReplyView.SmartReplies
+import java.util.concurrent.FutureTask
+import java.util.concurrent.SynchronousQueue
+import java.util.concurrent.ThreadPoolExecutor
+import java.util.concurrent.TimeUnit
import javax.inject.Inject
+import kotlin.system.measureTimeMillis
+
/** Returns whether we should show the smart reply view and its smart suggestions. */
fun shouldShowSmartReplyView(
@@ -281,6 +294,51 @@
): Button
}
+private const val ICON_TASK_TIMEOUT_MS = 500L
+private val iconTaskThreadPool = ThreadPoolExecutor(0, 25, 1, TimeUnit.MINUTES, SynchronousQueue())
+
+private fun loadIconDrawableWithTimeout(
+ icon: Icon,
+ packageContext: Context,
+ targetSize: Int,
+): Drawable? {
+ if (icon.type != Icon.TYPE_URI && icon.type != Icon.TYPE_URI_ADAPTIVE_BITMAP) {
+ return icon.loadDrawable(packageContext)
+ }
+ val bitmapTask = FutureTask {
+ val bitmap: Bitmap?
+ val durationMillis = measureTimeMillis {
+ val source = ImageDecoder.createSource(packageContext.contentResolver, icon.uri)
+ bitmap = ImageDecoder.decodeBitmap(source) { decoder, _, _ ->
+ decoder.setTargetSize(targetSize, targetSize)
+ decoder.allocator = ImageDecoder.ALLOCATOR_DEFAULT
+ }
+ }
+ if (durationMillis > ICON_TASK_TIMEOUT_MS) {
+ Log.w(TAG, "Loading $icon took ${durationMillis / 1000f} sec")
+ }
+ checkNotNull(bitmap) { "ImageDecoder.decodeBitmap() returned null" }
+ }
+ val bitmap = runCatching {
+ iconTaskThreadPool.execute(bitmapTask)
+ bitmapTask.get(ICON_TASK_TIMEOUT_MS, TimeUnit.MILLISECONDS)
+ }.getOrElse { ex ->
+ Log.e(TAG, "Failed to load $icon: $ex")
+ bitmapTask.cancel(true)
+ return null
+ }
+ // TODO(b/288561520): rewrite Icon so that we don't need to duplicate this logic
+ val bitmapDrawable = BitmapDrawable(packageContext.resources, bitmap)
+ val result = if (icon.type == Icon.TYPE_URI_ADAPTIVE_BITMAP)
+ AdaptiveIconDrawable(null, bitmapDrawable) else bitmapDrawable
+ if (icon.hasTint()) {
+ result.mutate()
+ result.setTintList(icon.tintList)
+ result.setTintBlendMode(icon.tintBlendMode)
+ }
+ return result
+}
+
/* internal */ class SmartActionInflaterImpl @Inject constructor(
private val constants: SmartReplyConstants,
private val activityStarter: ActivityStarter,
@@ -304,12 +362,12 @@
// We received the Icon from the application - so use the Context of the application to
// reference icon resources.
- val iconDrawable = action.getIcon().loadDrawable(packageContext)
- .apply {
- val newIconSize: Int = context.resources.getDimensionPixelSize(
- R.dimen.smart_action_button_icon_size)
- setBounds(0, 0, newIconSize, newIconSize)
- }
+ val newIconSize = context.resources
+ .getDimensionPixelSize(R.dimen.smart_action_button_icon_size)
+ val iconDrawable =
+ loadIconDrawableWithTimeout(action.getIcon(), packageContext, newIconSize)
+ ?: GradientDrawable()
+ iconDrawable.setBounds(0, 0, newIconSize, newIconSize)
// Add the action icon to the Smart Action button.
setCompoundDrawablesRelative(iconDrawable, null, null, null)
diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewLogger.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewLogger.kt
index 066ac04..a9d2029 100644
--- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewLogger.kt
@@ -18,7 +18,7 @@
import android.view.View
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.log.core.LogLevel
/** A logger for temporary view changes -- see [TemporaryViewDisplayController]. */
open class TemporaryViewLogger<T : TemporaryViewInfo>(
diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarLogger.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarLogger.kt
index d55751b..6706873 100644
--- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarLogger.kt
@@ -18,7 +18,7 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.log.core.LogLevel
import com.android.systemui.temporarydisplay.TemporaryViewLogger
import com.android.systemui.temporarydisplay.dagger.ChipbarLog
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/toast/ToastLogger.kt b/packages/SystemUI/src/com/android/systemui/toast/ToastLogger.kt
index dfe748a..c109eb4 100644
--- a/packages/SystemUI/src/com/android/systemui/toast/ToastLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/toast/ToastLogger.kt
@@ -18,9 +18,9 @@
import com.android.systemui.log.dagger.ToastLog
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
-import com.android.systemui.log.LogLevel.DEBUG
-import com.android.systemui.log.LogMessage
+import com.android.systemui.log.core.LogLevel
+import com.android.systemui.log.core.LogLevel.DEBUG
+import com.android.systemui.log.core.LogMessage
import javax.inject.Inject
private const val TAG = "ToastLog"
diff --git a/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLockLogger.kt b/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLockLogger.kt
index 0926800..d69b10f 100644
--- a/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLockLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLockLogger.kt
@@ -18,7 +18,7 @@
import android.os.PowerManager
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.log.core.LogLevel
import javax.inject.Inject
class WakeLockLogger @Inject constructor(@WakeLockLog private val buffer: LogBuffer) {
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index 4c7e6b0..5144d19 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -334,10 +334,8 @@
}
@Override
- public void setImeWindowStatus(int displayId, IBinder token,
- @InputMethodService.ImeWindowVisibility int vis,
- @InputMethodService.BackDispositionMode int backDisposition,
- boolean showImeSwitcher) {
+ public void setImeWindowStatus(int displayId, IBinder token, int vis,
+ int backDisposition, boolean showImeSwitcher) {
if (displayId == mDisplayTracker.getDefaultDisplayId()
&& (vis & InputMethodService.IME_VISIBLE) != 0) {
oneHanded.stopOneHanded(
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt
index d3b4190..5a56baf 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt
@@ -97,21 +97,7 @@
`when`(keyguardPinView.findViewById<NumPadButton>(R.id.delete_button))
.thenReturn(deleteButton)
`when`(keyguardPinView.findViewById<View>(R.id.key_enter)).thenReturn(enterButton)
- pinViewController =
- KeyguardPinViewController(
- keyguardPinView,
- keyguardUpdateMonitor,
- securityMode,
- lockPatternUtils,
- mKeyguardSecurityCallback,
- keyguardMessageAreaControllerFactory,
- mLatencyTracker,
- liftToActivateListener,
- mEmergencyButtonController,
- falsingCollector,
- postureController,
- featureFlags
- )
+ constructViewController()
}
@Test
@@ -135,8 +121,10 @@
`when`(lockPatternUtils.isAutoPinConfirmEnabled(anyInt())).thenReturn(true)
`when`(lockPatternUtils.getCurrentFailedPasswordAttempts(anyInt())).thenReturn(3)
`when`(passwordTextView.text).thenReturn("")
+ constructViewController()
pinViewController.startAppearAnimation()
+
verify(deleteButton).visibility = View.INVISIBLE
verify(enterButton).visibility = View.INVISIBLE
verify(passwordTextView).setUsePinShapes(true)
@@ -150,8 +138,10 @@
`when`(lockPatternUtils.isAutoPinConfirmEnabled(anyInt())).thenReturn(true)
`when`(lockPatternUtils.getCurrentFailedPasswordAttempts(anyInt())).thenReturn(6)
`when`(passwordTextView.text).thenReturn("")
+ constructViewController()
pinViewController.startAppearAnimation()
+
verify(deleteButton).visibility = View.VISIBLE
verify(enterButton).visibility = View.VISIBLE
verify(passwordTextView).setUsePinShapes(true)
@@ -163,4 +153,22 @@
pinViewController.handleAttemptLockout(0)
verify(lockPatternUtils).getCurrentFailedPasswordAttempts(anyInt())
}
+
+ fun constructViewController() {
+ pinViewController =
+ KeyguardPinViewController(
+ keyguardPinView,
+ keyguardUpdateMonitor,
+ securityMode,
+ lockPatternUtils,
+ mKeyguardSecurityCallback,
+ keyguardMessageAreaControllerFactory,
+ mLatencyTracker,
+ liftToActivateListener,
+ mEmergencyButtonController,
+ falsingCollector,
+ postureController,
+ featureFlags
+ )
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 901c3fb..4263091 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -83,6 +83,7 @@
import android.content.pm.UserInfo;
import android.database.ContentObserver;
import android.hardware.SensorPrivacyManager;
+import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricSourceType;
@@ -3000,6 +3001,24 @@
TelephonyManager.SIM_STATE_UNKNOWN);
}
+ @Test
+ public void onAuthEnrollmentChangesCallbacksAreNotified() {
+ KeyguardUpdateMonitorCallback callback = mock(KeyguardUpdateMonitorCallback.class);
+ ArgumentCaptor<AuthController.Callback> authCallback = ArgumentCaptor.forClass(
+ AuthController.Callback.class);
+ verify(mAuthController).addCallback(authCallback.capture());
+
+ mKeyguardUpdateMonitor.registerCallback(callback);
+
+ authCallback.getValue().onEnrollmentsChanged(TYPE_FINGERPRINT);
+ mTestableLooper.processAllMessages();
+ verify(callback).onBiometricEnrollmentStateChanged(BiometricSourceType.FINGERPRINT);
+
+ authCallback.getValue().onEnrollmentsChanged(BiometricAuthenticator.TYPE_FACE);
+ mTestableLooper.processAllMessages();
+ verify(callback).onBiometricEnrollmentStateChanged(BiometricSourceType.FACE);
+ }
+
private void verifyFingerprintAuthenticateNeverCalled() {
verify(mFingerprintManager, never()).authenticate(any(), any(), any(), any(), any());
verify(mFingerprintManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt
index ac2d492..ea3289c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt
@@ -25,7 +25,6 @@
import com.android.systemui.scene.SceneTestUtils
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Test
@@ -37,8 +36,8 @@
@RunWith(JUnit4::class)
class AuthenticationInteractorTest : SysuiTestCase() {
- private val testScope = TestScope()
- private val utils = SceneTestUtils(this, testScope)
+ private val utils = SceneTestUtils(this)
+ private val testScope = utils.testScope
private val repository: AuthenticationRepository = utils.authenticationRepository()
private val underTest =
utils.authenticationInteractor(
@@ -46,47 +45,23 @@
)
@Test
- fun authMethod() =
+ fun getAuthenticationMethod() =
testScope.runTest {
- val authMethod by collectLastValue(underTest.authenticationMethod)
- assertThat(authMethod).isEqualTo(AuthenticationMethodModel.Pin(1234))
+ assertThat(underTest.getAuthenticationMethod())
+ .isEqualTo(AuthenticationMethodModel.Pin(1234))
- underTest.setAuthenticationMethod(AuthenticationMethodModel.Password("password"))
- assertThat(authMethod).isEqualTo(AuthenticationMethodModel.Password("password"))
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Password("password")
+ )
+ assertThat(underTest.getAuthenticationMethod())
+ .isEqualTo(AuthenticationMethodModel.Password("password"))
}
@Test
fun isUnlocked_whenAuthMethodIsNone_isTrue() =
testScope.runTest {
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.None)
val isUnlocked by collectLastValue(underTest.isUnlocked)
- assertThat(isUnlocked).isFalse()
-
- underTest.setAuthenticationMethod(AuthenticationMethodModel.None)
-
- assertThat(isUnlocked).isTrue()
- }
-
- @Test
- fun unlockDevice() =
- testScope.runTest {
- val isUnlocked by collectLastValue(underTest.isUnlocked)
- assertThat(isUnlocked).isFalse()
-
- underTest.unlockDevice()
- runCurrent()
-
- assertThat(isUnlocked).isTrue()
- }
-
- @Test
- fun biometricUnlock() =
- testScope.runTest {
- val isUnlocked by collectLastValue(underTest.isUnlocked)
- assertThat(isUnlocked).isFalse()
-
- underTest.biometricUnlock()
- runCurrent()
-
assertThat(isUnlocked).isTrue()
}
@@ -106,9 +81,11 @@
@Test
fun isAuthenticationRequired_lockedAndSecured_true() =
testScope.runTest {
- underTest.lockDevice()
+ utils.authenticationRepository.setUnlocked(false)
runCurrent()
- underTest.setAuthenticationMethod(AuthenticationMethodModel.Password("password"))
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Password("password")
+ )
assertThat(underTest.isAuthenticationRequired()).isTrue()
}
@@ -116,9 +93,9 @@
@Test
fun isAuthenticationRequired_lockedAndNotSecured_false() =
testScope.runTest {
- underTest.lockDevice()
+ utils.authenticationRepository.setUnlocked(false)
runCurrent()
- underTest.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
assertThat(underTest.isAuthenticationRequired()).isFalse()
}
@@ -126,9 +103,11 @@
@Test
fun isAuthenticationRequired_unlockedAndSecured_false() =
testScope.runTest {
- underTest.unlockDevice()
+ utils.authenticationRepository.setUnlocked(true)
runCurrent()
- underTest.setAuthenticationMethod(AuthenticationMethodModel.Password("password"))
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Password("password")
+ )
assertThat(underTest.isAuthenticationRequired()).isFalse()
}
@@ -136,67 +115,63 @@
@Test
fun isAuthenticationRequired_unlockedAndNotSecured_false() =
testScope.runTest {
- underTest.unlockDevice()
+ utils.authenticationRepository.setUnlocked(true)
runCurrent()
- underTest.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
assertThat(underTest.isAuthenticationRequired()).isFalse()
}
@Test
- fun authenticate_withCorrectPin_returnsTrueAndUnlocksDevice() =
+ fun authenticate_withCorrectPin_returnsTrue() =
testScope.runTest {
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
- val isUnlocked by collectLastValue(underTest.isUnlocked)
- underTest.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
- assertThat(isUnlocked).isFalse()
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
assertThat(underTest.authenticate(listOf(1, 2, 3, 4))).isTrue()
- assertThat(isUnlocked).isTrue()
assertThat(failedAttemptCount).isEqualTo(0)
}
@Test
- fun authenticate_withIncorrectPin_returnsFalseAndDoesNotUnlockDevice() =
+ fun authenticate_withIncorrectPin_returnsFalse() =
testScope.runTest {
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
- val isUnlocked by collectLastValue(underTest.isUnlocked)
- underTest.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
- assertThat(isUnlocked).isFalse()
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
assertThat(underTest.authenticate(listOf(9, 8, 7))).isFalse()
- assertThat(isUnlocked).isFalse()
assertThat(failedAttemptCount).isEqualTo(1)
}
@Test
- fun authenticate_withEmptyPin_returnsFalseAndDoesNotUnlockDevice() =
+ fun authenticate_withEmptyPin_returnsFalse() =
testScope.runTest {
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
- val isUnlocked by collectLastValue(underTest.isUnlocked)
- underTest.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
- assertThat(isUnlocked).isFalse()
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
assertThat(underTest.authenticate(listOf())).isFalse()
- assertThat(isUnlocked).isFalse()
assertThat(failedAttemptCount).isEqualTo(1)
}
@Test
- fun authenticate_withCorrectMaxLengthPin_returnsTrueAndUnlocksDevice() =
+ fun authenticate_withCorrectMaxLengthPin_returnsTrue() =
testScope.runTest {
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
- val isUnlocked by collectLastValue(underTest.isUnlocked)
- underTest.setAuthenticationMethod(AuthenticationMethodModel.Pin(9999999999999999))
- assertThat(isUnlocked).isFalse()
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(9999999999999999)
+ )
assertThat(underTest.authenticate(List(16) { 9 })).isTrue()
- assertThat(isUnlocked).isTrue()
assertThat(failedAttemptCount).isEqualTo(0)
}
@Test
- fun authenticate_withCorrectTooLongPin_returnsFalseAndDoesNotUnlockDevice() =
+ fun authenticate_withCorrectTooLongPin_returnsFalse() =
testScope.runTest {
// Max pin length is 16 digits. To avoid issues with overflows, this test ensures
// that all pins > 16 decimal digits are rejected.
@@ -205,47 +180,43 @@
assertThat(DevicePolicyManager.MAX_PASSWORD_LENGTH).isLessThan(17)
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
- val isUnlocked by collectLastValue(underTest.isUnlocked)
- underTest.setAuthenticationMethod(AuthenticationMethodModel.Pin(99999999999999999))
- assertThat(isUnlocked).isFalse()
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(99999999999999999)
+ )
assertThat(underTest.authenticate(List(17) { 9 })).isFalse()
- assertThat(isUnlocked).isFalse()
assertThat(failedAttemptCount).isEqualTo(1)
}
@Test
- fun authenticate_withCorrectPassword_returnsTrueAndUnlocksDevice() =
+ fun authenticate_withCorrectPassword_returnsTrue() =
testScope.runTest {
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
- val isUnlocked by collectLastValue(underTest.isUnlocked)
- underTest.setAuthenticationMethod(AuthenticationMethodModel.Password("password"))
- assertThat(isUnlocked).isFalse()
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Password("password")
+ )
assertThat(underTest.authenticate("password".toList())).isTrue()
- assertThat(isUnlocked).isTrue()
assertThat(failedAttemptCount).isEqualTo(0)
}
@Test
- fun authenticate_withIncorrectPassword_returnsFalseAndDoesNotUnlockDevice() =
+ fun authenticate_withIncorrectPassword_returnsFalse() =
testScope.runTest {
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
- val isUnlocked by collectLastValue(underTest.isUnlocked)
- underTest.setAuthenticationMethod(AuthenticationMethodModel.Password("password"))
- assertThat(isUnlocked).isFalse()
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Password("password")
+ )
assertThat(underTest.authenticate("alohomora".toList())).isFalse()
- assertThat(isUnlocked).isFalse()
assertThat(failedAttemptCount).isEqualTo(1)
}
@Test
- fun authenticate_withCorrectPattern_returnsTrueAndUnlocksDevice() =
+ fun authenticate_withCorrectPattern_returnsTrue() =
testScope.runTest {
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
- val isUnlocked by collectLastValue(underTest.isUnlocked)
- underTest.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pattern(
listOf(
AuthenticationMethodModel.Pattern.PatternCoordinate(
@@ -263,7 +234,6 @@
)
)
)
- assertThat(isUnlocked).isFalse()
assertThat(
underTest.authenticate(
@@ -284,16 +254,14 @@
)
)
.isTrue()
- assertThat(isUnlocked).isTrue()
assertThat(failedAttemptCount).isEqualTo(0)
}
@Test
- fun authenticate_withIncorrectPattern_returnsFalseAndDoesNotUnlockDevice() =
+ fun authenticate_withIncorrectPattern_returnsFalse() =
testScope.runTest {
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
- val isUnlocked by collectLastValue(underTest.isUnlocked)
- underTest.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pattern(
listOf(
AuthenticationMethodModel.Pattern.PatternCoordinate(
@@ -311,7 +279,6 @@
)
)
)
- assertThat(isUnlocked).isFalse()
assertThat(
underTest.authenticate(
@@ -332,22 +299,18 @@
)
)
.isFalse()
- assertThat(isUnlocked).isFalse()
assertThat(failedAttemptCount).isEqualTo(1)
}
@Test
- fun tryAutoConfirm_withAutoConfirmPinAndEmptyInput_returnsNullAndHasNoEffect() =
+ fun tryAutoConfirm_withAutoConfirmPinAndEmptyInput_returnsNull() =
testScope.runTest {
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
- val isUnlocked by collectLastValue(underTest.isUnlocked)
- underTest.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234, autoConfirm = true)
)
- assertThat(isUnlocked).isFalse()
assertThat(underTest.authenticate(listOf(), tryAutoConfirm = true)).isNull()
- assertThat(isUnlocked).isFalse()
assertThat(failedAttemptCount).isEqualTo(0)
}
@@ -355,14 +318,11 @@
fun tryAutoConfirm_withAutoConfirmPinAndShorterPin_returnsNullAndHasNoEffect() =
testScope.runTest {
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
- val isUnlocked by collectLastValue(underTest.isUnlocked)
- underTest.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234, autoConfirm = true)
)
- assertThat(isUnlocked).isFalse()
assertThat(underTest.authenticate(listOf(1, 2, 3), tryAutoConfirm = true)).isNull()
- assertThat(isUnlocked).isFalse()
assertThat(failedAttemptCount).isEqualTo(0)
}
@@ -370,14 +330,11 @@
fun tryAutoConfirm_withAutoConfirmWrongPinCorrectLength_returnsFalseAndDoesNotUnlockDevice() =
testScope.runTest {
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
- val isUnlocked by collectLastValue(underTest.isUnlocked)
- underTest.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234, autoConfirm = true)
)
- assertThat(isUnlocked).isFalse()
assertThat(underTest.authenticate(listOf(1, 2, 4, 4), tryAutoConfirm = true)).isFalse()
- assertThat(isUnlocked).isFalse()
assertThat(failedAttemptCount).isEqualTo(1)
}
@@ -385,15 +342,12 @@
fun tryAutoConfirm_withAutoConfirmLongerPin_returnsFalseAndDoesNotUnlockDevice() =
testScope.runTest {
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
- val isUnlocked by collectLastValue(underTest.isUnlocked)
- underTest.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234, autoConfirm = true)
)
- assertThat(isUnlocked).isFalse()
assertThat(underTest.authenticate(listOf(1, 2, 3, 4, 5), tryAutoConfirm = true))
.isFalse()
- assertThat(isUnlocked).isFalse()
assertThat(failedAttemptCount).isEqualTo(1)
}
@@ -401,14 +355,11 @@
fun tryAutoConfirm_withAutoConfirmCorrectPin_returnsTrueAndUnlocksDevice() =
testScope.runTest {
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
- val isUnlocked by collectLastValue(underTest.isUnlocked)
- underTest.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234, autoConfirm = true)
)
- assertThat(isUnlocked).isFalse()
assertThat(underTest.authenticate(listOf(1, 2, 4, 4), tryAutoConfirm = true)).isFalse()
- assertThat(isUnlocked).isFalse()
assertThat(failedAttemptCount).isEqualTo(1)
}
@@ -416,14 +367,11 @@
fun tryAutoConfirm_withoutAutoConfirmButCorrectPin_returnsNullAndHasNoEffects() =
testScope.runTest {
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
- val isUnlocked by collectLastValue(underTest.isUnlocked)
- underTest.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234, autoConfirm = false)
)
- assertThat(isUnlocked).isFalse()
assertThat(underTest.authenticate(listOf(1, 2, 3, 4), tryAutoConfirm = true)).isNull()
- assertThat(isUnlocked).isFalse()
assertThat(failedAttemptCount).isEqualTo(0)
}
@@ -431,23 +379,11 @@
fun tryAutoConfirm_withoutCorrectPassword_returnsNullAndHasNoEffects() =
testScope.runTest {
val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
- val isUnlocked by collectLastValue(underTest.isUnlocked)
- underTest.setAuthenticationMethod(AuthenticationMethodModel.Password("password"))
- assertThat(isUnlocked).isFalse()
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Password("password")
+ )
assertThat(underTest.authenticate("password".toList(), tryAutoConfirm = true)).isNull()
- assertThat(isUnlocked).isFalse()
assertThat(failedAttemptCount).isEqualTo(0)
}
-
- @Test
- fun unlocksDevice_whenAuthMethodBecomesNone() =
- testScope.runTest {
- val isUnlocked by collectLastValue(underTest.isUnlocked)
- assertThat(isUnlocked).isFalse()
-
- repository.setAuthenticationMethod(AuthenticationMethodModel.None)
-
- assertThat(isUnlocked).isTrue()
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index 821c2cb..30e5447 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -1316,12 +1316,22 @@
// WHEN ACTION_DOWN is received
when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
processorResultDown);
- MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
- mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
+ MotionEvent event = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
+ mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
mBiometricExecutor.runAllReady();
- downEvent.recycle();
- // THEN the touch is pilfered
+ // WHEN ACTION_MOVE is received after
+ final TouchProcessorResult processorResultUnchanged =
+ new TouchProcessorResult.ProcessedTouch(
+ InteractionEvent.UNCHANGED, 1 /* pointerId */, touchData);
+ when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
+ processorResultUnchanged);
+ event.setAction(ACTION_MOVE);
+ mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
+ mBiometricExecutor.runAllReady();
+ event.recycle();
+
+ // THEN only pilfer once on the initial down
verify(mInputManager).pilferPointers(any());
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt
index 9483667..d09353b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt
@@ -26,7 +26,6 @@
import com.android.systemui.scene.shared.model.SceneModel
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.advanceTimeBy
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
@@ -40,8 +39,8 @@
@RunWith(JUnit4::class)
class BouncerInteractorTest : SysuiTestCase() {
- private val testScope = TestScope()
- private val utils = SceneTestUtils(this, testScope)
+ private val utils = SceneTestUtils(this)
+ private val testScope = utils.testScope
private val authenticationInteractor =
utils.authenticationInteractor(
repository = utils.authenticationRepository(),
@@ -69,8 +68,10 @@
val currentScene by collectLastValue(sceneInteractor.currentScene("container1"))
val message by collectLastValue(underTest.message)
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
- authenticationInteractor.lockDevice()
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
+ utils.authenticationRepository.setUnlocked(false)
underTest.showOrUnlockDevice("container1")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
assertThat(message).isEqualTo(MESSAGE_ENTER_YOUR_PIN)
@@ -100,10 +101,10 @@
val currentScene by collectLastValue(sceneInteractor.currentScene("container1"))
val message by collectLastValue(underTest.message)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234, autoConfirm = true)
)
- authenticationInteractor.lockDevice()
+ utils.authenticationRepository.setUnlocked(false)
underTest.showOrUnlockDevice("container1")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
assertThat(message).isEqualTo(MESSAGE_ENTER_YOUR_PIN)
@@ -130,10 +131,10 @@
val currentScene by collectLastValue(sceneInteractor.currentScene("container1"))
val message by collectLastValue(underTest.message)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234, autoConfirm = false)
)
- authenticationInteractor.lockDevice()
+ utils.authenticationRepository.setUnlocked(false)
underTest.showOrUnlockDevice("container1")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.clearMessage()
@@ -154,10 +155,10 @@
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene("container1"))
val message by collectLastValue(underTest.message)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password("password")
)
- authenticationInteractor.lockDevice()
+ utils.authenticationRepository.setUnlocked(false)
underTest.showOrUnlockDevice("container1")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
assertThat(message).isEqualTo(MESSAGE_ENTER_YOUR_PASSWORD)
@@ -186,10 +187,10 @@
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene("container1"))
val message by collectLastValue(underTest.message)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pattern(emptyList())
)
- authenticationInteractor.lockDevice()
+ utils.authenticationRepository.setUnlocked(false)
underTest.showOrUnlockDevice("container1")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
assertThat(message).isEqualTo(MESSAGE_ENTER_YOUR_PATTERN)
@@ -222,8 +223,10 @@
fun showOrUnlockDevice_notLocked_switchesToGoneScene() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene("container1"))
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
- authenticationInteractor.unlockDevice()
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
+ utils.authenticationRepository.setUnlocked(true)
runCurrent()
underTest.showOrUnlockDevice("container1")
@@ -235,8 +238,8 @@
fun showOrUnlockDevice_authMethodNotSecure_switchesToGoneScene() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene("container1"))
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
- authenticationInteractor.lockDevice()
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
+ utils.authenticationRepository.setUnlocked(false)
underTest.showOrUnlockDevice("container1")
@@ -248,10 +251,10 @@
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene("container1"))
val message by collectLastValue(underTest.message)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password("password")
)
- authenticationInteractor.lockDevice()
+ utils.authenticationRepository.setUnlocked(false)
val customMessage = "Hello there!"
underTest.showOrUnlockDevice("container1", customMessage)
@@ -265,11 +268,17 @@
testScope.runTest {
val throttling by collectLastValue(underTest.throttling)
val message by collectLastValue(underTest.message)
- val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
+ val currentScene by
+ collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
+ runCurrent()
+ underTest.showOrUnlockDevice(SceneTestUtils.CONTAINER_1)
+ runCurrent()
+ assertThat(currentScene?.key).isEqualTo(SceneKey.Bouncer)
assertThat(throttling).isNull()
- assertThat(message).isEqualTo("")
- assertThat(isUnlocked).isFalse()
+ assertThat(message).isEqualTo(MESSAGE_ENTER_YOUR_PIN)
repeat(BouncerInteractor.THROTTLE_EVERY) { times ->
// Wrong PIN.
assertThat(underTest.authenticate(listOf(6, 7, 8, 9))).isFalse()
@@ -280,9 +289,9 @@
assertThat(throttling).isNotNull()
assertTryAgainMessage(message, BouncerInteractor.THROTTLE_DURATION_SEC)
- // Correct PIN, but throttled, so doesn't unlock:
+ // Correct PIN, but throttled, so doesn't change away from the bouncer scene:
assertThat(underTest.authenticate(listOf(1, 2, 3, 4))).isFalse()
- assertThat(isUnlocked).isFalse()
+ assertThat(currentScene?.key).isEqualTo(SceneKey.Bouncer)
assertTryAgainMessage(message, BouncerInteractor.THROTTLE_DURATION_SEC)
throttling?.totalDurationSec?.let { seconds ->
@@ -296,11 +305,28 @@
}
assertThat(message).isEqualTo("")
assertThat(throttling).isNull()
- assertThat(isUnlocked).isFalse()
+ assertThat(currentScene?.key).isEqualTo(SceneKey.Bouncer)
- // Correct PIN and no longer throttled so unlocks:
+ // Correct PIN and no longer throttled so changes to the Gone scene:
assertThat(underTest.authenticate(listOf(1, 2, 3, 4))).isTrue()
- assertThat(isUnlocked).isTrue()
+ assertThat(currentScene?.key).isEqualTo(SceneKey.Gone)
+ }
+
+ @Test
+ fun switchesToGone_whenUnlocked() =
+ testScope.runTest {
+ utils.authenticationRepository.setUnlocked(false)
+ sceneInteractor.setCurrentScene(
+ SceneTestUtils.CONTAINER_1,
+ SceneModel(SceneKey.Bouncer)
+ )
+ val currentScene by
+ collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
+ assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
+
+ utils.authenticationRepository.setUnlocked(true)
+
+ assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone))
}
private fun assertTryAgainMessage(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt
index b53e034..22ac1b6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt
@@ -24,7 +24,6 @@
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith
@@ -35,8 +34,8 @@
@RunWith(JUnit4::class)
class AuthMethodBouncerViewModelTest : SysuiTestCase() {
- private val testScope = TestScope()
- private val utils = SceneTestUtils(this, testScope)
+ private val utils = SceneTestUtils(this)
+ private val testScope = utils.testScope
private val authenticationInteractor =
utils.authenticationInteractor(
utils.authenticationRepository(),
@@ -55,7 +54,9 @@
@Test
fun animateFailure() =
testScope.runTest {
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
val animateFailure by collectLastValue(underTest.animateFailure)
assertThat(animateFailure).isFalse()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt
index c607496..5ffc471 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt
@@ -23,11 +23,14 @@
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.scene.SceneTestUtils
import com.google.common.truth.Truth.assertThat
+import com.google.common.truth.Truth.assertWithMessage
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.flatMapLatest
-import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.test.advanceTimeBy
+import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith
@@ -38,8 +41,8 @@
@RunWith(JUnit4::class)
class BouncerViewModelTest : SysuiTestCase() {
- private val testScope = TestScope()
- private val utils = SceneTestUtils(this, testScope)
+ private val utils = SceneTestUtils(this)
+ private val testScope = utils.testScope
private val authenticationInteractor =
utils.authenticationInteractor(
repository = utils.authenticationRepository(),
@@ -54,16 +57,26 @@
@Test
fun authMethod_nonNullForSecureMethods_nullForNotSecureMethods() =
testScope.runTest {
- val authMethodViewModel: AuthMethodBouncerViewModel? by
- collectLastValue(underTest.authMethod)
+ var authMethodViewModel: AuthMethodBouncerViewModel? = null
+
authMethodsToTest().forEach { authMethod ->
- authenticationInteractor.setAuthenticationMethod(authMethod)
+ utils.authenticationRepository.setAuthenticationMethod(authMethod)
+ val job = underTest.authMethod.onEach { authMethodViewModel = it }.launchIn(this)
+ runCurrent()
if (authMethod.isSecure) {
- assertThat(authMethodViewModel).isNotNull()
+ assertWithMessage("View-model unexpectedly null for auth method $authMethod")
+ .that(authMethodViewModel)
+ .isNotNull()
} else {
- assertThat(authMethodViewModel).isNull()
+ assertWithMessage(
+ "View-model unexpectedly non-null for auth method $authMethod"
+ )
+ .that(authMethodViewModel)
+ .isNull()
}
+
+ job.cancel()
}
}
@@ -75,13 +88,13 @@
collectLastValue(underTest.authMethod)
// First pass, populate our "seen" map:
authMethodsToTest().forEach { authMethod ->
- authenticationInteractor.setAuthenticationMethod(authMethod)
+ utils.authenticationRepository.setAuthenticationMethod(authMethod)
authMethodViewModel?.let { seen[authMethod] = it }
}
// Second pass, assert same instances are reused:
authMethodsToTest().forEach { authMethod ->
- authenticationInteractor.setAuthenticationMethod(authMethod)
+ utils.authenticationRepository.setAuthenticationMethod(authMethod)
authMethodViewModel?.let { assertThat(it).isSameInstanceAs(seen[authMethod]) }
}
}
@@ -97,7 +110,9 @@
testScope.runTest {
val message by collectLastValue(underTest.message)
val throttling by collectLastValue(bouncerInteractor.throttling)
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
assertThat(message?.isUpdateAnimated).isTrue()
repeat(BouncerInteractor.THROTTLE_EVERY) {
@@ -120,7 +135,9 @@
}
)
val throttling by collectLastValue(bouncerInteractor.throttling)
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
assertThat(isInputEnabled).isTrue()
repeat(BouncerInteractor.THROTTLE_EVERY) {
@@ -137,7 +154,9 @@
fun throttlingDialogMessage() =
testScope.runTest {
val throttlingDialogMessage by collectLastValue(underTest.throttlingDialogMessage)
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
repeat(BouncerInteractor.THROTTLE_EVERY) {
// Wrong PIN.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
index f436aa3..699571b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
@@ -28,7 +28,7 @@
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
-import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
@@ -40,8 +40,8 @@
@RunWith(JUnit4::class)
class PasswordBouncerViewModelTest : SysuiTestCase() {
- private val testScope = TestScope()
- private val utils = SceneTestUtils(this, testScope)
+ private val utils = SceneTestUtils(this)
+ private val testScope = utils.testScope
private val authenticationInteractor =
utils.authenticationInteractor(
repository = utils.authenticationRepository(),
@@ -58,6 +58,7 @@
)
private val underTest =
PasswordBouncerViewModel(
+ applicationScope = testScope.backgroundScope,
interactor = bouncerInteractor,
isInputEnabled = MutableStateFlow(true).asStateFlow(),
)
@@ -71,84 +72,74 @@
@Test
fun onShown() =
testScope.runTest {
- val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
val message by collectLastValue(bouncerViewModel.message)
val password by collectLastValue(underTest.password)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password("password")
)
- authenticationInteractor.lockDevice()
+ utils.authenticationRepository.setUnlocked(false)
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
- assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
assertThat(message?.text).isEqualTo(ENTER_YOUR_PASSWORD)
assertThat(password).isEqualTo("")
- assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
}
@Test
fun onPasswordInputChanged() =
testScope.runTest {
- val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
val message by collectLastValue(bouncerViewModel.message)
val password by collectLastValue(underTest.password)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password("password")
)
- authenticationInteractor.lockDevice()
+ utils.authenticationRepository.setUnlocked(false)
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
- assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
+ runCurrent()
underTest.onPasswordInputChanged("password")
assertThat(message?.text).isEmpty()
assertThat(password).isEqualTo("password")
- assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
}
@Test
fun onAuthenticateKeyPressed_whenCorrect() =
testScope.runTest {
- val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password("password")
)
- authenticationInteractor.lockDevice()
+ utils.authenticationRepository.setUnlocked(false)
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
- assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onPasswordInputChanged("password")
underTest.onAuthenticateKeyPressed()
- assertThat(isUnlocked).isTrue()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone))
}
@Test
fun onAuthenticateKeyPressed_whenWrong() =
testScope.runTest {
- val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
val message by collectLastValue(bouncerViewModel.message)
val password by collectLastValue(underTest.password)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password("password")
)
- authenticationInteractor.lockDevice()
+ utils.authenticationRepository.setUnlocked(false)
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
- assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onPasswordInputChanged("wrong")
@@ -157,30 +148,26 @@
assertThat(password).isEqualTo("")
assertThat(message?.text).isEqualTo(WRONG_PASSWORD)
- assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
}
@Test
fun onAuthenticateKeyPressed_correctAfterWrong() =
testScope.runTest {
- val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
val message by collectLastValue(bouncerViewModel.message)
val password by collectLastValue(underTest.password)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password("password")
)
- authenticationInteractor.lockDevice()
+ utils.authenticationRepository.setUnlocked(false)
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
- assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onPasswordInputChanged("wrong")
underTest.onAuthenticateKeyPressed()
assertThat(password).isEqualTo("")
assertThat(message?.text).isEqualTo(WRONG_PASSWORD)
- assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
// Enter the correct password:
@@ -189,7 +176,6 @@
underTest.onAuthenticateKeyPressed()
- assertThat(isUnlocked).isTrue()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone))
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt
index d7d7154..9a1f584 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt
@@ -29,7 +29,7 @@
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
-import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
@@ -41,8 +41,8 @@
@RunWith(JUnit4::class)
class PatternBouncerViewModelTest : SysuiTestCase() {
- private val testScope = TestScope()
- private val utils = SceneTestUtils(this, testScope)
+ private val utils = SceneTestUtils(this)
+ private val testScope = utils.testScope
private val authenticationInteractor =
utils.authenticationInteractor(
repository = utils.authenticationRepository(),
@@ -74,17 +74,15 @@
@Test
fun onShown() =
testScope.runTest {
- val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
val message by collectLastValue(bouncerViewModel.message)
val selectedDots by collectLastValue(underTest.selectedDots)
val currentDot by collectLastValue(underTest.currentDot)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pattern(CORRECT_PATTERN)
)
- authenticationInteractor.lockDevice()
+ utils.authenticationRepository.setUnlocked(false)
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
- assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
@@ -92,49 +90,44 @@
assertThat(message?.text).isEqualTo(ENTER_YOUR_PATTERN)
assertThat(selectedDots).isEmpty()
assertThat(currentDot).isNull()
- assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
}
@Test
fun onDragStart() =
testScope.runTest {
- val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
val message by collectLastValue(bouncerViewModel.message)
val selectedDots by collectLastValue(underTest.selectedDots)
val currentDot by collectLastValue(underTest.currentDot)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pattern(CORRECT_PATTERN)
)
- authenticationInteractor.lockDevice()
+ utils.authenticationRepository.setUnlocked(false)
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
- assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
+ runCurrent()
underTest.onDragStart()
assertThat(message?.text).isEmpty()
assertThat(selectedDots).isEmpty()
assertThat(currentDot).isNull()
- assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
}
@Test
fun onDragEnd_whenCorrect() =
testScope.runTest {
- val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
val selectedDots by collectLastValue(underTest.selectedDots)
val currentDot by collectLastValue(underTest.currentDot)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pattern(CORRECT_PATTERN)
)
- authenticationInteractor.lockDevice()
+ utils.authenticationRepository.setUnlocked(false)
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
- assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onDragStart()
@@ -168,24 +161,21 @@
underTest.onDragEnd()
- assertThat(isUnlocked).isTrue()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone))
}
@Test
fun onDragEnd_whenWrong() =
testScope.runTest {
- val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
val message by collectLastValue(bouncerViewModel.message)
val selectedDots by collectLastValue(underTest.selectedDots)
val currentDot by collectLastValue(underTest.currentDot)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pattern(CORRECT_PATTERN)
)
- authenticationInteractor.lockDevice()
+ utils.authenticationRepository.setUnlocked(false)
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
- assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onDragStart()
@@ -203,24 +193,21 @@
assertThat(selectedDots).isEmpty()
assertThat(currentDot).isNull()
assertThat(message?.text).isEqualTo(WRONG_PATTERN)
- assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
}
@Test
fun onDragEnd_correctAfterWrong() =
testScope.runTest {
- val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
val message by collectLastValue(bouncerViewModel.message)
val selectedDots by collectLastValue(underTest.selectedDots)
val currentDot by collectLastValue(underTest.currentDot)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pattern(CORRECT_PATTERN)
)
- authenticationInteractor.lockDevice()
+ utils.authenticationRepository.setUnlocked(false)
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
- assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onDragStart()
@@ -236,7 +223,6 @@
assertThat(selectedDots).isEmpty()
assertThat(currentDot).isNull()
assertThat(message?.text).isEqualTo(WRONG_PATTERN)
- assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
// Enter the correct pattern:
@@ -251,7 +237,6 @@
underTest.onDragEnd()
- assertThat(isUnlocked).isTrue()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone))
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
index 7e358d2..61432e2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
@@ -29,7 +29,7 @@
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
-import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
@@ -41,8 +41,8 @@
@RunWith(JUnit4::class)
class PinBouncerViewModelTest : SysuiTestCase() {
- private val testScope = TestScope()
- private val utils = SceneTestUtils(this, testScope)
+ private val utils = SceneTestUtils(this)
+ private val testScope = utils.testScope
private val sceneInteractor = utils.sceneInteractor()
private val authenticationInteractor =
utils.authenticationInteractor(
@@ -81,60 +81,57 @@
@Test
fun onShown() =
testScope.runTest {
- val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
val message by collectLastValue(bouncerViewModel.message)
val entries by collectLastValue(underTest.pinEntries)
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
- authenticationInteractor.lockDevice()
+ utils.authenticationRepository.setUnlocked(false)
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
- assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
assertThat(message?.text).isEqualTo(ENTER_YOUR_PIN)
assertThat(entries).hasSize(0)
- assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
}
@Test
fun onPinButtonClicked() =
testScope.runTest {
- val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
val message by collectLastValue(bouncerViewModel.message)
val entries by collectLastValue(underTest.pinEntries)
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
- authenticationInteractor.lockDevice()
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
+ utils.authenticationRepository.setUnlocked(false)
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
- assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
+ runCurrent()
underTest.onPinButtonClicked(1)
assertThat(message?.text).isEmpty()
assertThat(entries).hasSize(1)
assertThat(entries?.map { it.input }).containsExactly(1)
- assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
}
@Test
fun onBackspaceButtonClicked() =
testScope.runTest {
- val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
val message by collectLastValue(bouncerViewModel.message)
val entries by collectLastValue(underTest.pinEntries)
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
- authenticationInteractor.lockDevice()
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
+ utils.authenticationRepository.setUnlocked(false)
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
- assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
+ runCurrent()
underTest.onPinButtonClicked(1)
assertThat(entries).hasSize(1)
@@ -142,21 +139,19 @@
assertThat(message?.text).isEmpty()
assertThat(entries).hasSize(0)
- assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
}
@Test
fun onPinEdit() =
testScope.runTest {
- val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
- val message by collectLastValue(bouncerViewModel.message)
val entries by collectLastValue(underTest.pinEntries)
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
- authenticationInteractor.lockDevice()
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
+ utils.authenticationRepository.setUnlocked(false)
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
- assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
@@ -176,16 +171,17 @@
@Test
fun onBackspaceButtonLongPressed() =
testScope.runTest {
- val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
val message by collectLastValue(bouncerViewModel.message)
val entries by collectLastValue(underTest.pinEntries)
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
- authenticationInteractor.lockDevice()
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
+ utils.authenticationRepository.setUnlocked(false)
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
- assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
+ runCurrent()
underTest.onPinButtonClicked(1)
underTest.onPinButtonClicked(2)
underTest.onPinButtonClicked(3)
@@ -195,19 +191,18 @@
assertThat(message?.text).isEmpty()
assertThat(entries).hasSize(0)
- assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
}
@Test
fun onAuthenticateButtonClicked_whenCorrect() =
testScope.runTest {
- val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
- authenticationInteractor.lockDevice()
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
+ utils.authenticationRepository.setUnlocked(false)
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
- assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onPinButtonClicked(1)
@@ -217,21 +212,20 @@
underTest.onAuthenticateButtonClicked()
- assertThat(isUnlocked).isTrue()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone))
}
@Test
fun onAuthenticateButtonClicked_whenWrong() =
testScope.runTest {
- val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
val message by collectLastValue(bouncerViewModel.message)
val entries by collectLastValue(underTest.pinEntries)
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
- authenticationInteractor.lockDevice()
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
+ utils.authenticationRepository.setUnlocked(false)
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
- assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onPinButtonClicked(1)
@@ -244,21 +238,20 @@
assertThat(entries).hasSize(0)
assertThat(message?.text).isEqualTo(WRONG_PIN)
- assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
}
@Test
fun onAuthenticateButtonClicked_correctAfterWrong() =
testScope.runTest {
- val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
val message by collectLastValue(bouncerViewModel.message)
val entries by collectLastValue(underTest.pinEntries)
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
- authenticationInteractor.lockDevice()
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
+ utils.authenticationRepository.setUnlocked(false)
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
- assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onPinButtonClicked(1)
@@ -269,7 +262,6 @@
underTest.onAuthenticateButtonClicked()
assertThat(message?.text).isEqualTo(WRONG_PIN)
assertThat(entries).hasSize(0)
- assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
// Enter the correct PIN:
@@ -281,21 +273,18 @@
underTest.onAuthenticateButtonClicked()
- assertThat(isUnlocked).isTrue()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone))
}
@Test
fun onAutoConfirm_whenCorrect() =
testScope.runTest {
- val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234, autoConfirm = true)
)
- authenticationInteractor.lockDevice()
+ utils.authenticationRepository.setUnlocked(false)
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
- assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onPinButtonClicked(1)
@@ -303,23 +292,20 @@
underTest.onPinButtonClicked(3)
underTest.onPinButtonClicked(4)
- assertThat(isUnlocked).isTrue()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone))
}
@Test
fun onAutoConfirm_whenWrong() =
testScope.runTest {
- val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
val message by collectLastValue(bouncerViewModel.message)
val entries by collectLastValue(underTest.pinEntries)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234, autoConfirm = true)
)
- authenticationInteractor.lockDevice()
+ utils.authenticationRepository.setUnlocked(false)
sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
- assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onPinButtonClicked(1)
@@ -329,7 +315,6 @@
assertThat(entries).hasSize(0)
assertThat(message?.text).isEqualTo(WRONG_PIN)
- assertThat(isUnlocked).isFalse()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
}
@@ -338,7 +323,7 @@
testScope.runTest {
val backspaceButtonAppearance by collectLastValue(underTest.backspaceButtonAppearance)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234, autoConfirm = false)
)
@@ -349,7 +334,7 @@
fun backspaceButtonAppearance_withAutoConfirmButNoInput_isHidden() =
testScope.runTest {
val backspaceButtonAppearance by collectLastValue(underTest.backspaceButtonAppearance)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234, autoConfirm = true)
)
@@ -360,7 +345,7 @@
fun backspaceButtonAppearance_withAutoConfirmAndInput_isShownQuiet() =
testScope.runTest {
val backspaceButtonAppearance by collectLastValue(underTest.backspaceButtonAppearance)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234, autoConfirm = true)
)
@@ -374,7 +359,7 @@
testScope.runTest {
val confirmButtonAppearance by collectLastValue(underTest.confirmButtonAppearance)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234, autoConfirm = false)
)
@@ -385,7 +370,7 @@
fun confirmButtonAppearance_withAutoConfirm_isHidden() =
testScope.runTest {
val confirmButtonAppearance by collectLastValue(underTest.confirmButtonAppearance)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234, autoConfirm = true)
)
@@ -396,7 +381,7 @@
fun hintedPinLength_withoutAutoConfirm_isNull() =
testScope.runTest {
val hintedPinLength by collectLastValue(underTest.hintedPinLength)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234, autoConfirm = false)
)
@@ -407,7 +392,7 @@
fun hintedPinLength_withAutoConfirmPinLessThanSixDigits_isNull() =
testScope.runTest {
val hintedPinLength by collectLastValue(underTest.hintedPinLength)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(12345, autoConfirm = true)
)
@@ -418,7 +403,7 @@
fun hintedPinLength_withAutoConfirmPinExactlySixDigits_isSix() =
testScope.runTest {
val hintedPinLength by collectLastValue(underTest.hintedPinLength)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(123456, autoConfirm = true)
)
@@ -429,7 +414,7 @@
fun hintedPinLength_withAutoConfirmPinMoreThanSixDigits_isNull() =
testScope.runTest {
val hintedPinLength by collectLastValue(underTest.hintedPinLength)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Pin(1234567, autoConfirm = true)
)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayMetricsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayMetricsRepositoryTest.kt
new file mode 100644
index 0000000..dd741b4
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayMetricsRepositoryTest.kt
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.display.data.repository
+
+import android.content.Context
+import android.util.DisplayMetrics
+import android.view.Display
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.statusbar.policy.FakeConfigurationController
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+
+@SmallTest
+@OptIn(ExperimentalCoroutinesApi::class)
+class DisplayMetricsRepositoryTest : SysuiTestCase() {
+ private lateinit var underTest: DisplayMetricsRepository
+
+ private val testScope = TestScope(StandardTestDispatcher())
+ private val configurationController = FakeConfigurationController()
+
+ private val displayMetrics =
+ DisplayMetrics().apply { this.heightPixels = INITIAL_HEIGHT_PIXELS }
+ private val mockContext: Context = mock()
+ private val mockDisplay: Display = mock()
+
+ @Before
+ fun setUp() {
+ underTest =
+ DisplayMetricsRepository(
+ testScope.backgroundScope,
+ configurationController,
+ displayMetrics,
+ mockContext,
+ LogBuffer("TestBuffer", maxSize = 10, logcatEchoTracker = mock())
+ )
+ whenever(mockContext.display).thenReturn(mockDisplay)
+ }
+
+ @Test
+ fun heightPixels_getsInitialValue() {
+ assertThat(underTest.heightPixels).isEqualTo(INITIAL_HEIGHT_PIXELS)
+ }
+
+ @Test
+ fun heightPixels_configChanged_heightUpdated() =
+ testScope.runTest {
+ runCurrent()
+
+ updateDisplayMetrics(456)
+ configurationController.notifyConfigurationChanged()
+ runCurrent()
+
+ assertThat(underTest.heightPixels).isEqualTo(456)
+
+ updateDisplayMetrics(23)
+ configurationController.notifyConfigurationChanged()
+ runCurrent()
+
+ assertThat(underTest.heightPixels).isEqualTo(23)
+ }
+
+ private fun updateDisplayMetrics(newHeight: Int) {
+ whenever(mockDisplay.getMetrics(displayMetrics)).thenAnswer {
+ it.getArgument<DisplayMetrics>(0).heightPixels = newHeight
+ Unit
+ }
+ }
+
+ private companion object {
+ const val INITIAL_HEIGHT_PIXELS = 345
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractorTest.kt
new file mode 100644
index 0000000..1b597f4
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractorTest.kt
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.display.domain.interactor
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.view.Display
+import android.view.Display.TYPE_EXTERNAL
+import android.view.Display.TYPE_INTERNAL
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.FlowValue
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.display.data.repository.DisplayRepository
+import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor.State
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+class ConnectedDisplayInteractorTest : SysuiTestCase() {
+
+ private val fakeDisplayRepository = FakeDisplayRepository()
+ private val connectedDisplayStateProvider: ConnectedDisplayInteractor =
+ ConnectedDisplayInteractorImpl(fakeDisplayRepository)
+ private val testScope = TestScope(UnconfinedTestDispatcher())
+
+ @Test
+ fun displayState_nullDisplays_disconnected() =
+ testScope.runTest {
+ val value by lastValue()
+
+ fakeDisplayRepository.emit(emptySet())
+
+ assertThat(value).isEqualTo(State.DISCONNECTED)
+ }
+
+ @Test
+ fun displayState_emptyDisplays_disconnected() =
+ testScope.runTest {
+ val value by lastValue()
+
+ fakeDisplayRepository.emit(emptySet())
+
+ assertThat(value).isEqualTo(State.DISCONNECTED)
+ }
+
+ @Test
+ fun displayState_internalDisplay_disconnected() =
+ testScope.runTest {
+ val value by lastValue()
+
+ fakeDisplayRepository.emit(setOf(display(type = TYPE_INTERNAL)))
+
+ assertThat(value).isEqualTo(State.DISCONNECTED)
+ }
+
+ @Test
+ fun displayState_externalDisplay_connected() =
+ testScope.runTest {
+ val value by lastValue()
+
+ fakeDisplayRepository.emit(setOf(display(type = TYPE_EXTERNAL)))
+
+ assertThat(value).isEqualTo(State.CONNECTED)
+ }
+
+ @Test
+ fun displayState_multipleExternalDisplays_connected() =
+ testScope.runTest {
+ val value by lastValue()
+
+ fakeDisplayRepository.emit(
+ setOf(display(type = TYPE_EXTERNAL), display(type = TYPE_EXTERNAL))
+ )
+
+ assertThat(value).isEqualTo(State.CONNECTED)
+ }
+
+ @Test
+ fun displayState_externalSecure_connectedSecure() =
+ testScope.runTest {
+ val value by lastValue()
+
+ fakeDisplayRepository.emit(
+ setOf(display(type = TYPE_EXTERNAL, flags = Display.FLAG_SECURE))
+ )
+
+ assertThat(value).isEqualTo(State.CONNECTED_SECURE)
+ }
+
+ @Test
+ fun displayState_multipleExternal_onlyOneSecure_connectedSecure() =
+ testScope.runTest {
+ val value by lastValue()
+
+ fakeDisplayRepository.emit(
+ setOf(
+ display(type = TYPE_EXTERNAL, flags = Display.FLAG_SECURE),
+ display(type = TYPE_EXTERNAL, flags = 0)
+ )
+ )
+
+ assertThat(value).isEqualTo(State.CONNECTED_SECURE)
+ }
+
+ private fun TestScope.lastValue(): FlowValue<State?> =
+ collectLastValue(connectedDisplayStateProvider.connectedDisplayState)
+
+ private fun display(type: Int, flags: Int = 0): Display {
+ return mock<Display>().also { mockDisplay ->
+ whenever(mockDisplay.type).thenReturn(type)
+ whenever(mockDisplay.flags).thenReturn(flags)
+ }
+ }
+
+ private class FakeDisplayRepository : DisplayRepository {
+ private val flow = MutableSharedFlow<Set<Display>>()
+ suspend fun emit(value: Set<Display>) = flow.emit(value)
+ override val displays: Flow<Set<Display>>
+ get() = flow
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dump/LogBufferHelper.kt b/packages/SystemUI/tests/src/com/android/systemui/dump/LogBufferHelper.kt
index bd029a7..a341ca3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dump/LogBufferHelper.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/dump/LogBufferHelper.kt
@@ -17,7 +17,7 @@
package com.android.systemui.dump
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
+import com.android.systemui.log.core.LogLevel
import com.android.systemui.log.LogcatEchoTracker
/**
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index 12a9f94..6f7c217 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -780,6 +780,11 @@
assertTrue(mViewMediator.isShowingAndNotOccluded());
}
+ @Test
+ public void testBouncerSwipeDown() {
+ mViewMediator.getViewMediatorCallback().onBouncerSwipeDown();
+ verify(mStatusBarKeyguardViewManager).reset(true);
+ }
private void createAndStartViewMediator() {
mViewMediator = new KeyguardViewMediator(
mContext,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
index 5922cbf..e042564 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
@@ -260,6 +260,7 @@
assertThat(authStatus()).isEqualTo(SuccessAuthenticationStatus(successResult))
assertThat(authenticated()).isTrue()
assertThat(authRunning()).isFalse()
+ assertThat(canFaceAuthRun()).isFalse()
}
private fun uiEventIsLogged(faceAuthUiEvent: FaceAuthUiEvent) {
@@ -417,13 +418,9 @@
FACE_ERROR_CANCELED,
"First auth attempt cancellation completed"
)
- assertThat(authStatus())
- .isEqualTo(
- ErrorAuthenticationStatus(
- FACE_ERROR_CANCELED,
- "First auth attempt cancellation completed"
- )
- )
+ val value = authStatus() as ErrorAuthenticationStatus
+ assertThat(value.msgId).isEqualTo(FACE_ERROR_CANCELED)
+ assertThat(value.msg).isEqualTo("First auth attempt cancellation completed")
faceAuthenticateIsCalled()
uiEventIsLogged(FACE_AUTH_TRIGGERED_ALTERNATE_BIOMETRIC_BOUNCER_SHOWN)
@@ -551,20 +548,6 @@
}
@Test
- fun authenticateDoesNotRunWhenDeviceIsSleeping() =
- testScope.runTest {
- testGatingCheckForFaceAuth {
- keyguardRepository.setWakefulnessModel(
- WakefulnessModel(
- state = WakefulnessState.ASLEEP,
- lastWakeReason = WakeSleepReason.OTHER,
- lastSleepReason = WakeSleepReason.OTHER,
- )
- )
- }
- }
-
- @Test
fun authenticateDoesNotRunWhenNonStrongBiometricIsNotAllowed() =
testScope.runTest {
testGatingCheckForFaceAuth {
@@ -586,6 +569,29 @@
}
@Test
+ fun authenticateRunsWhenSecureCameraIsActiveIfBouncerIsShowing() =
+ testScope.runTest {
+ initCollectors()
+ allPreconditionsToRunFaceAuthAreTrue()
+ bouncerRepository.setAlternateVisible(false)
+ bouncerRepository.setPrimaryShow(false)
+
+ assertThat(canFaceAuthRun()).isTrue()
+
+ // launch secure camera
+ fakeCommandQueue.doForEachCallback {
+ it.onCameraLaunchGestureDetected(CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP)
+ }
+ keyguardRepository.setKeyguardOccluded(true)
+ runCurrent()
+ assertThat(canFaceAuthRun()).isFalse()
+
+ // but bouncer is shown after that.
+ bouncerRepository.setPrimaryShow(true)
+ assertThat(canFaceAuthRun()).isTrue()
+ }
+
+ @Test
fun authenticateDoesNotRunOnUnsupportedPosture() =
testScope.runTest {
testGatingCheckForFaceAuth {
@@ -616,6 +622,27 @@
}
@Test
+ fun authenticateFallbacksToDetectionWhenUserIsAlreadyTrustedByTrustManager() =
+ testScope.runTest {
+ whenever(faceManager.sensorPropertiesInternal)
+ .thenReturn(listOf(createFaceSensorProperties(supportsFaceDetection = true)))
+ whenever(bypassController.bypassEnabled).thenReturn(true)
+ underTest = createDeviceEntryFaceAuthRepositoryImpl()
+ initCollectors()
+ allPreconditionsToRunFaceAuthAreTrue()
+
+ trustRepository.setCurrentUserTrusted(true)
+ assertThat(canFaceAuthRun()).isFalse()
+ underTest.authenticate(
+ FACE_AUTH_TRIGGERED_SWIPE_UP_ON_BOUNCER,
+ fallbackToDetection = true
+ )
+ faceAuthenticateIsNotCalled()
+
+ faceDetectIsCalled()
+ }
+
+ @Test
fun everythingWorksWithFaceAuthRefactorFlagDisabled() =
testScope.runTest {
featureFlags.set(FACE_AUTH_REFACTOR, false)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
index 953d618..25573de 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
@@ -235,11 +235,10 @@
fun isKeyguardUnlocked() =
testScope.runTest {
whenever(keyguardStateController.isUnlocked).thenReturn(false)
- var latest: Boolean? = null
- val job = underTest.isKeyguardUnlocked.onEach { latest = it }.launchIn(this)
+ val isKeyguardUnlocked by collectLastValue(underTest.isKeyguardUnlocked)
runCurrent()
- assertThat(latest).isFalse()
+ assertThat(isKeyguardUnlocked).isFalse()
val captor = argumentCaptor<KeyguardStateController.Callback>()
verify(keyguardStateController).addCallback(captor.capture())
@@ -247,14 +246,12 @@
whenever(keyguardStateController.isUnlocked).thenReturn(true)
captor.value.onUnlockedChanged()
runCurrent()
- assertThat(latest).isTrue()
+ assertThat(isKeyguardUnlocked).isTrue()
whenever(keyguardStateController.isUnlocked).thenReturn(false)
- captor.value.onUnlockedChanged()
+ captor.value.onKeyguardShowingChanged()
runCurrent()
- assertThat(latest).isFalse()
-
- job.cancel()
+ assertThat(isKeyguardUnlocked).isFalse()
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt
index 80700e5..ee5c1cc3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.keyguard.domain.interactor
+import android.hardware.biometrics.BiometricFaceConstants
import android.os.Handler
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -30,6 +31,7 @@
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.bouncer.ui.BouncerView
import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.dump.logcatLogBuffer
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
@@ -39,6 +41,7 @@
import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.data.repository.FakeTrustRepository
+import com.android.systemui.keyguard.shared.model.ErrorAuthenticationStatus
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
@@ -90,6 +93,7 @@
underTest =
SystemUIKeyguardFaceAuthInteractor(
+ mContext,
testScope.backgroundScope,
dispatcher,
faceAuthRepository,
@@ -144,6 +148,22 @@
}
@Test
+ fun whenFaceIsLockedOutAnyAttemptsToTriggerFaceAuthMustProvideLockoutError() =
+ testScope.runTest {
+ underTest.start()
+ val authenticationStatus = collectLastValue(underTest.authenticationStatus)
+ faceAuthRepository.setLockedOut(true)
+
+ underTest.onDeviceLifted()
+
+ val outputValue = authenticationStatus()!! as ErrorAuthenticationStatus
+ assertThat(outputValue.msgId)
+ .isEqualTo(BiometricFaceConstants.FACE_ERROR_LOCKOUT_PERMANENT)
+ assertThat(outputValue.msg).isEqualTo("Face Unlock unavailable")
+ assertThat(faceAuthRepository.runningAuthRequest.value).isNull()
+ }
+
+ @Test
fun faceAuthIsRequestedWhenLockscreenBecomesVisibleFromAodState() =
testScope.runTest {
underTest.start()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
index 50075b5..b559015 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
@@ -25,7 +25,6 @@
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
-import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
import com.android.systemui.keyguard.shared.model.DozeStateModel
import com.android.systemui.keyguard.shared.model.DozeTransitionModel
@@ -56,6 +55,7 @@
import org.mockito.Mock
import org.mockito.Mockito.never
import org.mockito.Mockito.reset
+import org.mockito.Mockito.spy
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@@ -72,10 +72,10 @@
private lateinit var bouncerRepository: FakeKeyguardBouncerRepository
private lateinit var shadeRepository: ShadeRepository
private lateinit var transitionRepository: FakeKeyguardTransitionRepository
+ private lateinit var transitionInteractor: KeyguardTransitionInteractor
private lateinit var featureFlags: FakeFeatureFlags
// Used to verify transition requests for test output
- @Mock private lateinit var mockTransitionRepository: KeyguardTransitionRepository
@Mock private lateinit var keyguardSecurityModel: KeyguardSecurityModel
private lateinit var fromLockscreenTransitionInteractor: FromLockscreenTransitionInteractor
@@ -97,92 +97,71 @@
keyguardRepository = FakeKeyguardRepository()
bouncerRepository = FakeKeyguardBouncerRepository()
shadeRepository = FakeShadeRepository()
- transitionRepository = FakeKeyguardTransitionRepository()
+ transitionRepository = spy(FakeKeyguardTransitionRepository())
+ transitionInteractor = KeyguardTransitionInteractor(
+ transitionRepository, testScope.backgroundScope)
whenever(keyguardSecurityModel.getSecurityMode(anyInt())).thenReturn(PIN)
featureFlags = FakeFeatureFlags().apply { set(Flags.FACE_AUTH_REFACTOR, true) }
- fromLockscreenTransitionInteractor =
- FromLockscreenTransitionInteractor(
+
+ fromLockscreenTransitionInteractor = FromLockscreenTransitionInteractor(
scope = testScope,
keyguardInteractor = createKeyguardInteractor(),
+ transitionRepository = transitionRepository,
+ transitionInteractor = transitionInteractor,
shadeRepository = shadeRepository,
- keyguardTransitionRepository = mockTransitionRepository,
- keyguardTransitionInteractor =
- KeyguardTransitionInteractor(transitionRepository, testScope.backgroundScope),
- )
- fromLockscreenTransitionInteractor.start()
+ ).apply { start() }
- fromDreamingTransitionInteractor =
- FromDreamingTransitionInteractor(
+ fromPrimaryBouncerTransitionInteractor = FromPrimaryBouncerTransitionInteractor(
scope = testScope,
keyguardInteractor = createKeyguardInteractor(),
- keyguardTransitionRepository = mockTransitionRepository,
- keyguardTransitionInteractor =
- KeyguardTransitionInteractor(transitionRepository, testScope.backgroundScope),
- )
- fromDreamingTransitionInteractor.start()
-
- fromAodTransitionInteractor =
- FromAodTransitionInteractor(
- scope = testScope,
- keyguardInteractor = createKeyguardInteractor(),
- keyguardTransitionRepository = mockTransitionRepository,
- keyguardTransitionInteractor =
- KeyguardTransitionInteractor(transitionRepository, testScope.backgroundScope),
- )
- fromAodTransitionInteractor.start()
-
- fromGoneTransitionInteractor =
- FromGoneTransitionInteractor(
- scope = testScope,
- keyguardInteractor = createKeyguardInteractor(),
- keyguardTransitionRepository = mockTransitionRepository,
- keyguardTransitionInteractor =
- KeyguardTransitionInteractor(transitionRepository, testScope.backgroundScope),
- )
- fromGoneTransitionInteractor.start()
-
- fromDozingTransitionInteractor =
- FromDozingTransitionInteractor(
- scope = testScope,
- keyguardInteractor = createKeyguardInteractor(),
- keyguardTransitionRepository = mockTransitionRepository,
- keyguardTransitionInteractor =
- KeyguardTransitionInteractor(transitionRepository, testScope.backgroundScope),
- )
- fromDozingTransitionInteractor.start()
-
- fromOccludedTransitionInteractor =
- FromOccludedTransitionInteractor(
- scope = testScope,
- keyguardInteractor = createKeyguardInteractor(),
- keyguardTransitionRepository = mockTransitionRepository,
- keyguardTransitionInteractor =
- KeyguardTransitionInteractor(transitionRepository, testScope.backgroundScope),
- )
- fromOccludedTransitionInteractor.start()
-
- fromAlternateBouncerTransitionInteractor =
- FromAlternateBouncerTransitionInteractor(
- scope = testScope,
- keyguardInteractor = createKeyguardInteractor(),
- keyguardTransitionRepository = mockTransitionRepository,
- keyguardTransitionInteractor =
- KeyguardTransitionInteractor(transitionRepository, testScope.backgroundScope),
- )
- fromAlternateBouncerTransitionInteractor.start()
-
- fromPrimaryBouncerTransitionInteractor =
- FromPrimaryBouncerTransitionInteractor(
- scope = testScope,
- keyguardInteractor = createKeyguardInteractor(),
- keyguardTransitionRepository = mockTransitionRepository,
- keyguardTransitionInteractor =
- KeyguardTransitionInteractor(transitionRepository, testScope.backgroundScope),
+ transitionRepository = transitionRepository,
+ transitionInteractor = transitionInteractor,
keyguardSecurityModel = keyguardSecurityModel,
- )
- fromPrimaryBouncerTransitionInteractor.start()
+ ).apply { start() }
+
+ fromDreamingTransitionInteractor = FromDreamingTransitionInteractor(
+ scope = testScope,
+ keyguardInteractor = createKeyguardInteractor(),
+ transitionRepository = transitionRepository,
+ transitionInteractor = transitionInteractor,
+ ).apply { start() }
+
+ fromAodTransitionInteractor = FromAodTransitionInteractor(
+ scope = testScope,
+ keyguardInteractor = createKeyguardInteractor(),
+ transitionRepository = transitionRepository,
+ transitionInteractor = transitionInteractor,
+ ).apply { start() }
+
+ fromGoneTransitionInteractor = FromGoneTransitionInteractor(
+ scope = testScope,
+ keyguardInteractor = createKeyguardInteractor(),
+ transitionRepository = transitionRepository,
+ transitionInteractor = transitionInteractor,
+ ).apply { start() }
+
+ fromDozingTransitionInteractor = FromDozingTransitionInteractor(
+ scope = testScope,
+ keyguardInteractor = createKeyguardInteractor(),
+ transitionRepository = transitionRepository,
+ transitionInteractor = transitionInteractor,
+ ).apply { start() }
+
+ fromOccludedTransitionInteractor = FromOccludedTransitionInteractor(
+ scope = testScope,
+ keyguardInteractor = createKeyguardInteractor(),
+ transitionRepository = transitionRepository,
+ transitionInteractor = transitionInteractor,
+ ).apply { start() }
+
+ fromAlternateBouncerTransitionInteractor = FromAlternateBouncerTransitionInteractor(
+ scope = testScope,
+ keyguardInteractor = createKeyguardInteractor(),
+ transitionRepository = transitionRepository,
+ transitionInteractor = transitionInteractor,
+ ).apply { start() }
}
@Test
@@ -201,7 +180,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to PRIMARY_BOUNCER should occur
assertThat(info.ownerName).isEqualTo("FromLockscreenTransitionInteractor")
@@ -228,7 +207,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to DOZING should occur
assertThat(info.ownerName).isEqualTo("FromOccludedTransitionInteractor")
@@ -255,7 +234,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to DOZING should occur
assertThat(info.ownerName).isEqualTo("FromOccludedTransitionInteractor")
@@ -286,7 +265,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to DREAMING should occur
assertThat(info.ownerName).isEqualTo("FromLockscreenTransitionInteractor")
@@ -313,7 +292,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to DOZING should occur
assertThat(info.ownerName).isEqualTo("FromLockscreenTransitionInteractor")
@@ -340,7 +319,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to DOZING should occur
assertThat(info.ownerName).isEqualTo("FromLockscreenTransitionInteractor")
@@ -363,7 +342,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to DOZING should occur
assertThat(info.ownerName).isEqualTo("FromDozingTransitionInteractor")
@@ -388,14 +367,14 @@
)
)
runCurrent()
- reset(mockTransitionRepository)
+ reset(transitionRepository)
// WHEN a signal comes that dreaming is enabled
keyguardRepository.setDreamingWithOverlay(true)
advanceUntilIdle()
// THEN the transition is ignored
- verify(mockTransitionRepository, never()).startTransition(any(), anyBoolean())
+ verify(transitionRepository, never()).startTransition(any(), anyBoolean())
coroutineContext.cancelChildren()
}
@@ -412,7 +391,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to DOZING should occur
assertThat(info.ownerName).isEqualTo("FromDozingTransitionInteractor")
@@ -439,7 +418,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to DOZING should occur
assertThat(info.ownerName).isEqualTo("FromGoneTransitionInteractor")
@@ -466,7 +445,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to AOD should occur
assertThat(info.ownerName).isEqualTo("FromGoneTransitionInteractor")
@@ -489,7 +468,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to AOD should occur
assertThat(info.ownerName).isEqualTo("FromGoneTransitionInteractor")
@@ -520,7 +499,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to DREAMING should occur
assertThat(info.ownerName).isEqualTo("FromGoneTransitionInteractor")
@@ -543,7 +522,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to PRIMARY_BOUNCER should occur
assertThat(info.ownerName).isEqualTo("FromAlternateBouncerTransitionInteractor")
@@ -572,7 +551,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to AOD should occur
assertThat(info.ownerName).isEqualTo("FromAlternateBouncerTransitionInteractor")
@@ -602,7 +581,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to DOZING should occur
assertThat(info.ownerName).isEqualTo("FromAlternateBouncerTransitionInteractor")
@@ -630,7 +609,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to LOCKSCREEN should occur
assertThat(info.ownerName).isEqualTo("FromAlternateBouncerTransitionInteractor")
@@ -658,7 +637,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to AOD should occur
assertThat(info.ownerName).isEqualTo("FromPrimaryBouncerTransitionInteractor")
@@ -686,7 +665,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to DOZING should occur
assertThat(info.ownerName).isEqualTo("FromPrimaryBouncerTransitionInteractor")
@@ -713,7 +692,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to LOCKSCREEN should occur
assertThat(info.ownerName).isEqualTo("FromPrimaryBouncerTransitionInteractor")
@@ -744,7 +723,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to GONE should occur
assertThat(info.ownerName).isEqualTo("FromOccludedTransitionInteractor")
@@ -773,7 +752,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to LOCKSCREEN should occur
assertThat(info.ownerName).isEqualTo("FromOccludedTransitionInteractor")
@@ -799,7 +778,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to AlternateBouncer should occur
assertThat(info.ownerName).isEqualTo("FromOccludedTransitionInteractor")
@@ -828,7 +807,7 @@
val info =
withArgCaptor<TransitionInfo> {
- verify(mockTransitionRepository).startTransition(capture(), anyBoolean())
+ verify(transitionRepository).startTransition(capture(), anyBoolean())
}
// THEN a transition to AlternateBouncer should occur
assertThat(info.ownerName).isEqualTo("FromPrimaryBouncerTransitionInteractor")
@@ -890,6 +869,6 @@
)
)
runCurrent()
- reset(mockTransitionRepository)
+ reset(transitionRepository)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractorTest.kt
index 65781c4..abbdc3d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractorTest.kt
@@ -26,7 +26,6 @@
import com.android.systemui.scene.shared.model.SceneModel
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Test
@@ -38,8 +37,8 @@
@RunWith(JUnit4::class)
class LockscreenSceneInteractorTest : SysuiTestCase() {
- private val testScope = TestScope()
- private val utils = SceneTestUtils(this, testScope)
+ private val utils = SceneTestUtils(this)
+ private val testScope = utils.testScope
private val sceneInteractor = utils.sceneInteractor()
private val authenticationInteractor =
utils.authenticationInteractor(
@@ -61,10 +60,10 @@
testScope.runTest {
val isDeviceLocked by collectLastValue(underTest.isDeviceLocked)
- authenticationInteractor.lockDevice()
+ utils.authenticationRepository.setUnlocked(false)
assertThat(isDeviceLocked).isTrue()
- authenticationInteractor.unlockDevice()
+ utils.authenticationRepository.setUnlocked(true)
assertThat(isDeviceLocked).isFalse()
}
@@ -73,8 +72,8 @@
testScope.runTest {
val isSwipeToDismissEnabled by collectLastValue(underTest.isSwipeToDismissEnabled)
- authenticationInteractor.lockDevice()
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
+ utils.authenticationRepository.setUnlocked(false)
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
assertThat(isSwipeToDismissEnabled).isTrue()
}
@@ -84,8 +83,8 @@
testScope.runTest {
val isSwipeToDismissEnabled by collectLastValue(underTest.isSwipeToDismissEnabled)
- authenticationInteractor.unlockDevice()
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
+ utils.authenticationRepository.setUnlocked(true)
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
assertThat(isSwipeToDismissEnabled).isFalse()
}
@@ -94,8 +93,10 @@
fun dismissLockScreen_deviceLockedWithSecureAuthMethod_switchesToBouncer() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
- authenticationInteractor.lockDevice()
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
+ utils.authenticationRepository.setUnlocked(false)
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
underTest.dismissLockscreen()
@@ -107,8 +108,10 @@
fun dismissLockScreen_deviceUnlocked_switchesToGone() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
- authenticationInteractor.unlockDevice()
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
+ utils.authenticationRepository.setUnlocked(true)
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
underTest.dismissLockscreen()
@@ -120,8 +123,8 @@
fun dismissLockScreen_deviceLockedWithInsecureAuthMethod_switchesToGone() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
- authenticationInteractor.lockDevice()
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
+ utils.authenticationRepository.setUnlocked(false)
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
underTest.dismissLockscreen()
@@ -136,66 +139,23 @@
runCurrent()
sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Gone))
runCurrent()
- authenticationInteractor.unlockDevice()
+ utils.authenticationRepository.setUnlocked(true)
runCurrent()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone))
- authenticationInteractor.lockDevice()
+ utils.authenticationRepository.setUnlocked(false)
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
}
@Test
- fun deviceBiometricUnlockedInLockScreen_bypassEnabled_switchesToGone() =
- testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
- authenticationInteractor.lockDevice()
- sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Lockscreen))
- if (!authenticationInteractor.isBypassEnabled.value) {
- authenticationInteractor.toggleBypassEnabled()
- }
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
-
- authenticationInteractor.biometricUnlock()
-
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone))
- }
-
- @Test
- fun deviceBiometricUnlockedInLockScreen_bypassNotEnabled_doesNotSwitch() =
- testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
- authenticationInteractor.lockDevice()
- sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Lockscreen))
- if (authenticationInteractor.isBypassEnabled.value) {
- authenticationInteractor.toggleBypassEnabled()
- }
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
-
- authenticationInteractor.biometricUnlock()
-
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
- }
-
- @Test
- fun switchFromLockScreenToGone_authMethodSwipe_unlocksDevice() =
- testScope.runTest {
- val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
- sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Lockscreen))
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
- assertThat(isUnlocked).isFalse()
-
- sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Gone))
-
- assertThat(isUnlocked).isTrue()
- }
-
- @Test
fun switchFromLockScreenToGone_authMethodNotSwipe_doesNotUnlockDevice() =
testScope.runTest {
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Lockscreen))
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
assertThat(isUnlocked).isFalse()
sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Gone))
@@ -210,7 +170,7 @@
runCurrent()
sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Shade))
runCurrent()
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
runCurrent()
assertThat(isUnlocked).isFalse()
@@ -220,29 +180,16 @@
}
@Test
- fun authMethodChangedToNone_onLockScreenScene_dismissesLockScreen() =
- testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
- sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Lockscreen))
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
-
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.None)
-
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone))
- }
-
- @Test
fun authMethodChangedToNone_notOnLockScreenScene_doesNotDismissLockScreen() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
runCurrent()
sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.QuickSettings))
runCurrent()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.QuickSettings))
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.None)
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.None)
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.QuickSettings))
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
index f0ea007..ff4ec4b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
@@ -29,7 +29,6 @@
import com.android.systemui.scene.shared.model.SceneModel
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Test
@@ -41,8 +40,8 @@
@RunWith(JUnit4::class)
class LockscreenSceneViewModelTest : SysuiTestCase() {
- private val testScope = TestScope()
- private val utils = SceneTestUtils(this, testScope)
+ private val utils = SceneTestUtils(this)
+ private val testScope = utils.testScope
private val sceneInteractor = utils.sceneInteractor()
private val authenticationInteractor =
utils.authenticationInteractor(
@@ -73,10 +72,10 @@
fun lockButtonIcon_whenLocked() =
testScope.runTest {
val lockButtonIcon by collectLastValue(underTest.lockButtonIcon)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password("password")
)
- authenticationInteractor.lockDevice()
+ utils.authenticationRepository.setUnlocked(false)
assertThat((lockButtonIcon as? Icon.Resource)?.res)
.isEqualTo(R.drawable.ic_device_lock_on)
@@ -86,10 +85,10 @@
fun lockButtonIcon_whenUnlocked() =
testScope.runTest {
val lockButtonIcon by collectLastValue(underTest.lockButtonIcon)
- authenticationInteractor.setAuthenticationMethod(
+ utils.authenticationRepository.setAuthenticationMethod(
AuthenticationMethodModel.Password("password")
)
- authenticationInteractor.unlockDevice()
+ utils.authenticationRepository.setUnlocked(true)
assertThat((lockButtonIcon as? Icon.Resource)?.res)
.isEqualTo(R.drawable.ic_device_lock_off)
@@ -99,8 +98,8 @@
fun upTransitionSceneKey_swipeToUnlockedEnabled_gone() =
testScope.runTest {
val upTransitionSceneKey by collectLastValue(underTest.upDestinationSceneKey)
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
- authenticationInteractor.lockDevice()
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
+ utils.authenticationRepository.setUnlocked(false)
assertThat(upTransitionSceneKey).isEqualTo(SceneKey.Gone)
}
@@ -109,8 +108,10 @@
fun upTransitionSceneKey_swipeToUnlockedNotEnabled_bouncer() =
testScope.runTest {
val upTransitionSceneKey by collectLastValue(underTest.upDestinationSceneKey)
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
- authenticationInteractor.lockDevice()
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
+ utils.authenticationRepository.setUnlocked(false)
assertThat(upTransitionSceneKey).isEqualTo(SceneKey.Bouncer)
}
@@ -119,8 +120,10 @@
fun onLockButtonClicked_deviceLockedSecurely_switchesToBouncer() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
- authenticationInteractor.lockDevice()
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
+ utils.authenticationRepository.setUnlocked(false)
runCurrent()
underTest.onLockButtonClicked()
@@ -132,8 +135,10 @@
fun onContentClicked_deviceUnlocked_switchesToGone() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
- authenticationInteractor.unlockDevice()
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
+ utils.authenticationRepository.setUnlocked(true)
runCurrent()
underTest.onContentClicked()
@@ -145,8 +150,10 @@
fun onContentClicked_deviceLockedSecurely_switchesToBouncer() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
- authenticationInteractor.lockDevice()
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
+ utils.authenticationRepository.setUnlocked(false)
runCurrent()
underTest.onContentClicked()
@@ -158,8 +165,10 @@
fun onLockButtonClicked_deviceUnlocked_switchesToGone() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
- authenticationInteractor.unlockDevice()
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
+ utils.authenticationRepository.setUnlocked(true)
runCurrent()
underTest.onLockButtonClicked()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/LogBufferTest.kt b/packages/SystemUI/tests/src/com/android/systemui/log/LogBufferTest.kt
index 0cf6d3d..6836733 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/log/LogBufferTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/log/LogBufferTest.kt
@@ -2,6 +2,7 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.log.core.LogLevel
import com.google.common.truth.Truth.assertThat
import java.io.PrintWriter
import java.io.StringWriter
diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferTest.kt b/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferTest.kt
index 12f4689..83182c5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferTest.kt
@@ -18,8 +18,8 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.log.LogLevel
import com.android.systemui.log.LogcatEchoTracker
+import com.android.systemui.log.core.LogLevel
import com.android.systemui.log.table.TableChange.Companion.IS_INITIAL_PREFIX
import com.android.systemui.log.table.TableChange.Companion.MAX_STRING_LENGTH
import com.android.systemui.util.mockito.any
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
index 697d1a3..25d494c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
@@ -20,6 +20,7 @@
import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN;
import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SWITCHER_SHOWN;
import static android.inputmethodservice.InputMethodService.BACK_DISPOSITION_DEFAULT;
+import static android.inputmethodservice.InputMethodService.IME_INVISIBLE;
import static android.inputmethodservice.InputMethodService.IME_VISIBLE;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
@@ -363,7 +364,7 @@
externalNavBar.setImeWindowStatus(EXTERNAL_DISPLAY_ID, null, IME_VISIBLE,
BACK_DISPOSITION_DEFAULT, true);
defaultNavBar.setImeWindowStatus(
- DEFAULT_DISPLAY, null, 0 /* vis */, BACK_DISPOSITION_DEFAULT, false);
+ DEFAULT_DISPLAY, null, IME_INVISIBLE, BACK_DISPOSITION_DEFAULT, false);
// Verify IME window state will be updated in external NavBar & default NavBar state reset.
assertEquals(NAVIGATION_HINT_BACK_ALT | NAVIGATION_HINT_IME_SHOWN
| NAVIGATION_HINT_IME_SWITCHER_SHOWN,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt
index a60dad4..fe6c9b3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt
@@ -15,9 +15,11 @@
import android.graphics.Rect
import android.testing.AndroidTestingRunner
+import android.testing.TestableContext
import android.testing.TestableLooper
import android.testing.TestableLooper.RunWithLooper
import android.testing.ViewUtils
+import android.view.ContextThemeWrapper
import android.view.View
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.view.accessibility.AccessibilityNodeInfo
@@ -55,19 +57,24 @@
private lateinit var footer: View
+ private val themedContext = TestableContext(
+ ContextThemeWrapper(context, R.style.Theme_SystemUI_QuickSettings)
+ )
+
@Before
@Throws(Exception::class)
fun setup() {
MockitoAnnotations.initMocks(this)
testableLooper = TestableLooper.get(this)
+ // Apply only the values of the theme that are not defined
testableLooper.runWithLooper {
- qsPanel = QSPanel(context, null)
+ qsPanel = QSPanel(themedContext, null)
qsPanel.mUsingMediaPlayer = true
qsPanel.initialize(qsLogger)
// QSPanel inflates a footer inside of it, mocking it here
- footer = LinearLayout(context).apply { id = R.id.qs_footer }
+ footer = LinearLayout(themedContext).apply { id = R.id.qs_footer }
qsPanel.addView(footer, MATCH_PARENT, 100)
qsPanel.onFinishInflate()
// Provides a parent with non-zero size for QSPanel
@@ -105,12 +112,12 @@
qsPanel.tileLayout?.addTile(
QSPanelControllerBase.TileRecord(
mock(QSTile::class.java),
- QSTileViewImpl(context, QSIconViewImpl(context))
+ QSTileViewImpl(themedContext, QSIconViewImpl(themedContext))
)
)
- val mediaView = FrameLayout(context)
- mediaView.addView(View(context), MATCH_PARENT, 800)
+ val mediaView = FrameLayout(themedContext)
+ mediaView.addView(View(themedContext), MATCH_PARENT, 800)
qsPanel.setUsingHorizontalLayout(/* horizontal */ true, mediaView, /* force */ true)
qsPanel.measure(
@@ -135,12 +142,12 @@
qsPanel.tileLayout?.addTile(
QSPanelControllerBase.TileRecord(
mock(QSTile::class.java),
- QSTileViewImpl(context, QSIconViewImpl(context))
+ QSTileViewImpl(themedContext, QSIconViewImpl(themedContext))
)
)
- val mediaView = FrameLayout(context)
- mediaView.addView(View(context), MATCH_PARENT, 800)
+ val mediaView = FrameLayout(themedContext)
+ mediaView.addView(View(themedContext), MATCH_PARENT, 800)
qsPanel.setUsingHorizontalLayout(/* horizontal */ true, mediaView, /* force */ true)
qsPanel.measure(
@@ -161,7 +168,10 @@
@Test
fun testBottomPadding() {
val padding = 10
- context.orCreateTestableResources.addOverride(R.dimen.qs_panel_padding_bottom, padding)
+ themedContext.orCreateTestableResources.addOverride(
+ R.dimen.qs_panel_padding_bottom,
+ padding
+ )
qsPanel.updatePadding()
assertThat(qsPanel.paddingBottom).isEqualTo(padding)
}
@@ -170,8 +180,11 @@
fun testTopPadding() {
val padding = 10
val paddingCombined = 100
- context.orCreateTestableResources.addOverride(R.dimen.qs_panel_padding_top, padding)
- context.orCreateTestableResources.addOverride(R.dimen.qs_panel_padding_top, paddingCombined)
+ themedContext.orCreateTestableResources.addOverride(R.dimen.qs_panel_padding_top, padding)
+ themedContext.orCreateTestableResources.addOverride(
+ R.dimen.qs_panel_padding_top,
+ paddingCombined
+ )
qsPanel.updatePadding()
assertThat(qsPanel.paddingTop).isEqualTo(paddingCombined)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
index d98bcee..9781baa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
@@ -25,6 +25,7 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -107,7 +108,7 @@
@Mock
private TunerService mTunerService;
@Mock
- private Provider<AutoTileManager> mAutoTiles;
+ private AutoTileManager mAutoTiles;
@Mock
private ShadeController mShadeController;
@Mock
@@ -140,6 +141,7 @@
mFeatureFlags = new FakeFeatureFlags();
mFeatureFlags.set(Flags.QS_PIPELINE_NEW_HOST, false);
+ mFeatureFlags.set(Flags.QS_PIPELINE_AUTO_ADD, false);
mMainExecutor = new FakeExecutor(new FakeSystemClock());
@@ -160,9 +162,10 @@
mSecureSettings = new FakeSettings();
saveSetting("");
mQSTileHost = new TestQSTileHost(mContext, mDefaultFactory, mMainExecutor,
- mPluginManager, mTunerService, mAutoTiles, mShadeController,
+ mPluginManager, mTunerService, () -> mAutoTiles, mShadeController,
mQSLogger, mUserTracker, mSecureSettings, mCustomTileStatePersister,
mTileLifecycleManagerFactory, mUserFileManager, mFeatureFlags);
+ mMainExecutor.runAllReady();
mSecureSettings.registerContentObserverForUser(SETTING, new ContentObserver(null) {
@Override
@@ -296,11 +299,20 @@
StringWriter w = new StringWriter();
PrintWriter pw = new PrintWriter(w);
mQSTileHost.dump(pw, new String[]{});
- String output = "QSTileHost:\n"
- + TestTile1.class.getSimpleName() + ":\n"
- + " " + MOCK_STATE_STRING + "\n"
- + TestTile2.class.getSimpleName() + ":\n"
- + " " + MOCK_STATE_STRING + "\n";
+
+ String output = "QSTileHost:" + "\n"
+ + "tile specs: [spec1, spec2]" + "\n"
+ + "current user: 0" + "\n"
+ + "is dirty: false" + "\n"
+ + "tiles:" + "\n"
+ + "TestTile1:" + "\n"
+ + " MockState" + "\n"
+ + "TestTile2:" + "\n"
+ + " MockState" + "\n";
+
+ System.out.println(output);
+ System.out.println(w.getBuffer().toString());
+
assertEquals(output, w.getBuffer().toString());
}
@@ -672,6 +684,17 @@
assertEquals(CUSTOM_TILE.getClassName(), proto.tiles[1].getComponentName().className);
}
+ @Test
+ public void testUserChange_flagOn_autoTileManagerNotified() {
+ mFeatureFlags.set(Flags.QS_PIPELINE_NEW_HOST, true);
+ int currentUser = mUserTracker.getUserId();
+ clearInvocations(mAutoTiles);
+ when(mUserTracker.getUserId()).thenReturn(currentUser + 1);
+
+ mQSTileHost.onTuningChanged(SETTING, "a,b");
+ verify(mAutoTiles).changeUser(UserHandle.of(currentUser + 1));
+ }
+
private SharedPreferences getSharedPreferencesForUser(int user) {
return mUserFileManager.getSharedPreferences(QSTileHost.TILES, 0, user);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java
index 8789253..f55ef65 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java
@@ -26,12 +26,14 @@
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.TestableLooper;
+import android.view.ContextThemeWrapper;
import android.view.View;
import android.view.accessibility.AccessibilityNodeInfo;
@@ -56,14 +58,17 @@
private Resources mResources;
private int mLayoutSizeForOneTile;
private TileLayout mTileLayout; // under test
+ private Context mSpyContext;
+
@Before
public void setUp() throws Exception {
- Context context = Mockito.spy(mContext);
- mResources = Mockito.spy(context.getResources());
- Mockito.when(mContext.getResources()).thenReturn(mResources);
+ mSpyContext = Mockito.spy(
+ new ContextThemeWrapper(mContext, R.style.Theme_SystemUI_QuickSettings));
+ mResources = Mockito.spy(mSpyContext.getResources());
+ when(mSpyContext.getResources()).thenReturn(mResources);
- mTileLayout = new TileLayout(context);
+ mTileLayout = new TileLayout(mSpyContext);
// Layout needs to leave space for the tile margins. Three times the margin size is
// sufficient for any number of columns.
mLayoutSizeForOneTile =
@@ -73,7 +78,7 @@
private QSPanelControllerBase.TileRecord createTileRecord() {
return new QSPanelControllerBase.TileRecord(
mock(QSTile.class),
- spy(new QSTileViewImpl(mContext, new QSIconViewImpl(mContext))));
+ spy(new QSTileViewImpl(mSpyContext, new QSIconViewImpl(mSpyContext))));
}
@Test
@@ -161,7 +166,7 @@
.layout(left2.capture(), top2.capture(), right2.capture(), bottom2.capture());
// We assume two tiles will always fit side-by-side.
- assertTrue(mContext.getResources().getInteger(R.integer.quick_settings_num_columns) > 1);
+ assertTrue(mSpyContext.getResources().getInteger(R.integer.quick_settings_num_columns) > 1);
// left <= right, top <= bottom
assertTrue(left1.getValue() <= right1.getValue());
@@ -218,16 +223,16 @@
@Test
public void resourcesChanged_updateResources_returnsTrue() {
- Mockito.when(mResources.getInteger(R.integer.quick_settings_num_columns)).thenReturn(1);
+ when(mResources.getInteger(R.integer.quick_settings_num_columns)).thenReturn(1);
mTileLayout.updateResources(); // setup with 1
- Mockito.when(mResources.getInteger(R.integer.quick_settings_num_columns)).thenReturn(2);
+ when(mResources.getInteger(R.integer.quick_settings_num_columns)).thenReturn(2);
assertEquals(true, mTileLayout.updateResources());
}
@Test
public void resourcesSame_updateResources_returnsFalse() {
- Mockito.when(mResources.getInteger(R.integer.quick_settings_num_columns)).thenReturn(1);
+ when(mResources.getInteger(R.integer.quick_settings_num_columns)).thenReturn(1);
mTileLayout.updateResources(); // setup with 1
assertEquals(false, mTileLayout.updateResources());
@@ -250,7 +255,7 @@
QSPanelControllerBase.TileRecord tileRecord = createTileRecord();
mTileLayout.addTile(tileRecord);
- FakeTileView tileView = new FakeTileView(mContext);
+ FakeTileView tileView = new FakeTileView(mSpyContext);
QSTile.State state = new QSTile.State();
state.label = "TEST LABEL";
state.secondaryLabel = "TEST SECONDARY LABEL";
@@ -276,9 +281,10 @@
}
private void changeFontScaling(float scale) {
- Configuration configuration = new Configuration(mContext.getResources().getConfiguration());
+ Configuration configuration =
+ new Configuration(mSpyContext.getResources().getConfiguration());
configuration.fontScale = scale;
// updateConfiguration could help update on both resource configuration and displayMetrics
- mContext.getResources().updateConfiguration(configuration, null, null);
+ mSpyContext.getResources().updateConfiguration(configuration, null, null);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt
index 2cc6709..d647d6a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt
@@ -21,6 +21,7 @@
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.testing.TestableLooper.RunWithLooper
+import android.view.ContextThemeWrapper
import androidx.test.filters.SmallTest
import com.android.settingslib.Utils
import com.android.settingslib.drawable.UserIconDrawable
@@ -63,6 +64,8 @@
private val testScope = TestScope()
private lateinit var utils: FooterActionsTestUtils
+ private val themedContext = ContextThemeWrapper(context, R.style.Theme_SystemUI_QuickSettings)
+
@Before
fun setUp() {
utils = FooterActionsTestUtils(context, TestableLooper.get(this), testScope.testScheduler)
@@ -84,8 +87,14 @@
ContentDescription.Resource(R.string.accessibility_quick_settings_settings)
)
)
- assertThat(settings.backgroundColor).isEqualTo(R.attr.offStateColor)
- assertThat(settings.iconTint).isNull()
+ assertThat(settings.backgroundColor).isEqualTo(R.attr.shadeInactive)
+ assertThat(settings.iconTint)
+ .isEqualTo(
+ Utils.getColorAttrDefaultColor(
+ themedContext,
+ R.attr.onShadeInactiveVariant,
+ )
+ )
}
@Test
@@ -105,12 +114,12 @@
ContentDescription.Resource(R.string.accessibility_quick_settings_power_menu)
)
)
- assertThat(power.backgroundColor).isEqualTo(com.android.internal.R.attr.colorAccent)
+ assertThat(power.backgroundColor).isEqualTo(R.attr.shadeActive)
assertThat(power.iconTint)
.isEqualTo(
Utils.getColorAttrDefaultColor(
- context,
- com.android.internal.R.attr.textColorOnAccent,
+ themedContext,
+ R.attr.onShadeActive,
),
)
}
@@ -170,7 +179,7 @@
assertThat(userSwitcher).isNotNull()
assertThat(userSwitcher!!.icon)
.isEqualTo(Icon.Loaded(picture, ContentDescription.Loaded("Signed in as foo")))
- assertThat(userSwitcher.backgroundColor).isEqualTo(R.attr.offStateColor)
+ assertThat(userSwitcher.backgroundColor).isEqualTo(R.attr.shadeInactive)
// Change the current user name.
userSwitcherControllerWrapper.currentUserName = "bar"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSettingListTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSettingListTest.kt
new file mode 100644
index 0000000..817ac61
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSettingListTest.kt
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.pipeline.domain.autoaddable
+
+import android.content.ComponentName
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.android.systemui.util.mockito.mock
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class AutoAddableSettingListTest : SysuiTestCase() {
+
+ private val factory =
+ object : AutoAddableSetting.Factory {
+ override fun create(setting: String, spec: TileSpec): AutoAddableSetting {
+ return AutoAddableSetting(
+ mock(),
+ mock(),
+ setting,
+ spec,
+ )
+ }
+ }
+
+ @Test
+ fun correctLines_correctAutoAddables() {
+ val setting1 = "setting1"
+ val setting2 = "setting2"
+ val spec1 = TileSpec.create("spec1")
+ val spec2 = TileSpec.create(ComponentName("pkg", "cls"))
+
+ context.orCreateTestableResources.addOverride(
+ R.array.config_quickSettingsAutoAdd,
+ arrayOf(toStringLine(setting1, spec1), toStringLine(setting2, spec2))
+ )
+
+ val autoAddables = AutoAddableSettingList.parseSettingsResource(context.resources, factory)
+
+ assertThat(autoAddables)
+ .containsExactly(factory.create(setting1, spec1), factory.create(setting2, spec2))
+ }
+
+ @Test
+ fun malformedLine_ignored() {
+ val setting = "setting"
+ val spec = TileSpec.create("spec")
+
+ context.orCreateTestableResources.addOverride(
+ R.array.config_quickSettingsAutoAdd,
+ arrayOf(toStringLine(setting, spec), "bad_line")
+ )
+
+ val autoAddables = AutoAddableSettingList.parseSettingsResource(context.resources, factory)
+
+ assertThat(autoAddables).containsExactly(factory.create(setting, spec))
+ }
+
+ @Test
+ fun invalidSpec_ignored() {
+ val setting = "setting"
+ val spec = TileSpec.create("spec")
+
+ context.orCreateTestableResources.addOverride(
+ R.array.config_quickSettingsAutoAdd,
+ arrayOf(toStringLine(setting, spec), "invalid:")
+ )
+
+ val autoAddables = AutoAddableSettingList.parseSettingsResource(context.resources, factory)
+
+ assertThat(autoAddables).containsExactly(factory.create(setting, spec))
+ }
+
+ companion object {
+ private fun toStringLine(setting: String, spec: TileSpec) =
+ "$setting$SETTINGS_SEPARATOR${spec.spec}"
+ private const val SETTINGS_SEPARATOR = ":"
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSettingTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSettingTest.kt
new file mode 100644
index 0000000..36c3c9d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSettingTest.kt
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.pipeline.domain.autoaddable
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.coroutines.collectValues
+import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
+import com.android.systemui.qs.pipeline.domain.model.AutoAddTracking
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.android.systemui.util.settings.FakeSettings
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class AutoAddableSettingTest : SysuiTestCase() {
+
+ private val testDispatcher = StandardTestDispatcher()
+ private val testScope = TestScope(testDispatcher)
+
+ private val secureSettings = FakeSettings()
+ private val underTest =
+ AutoAddableSetting(
+ secureSettings,
+ testDispatcher,
+ SETTING,
+ SPEC,
+ )
+
+ @Test
+ fun settingNotSet_noSignal() =
+ testScope.runTest {
+ val userId = 0
+ val signal by collectLastValue(underTest.autoAddSignal(userId))
+
+ assertThat(signal).isNull() // null means no emitted value
+ }
+
+ @Test
+ fun settingSetTo0_noSignal() =
+ testScope.runTest {
+ val userId = 0
+ val signal by collectLastValue(underTest.autoAddSignal(userId))
+
+ secureSettings.putIntForUser(SETTING, 0, userId)
+
+ assertThat(signal).isNull() // null means no emitted value
+ }
+
+ @Test
+ fun settingSetToNon0_signal() =
+ testScope.runTest {
+ val userId = 0
+ val signal by collectLastValue(underTest.autoAddSignal(userId))
+
+ secureSettings.putIntForUser(SETTING, 42, userId)
+
+ assertThat(signal).isEqualTo(AutoAddSignal.Add(SPEC))
+ }
+
+ @Test
+ fun settingSetForUser_onlySignalInThatUser() =
+ testScope.runTest {
+ val signal0 by collectLastValue(underTest.autoAddSignal(0))
+ val signal1 by collectLastValue(underTest.autoAddSignal(1))
+
+ secureSettings.putIntForUser(SETTING, /* value */ 42, /* userHandle */ 1)
+
+ assertThat(signal0).isNull()
+ assertThat(signal1).isEqualTo(AutoAddSignal.Add(SPEC))
+ }
+
+ @Test
+ fun multipleNonZeroChanges_onlyOneSignal() =
+ testScope.runTest {
+ val userId = 0
+ val signals by collectValues(underTest.autoAddSignal(userId))
+
+ secureSettings.putIntForUser(SETTING, 1, userId)
+ secureSettings.putIntForUser(SETTING, 2, userId)
+
+ assertThat(signals.size).isEqualTo(1)
+ }
+
+ @Test
+ fun strategyIfNotAdded() {
+ assertThat(underTest.autoAddTracking).isEqualTo(AutoAddTracking.IfNotAdded(SPEC))
+ }
+
+ companion object {
+ private const val SETTING = "setting"
+ private val SPEC = TileSpec.create("spec")
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/CallbackControllerAutoAddableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/CallbackControllerAutoAddableTest.kt
new file mode 100644
index 0000000..afb43c7
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/CallbackControllerAutoAddableTest.kt
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.pipeline.domain.autoaddable
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
+import com.android.systemui.qs.pipeline.domain.model.AutoAddTracking
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.android.systemui.statusbar.policy.CallbackController
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.channels.ProducerScope
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class CallbackControllerAutoAddableTest : SysuiTestCase() {
+
+ @Test
+ fun callbackAddedAndRemoved() = runTest {
+ val controller = TestableController()
+ val callback = object : TestableController.Callback {}
+ val underTest =
+ object :
+ CallbackControllerAutoAddable<TestableController.Callback, TestableController>(
+ controller
+ ) {
+ override val description: String = ""
+ override val spec: TileSpec
+ get() = SPEC
+
+ override fun ProducerScope<AutoAddSignal>.getCallback():
+ TestableController.Callback {
+ return callback
+ }
+ }
+
+ val job = launch { underTest.autoAddSignal(0).collect {} }
+ runCurrent()
+ assertThat(controller.callbacks).containsExactly(callback)
+ job.cancel()
+ runCurrent()
+ assertThat(controller.callbacks).isEmpty()
+ }
+
+ @Test
+ fun sendAddFromCallback() = runTest {
+ val controller = TestableController()
+ val underTest =
+ object :
+ CallbackControllerAutoAddable<TestableController.Callback, TestableController>(
+ controller
+ ) {
+ override val description: String = ""
+
+ override val spec: TileSpec
+ get() = SPEC
+
+ override fun ProducerScope<AutoAddSignal>.getCallback():
+ TestableController.Callback {
+ return object : TestableController.Callback {
+ override fun change() {
+ sendAdd()
+ }
+ }
+ }
+ }
+
+ val signal by collectLastValue(underTest.autoAddSignal(0))
+ assertThat(signal).isNull()
+
+ controller.callbacks.first().change()
+
+ assertThat(signal).isEqualTo(AutoAddSignal.Add(SPEC))
+ }
+
+ @Test
+ fun strategyIfNotAdded() {
+ val underTest =
+ object :
+ CallbackControllerAutoAddable<TestableController.Callback, TestableController>(
+ TestableController()
+ ) {
+ override val description: String = ""
+ override val spec: TileSpec
+ get() = SPEC
+
+ override fun ProducerScope<AutoAddSignal>.getCallback():
+ TestableController.Callback {
+ return object : TestableController.Callback {}
+ }
+ }
+
+ assertThat(underTest.autoAddTracking).isEqualTo(AutoAddTracking.IfNotAdded(SPEC))
+ }
+
+ private class TestableController : CallbackController<TestableController.Callback> {
+
+ val callbacks = mutableSetOf<Callback>()
+
+ override fun addCallback(listener: Callback) {
+ callbacks.add(listener)
+ }
+
+ override fun removeCallback(listener: Callback) {
+ callbacks.remove(listener)
+ }
+
+ interface Callback {
+ fun change() {}
+ }
+ }
+
+ companion object {
+ private val SPEC = TileSpec.create("test")
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/CastAutoAddableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/CastAutoAddableTest.kt
new file mode 100644
index 0000000..a357dad
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/CastAutoAddableTest.kt
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.pipeline.domain.autoaddable
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.android.systemui.qs.tiles.CastTile
+import com.android.systemui.statusbar.policy.CastController
+import com.android.systemui.util.mockito.capture
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Captor
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class CastAutoAddableTest : SysuiTestCase() {
+
+ @Mock private lateinit var castController: CastController
+ @Captor private lateinit var callbackCaptor: ArgumentCaptor<CastController.Callback>
+
+ private lateinit var underTest: CastAutoAddable
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ underTest = CastAutoAddable(castController)
+ }
+
+ @Test
+ fun onCastDevicesChanged_noDevices_noSignal() = runTest {
+ val signal by collectLastValue(underTest.autoAddSignal(0))
+ runCurrent()
+
+ verify(castController).addCallback(capture(callbackCaptor))
+
+ callbackCaptor.value.onCastDevicesChanged()
+
+ assertThat(signal).isNull()
+ }
+
+ @Test
+ fun onCastDevicesChanged_deviceNotConnectedOrConnecting_noSignal() = runTest {
+ val device =
+ CastController.CastDevice().apply {
+ state = CastController.CastDevice.STATE_DISCONNECTED
+ }
+ whenever(castController.castDevices).thenReturn(listOf(device))
+
+ val signal by collectLastValue(underTest.autoAddSignal(0))
+ runCurrent()
+
+ verify(castController).addCallback(capture(callbackCaptor))
+
+ callbackCaptor.value.onCastDevicesChanged()
+
+ assertThat(signal).isNull()
+ }
+
+ @Test
+ fun onCastDevicesChanged_someDeviceConnecting_addSignal() = runTest {
+ val disconnectedDevice =
+ CastController.CastDevice().apply {
+ state = CastController.CastDevice.STATE_DISCONNECTED
+ }
+ val connectingDevice =
+ CastController.CastDevice().apply { state = CastController.CastDevice.STATE_CONNECTING }
+ whenever(castController.castDevices)
+ .thenReturn(listOf(disconnectedDevice, connectingDevice))
+
+ val signal by collectLastValue(underTest.autoAddSignal(0))
+ runCurrent()
+
+ verify(castController).addCallback(capture(callbackCaptor))
+
+ callbackCaptor.value.onCastDevicesChanged()
+
+ assertThat(signal).isEqualTo(AutoAddSignal.Add(SPEC))
+ }
+
+ @Test
+ fun onCastDevicesChanged_someDeviceConnected_addSignal() = runTest {
+ val disconnectedDevice =
+ CastController.CastDevice().apply {
+ state = CastController.CastDevice.STATE_DISCONNECTED
+ }
+ val connectedDevice =
+ CastController.CastDevice().apply { state = CastController.CastDevice.STATE_CONNECTED }
+ whenever(castController.castDevices).thenReturn(listOf(disconnectedDevice, connectedDevice))
+
+ val signal by collectLastValue(underTest.autoAddSignal(0))
+ runCurrent()
+
+ verify(castController).addCallback(capture(callbackCaptor))
+
+ callbackCaptor.value.onCastDevicesChanged()
+
+ assertThat(signal).isEqualTo(AutoAddSignal.Add(SPEC))
+ }
+
+ companion object {
+ private val SPEC = TileSpec.create(CastTile.TILE_SPEC)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/DataSaverAutoAddableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/DataSaverAutoAddableTest.kt
new file mode 100644
index 0000000..098ffc3
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/DataSaverAutoAddableTest.kt
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.pipeline.domain.autoaddable
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.android.systemui.qs.tiles.DataSaverTile
+import com.android.systemui.statusbar.policy.DataSaverController
+import com.android.systemui.util.mockito.capture
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Captor
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class DataSaverAutoAddableTest : SysuiTestCase() {
+
+ @Mock private lateinit var dataSaverController: DataSaverController
+ @Captor private lateinit var callbackCaptor: ArgumentCaptor<DataSaverController.Listener>
+
+ private lateinit var underTest: DataSaverAutoAddable
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ underTest = DataSaverAutoAddable(dataSaverController)
+ }
+
+ @Test
+ fun dataSaverNotEnabled_NoSignal() = runTest {
+ val signal by collectLastValue(underTest.autoAddSignal(0))
+ runCurrent()
+
+ verify(dataSaverController).addCallback(capture(callbackCaptor))
+
+ callbackCaptor.value.onDataSaverChanged(false)
+
+ assertThat(signal).isNull()
+ }
+
+ @Test
+ fun dataSaverEnabled_addSignal() = runTest {
+ val signal by collectLastValue(underTest.autoAddSignal(0))
+ runCurrent()
+
+ verify(dataSaverController).addCallback(capture(callbackCaptor))
+
+ callbackCaptor.value.onDataSaverChanged(true)
+
+ assertThat(signal).isEqualTo(AutoAddSignal.Add(SPEC))
+ }
+
+ companion object {
+ private val SPEC = TileSpec.create(DataSaverTile.TILE_SPEC)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/DeviceControlsAutoAddableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/DeviceControlsAutoAddableTest.kt
new file mode 100644
index 0000000..a2e3538
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/DeviceControlsAutoAddableTest.kt
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.pipeline.domain.autoaddable
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
+import com.android.systemui.qs.pipeline.domain.model.AutoAddTracking
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.android.systemui.qs.tiles.DeviceControlsTile
+import com.android.systemui.statusbar.policy.DeviceControlsController
+import com.android.systemui.util.mockito.capture
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Captor
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class DeviceControlsAutoAddableTest : SysuiTestCase() {
+
+ @Mock private lateinit var deviceControlsController: DeviceControlsController
+ @Captor private lateinit var callbackCaptor: ArgumentCaptor<DeviceControlsController.Callback>
+
+ private lateinit var underTest: DeviceControlsAutoAddable
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ underTest = DeviceControlsAutoAddable(deviceControlsController)
+ }
+
+ @Test
+ fun strategyAlways() {
+ assertThat(underTest.autoAddTracking).isEqualTo(AutoAddTracking.Always)
+ }
+
+ @Test
+ fun onControlsUpdate_position_addSignal() = runTest {
+ val signal by collectLastValue(underTest.autoAddSignal(0))
+ val position = 5
+ runCurrent()
+
+ verify(deviceControlsController).setCallback(capture(callbackCaptor))
+ callbackCaptor.value.onControlsUpdate(position)
+
+ assertThat(signal).isEqualTo(AutoAddSignal.Add(SPEC, position))
+ verify(deviceControlsController).removeCallback()
+ }
+
+ @Test
+ fun onControlsUpdate_nullPosition_noAddSignal() = runTest {
+ val signal by collectLastValue(underTest.autoAddSignal(0))
+ runCurrent()
+
+ verify(deviceControlsController).setCallback(capture(callbackCaptor))
+ callbackCaptor.value.onControlsUpdate(null)
+
+ assertThat(signal).isNull()
+ verify(deviceControlsController).removeCallback()
+ }
+
+ @Test
+ fun onRemoveControlsAutoTracker_removeSignal() = runTest {
+ val signal by collectLastValue(underTest.autoAddSignal(0))
+ runCurrent()
+
+ verify(deviceControlsController).setCallback(capture(callbackCaptor))
+ callbackCaptor.value.removeControlsAutoTracker()
+
+ assertThat(signal).isEqualTo(AutoAddSignal.Remove(SPEC))
+ }
+
+ @Test
+ fun flowCancelled_removeCallback() = runTest {
+ val job = launch { underTest.autoAddSignal(0).collect() }
+ runCurrent()
+
+ job.cancel()
+ runCurrent()
+ verify(deviceControlsController).removeCallback()
+ }
+
+ companion object {
+ private val SPEC = TileSpec.create(DeviceControlsTile.TILE_SPEC)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/HotspotAutoAddableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/HotspotAutoAddableTest.kt
new file mode 100644
index 0000000..ee96b47
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/HotspotAutoAddableTest.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.pipeline.domain.autoaddable
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.android.systemui.qs.tiles.HotspotTile
+import com.android.systemui.statusbar.policy.HotspotController
+import com.android.systemui.util.mockito.capture
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Captor
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class HotspotAutoAddableTest : SysuiTestCase() {
+
+ @Mock private lateinit var hotspotController: HotspotController
+ @Captor private lateinit var callbackCaptor: ArgumentCaptor<HotspotController.Callback>
+
+ private lateinit var underTest: HotspotAutoAddable
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ underTest = HotspotAutoAddable(hotspotController)
+ }
+
+ @Test
+ fun enabled_addSignal() = runTest {
+ val signal by collectLastValue(underTest.autoAddSignal(0))
+ runCurrent()
+
+ verify(hotspotController).addCallback(capture(callbackCaptor))
+ callbackCaptor.value.onHotspotChanged(/* enabled = */ true, /* numDevices = */ 5)
+
+ assertThat(signal).isEqualTo(AutoAddSignal.Add(SPEC))
+ }
+
+ @Test
+ fun notEnabled_noSignal() = runTest {
+ val signal by collectLastValue(underTest.autoAddSignal(0))
+ runCurrent()
+
+ verify(hotspotController).addCallback(capture(callbackCaptor))
+ callbackCaptor.value.onHotspotChanged(/* enabled = */ false, /* numDevices = */ 0)
+
+ assertThat(signal).isNull()
+ }
+
+ companion object {
+ private val SPEC = TileSpec.create(HotspotTile.TILE_SPEC)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/NightDisplayAutoAddableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/NightDisplayAutoAddableTest.kt
new file mode 100644
index 0000000..e03072a
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/NightDisplayAutoAddableTest.kt
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.pipeline.domain.autoaddable
+
+import android.hardware.display.NightDisplayListener
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.dagger.NightDisplayListenerModule
+import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
+import com.android.systemui.qs.pipeline.domain.model.AutoAddTracking
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.android.systemui.qs.tiles.NightDisplayTile
+import com.android.systemui.util.mockito.capture
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.TestResult
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Answers
+import org.mockito.ArgumentCaptor
+import org.mockito.Captor
+import org.mockito.Mock
+import org.mockito.Mockito.inOrder
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class NightDisplayAutoAddableTest : SysuiTestCase() {
+
+ @Mock(answer = Answers.RETURNS_SELF)
+ private lateinit var nightDisplayListenerBuilder: NightDisplayListenerModule.Builder
+ @Mock private lateinit var nightDisplayListener: NightDisplayListener
+ @Captor private lateinit var callbackCaptor: ArgumentCaptor<NightDisplayListener.Callback>
+
+ private lateinit var underTest: NightDisplayAutoAddable
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ whenever(nightDisplayListenerBuilder.build()).thenReturn(nightDisplayListener)
+ }
+
+ @Test
+ fun disabled_strategyDisabled() =
+ testWithFeatureAvailability(enabled = false) {
+ assertThat(underTest.autoAddTracking).isEqualTo(AutoAddTracking.Disabled)
+ }
+
+ @Test
+ fun enabled_strategyIfNotAdded() = testWithFeatureAvailability {
+ assertThat(underTest.autoAddTracking).isEqualTo(AutoAddTracking.IfNotAdded(SPEC))
+ }
+
+ @Test
+ fun listenerCreatedForCorrectUser() = testWithFeatureAvailability {
+ val user = 42
+ backgroundScope.launch { underTest.autoAddSignal(user).collect() }
+ runCurrent()
+
+ val inOrder = inOrder(nightDisplayListenerBuilder)
+ inOrder.verify(nightDisplayListenerBuilder).setUser(user)
+ inOrder.verify(nightDisplayListenerBuilder).build()
+ }
+
+ @Test
+ fun onCancelFlow_removeCallback() = testWithFeatureAvailability {
+ val job = launch { underTest.autoAddSignal(0).collect() }
+ runCurrent()
+ job.cancel()
+ runCurrent()
+ verify(nightDisplayListener).setCallback(null)
+ }
+
+ @Test
+ fun onActivatedTrue_addSignal() = testWithFeatureAvailability {
+ val signal by collectLastValue(underTest.autoAddSignal(0))
+ runCurrent()
+
+ verify(nightDisplayListener).setCallback(capture(callbackCaptor))
+ callbackCaptor.value.onActivated(true)
+
+ assertThat(signal).isEqualTo(AutoAddSignal.Add(SPEC))
+ }
+
+ private fun testWithFeatureAvailability(
+ enabled: Boolean = true,
+ body: suspend TestScope.() -> TestResult
+ ) = runTest {
+ context.orCreateTestableResources.addOverride(
+ com.android.internal.R.bool.config_nightDisplayAvailable,
+ enabled
+ )
+ underTest = NightDisplayAutoAddable(nightDisplayListenerBuilder, context)
+ body()
+ }
+
+ companion object {
+ private val SPEC = TileSpec.create(NightDisplayTile.TILE_SPEC)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/ReduceBrightColorsAutoAddableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/ReduceBrightColorsAutoAddableTest.kt
new file mode 100644
index 0000000..7b4a55e
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/ReduceBrightColorsAutoAddableTest.kt
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.pipeline.domain.autoaddable
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.qs.ReduceBrightColorsController
+import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
+import com.android.systemui.qs.pipeline.domain.model.AutoAddTracking
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.android.systemui.qs.tiles.ReduceBrightColorsTile
+import com.android.systemui.util.mockito.capture
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestResult
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Captor
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class ReduceBrightColorsAutoAddableTest : SysuiTestCase() {
+
+ @Mock private lateinit var reduceBrightColorsController: ReduceBrightColorsController
+ @Captor
+ private lateinit var reduceBrightColorsListenerCaptor:
+ ArgumentCaptor<ReduceBrightColorsController.Listener>
+
+ private lateinit var underTest: ReduceBrightColorsAutoAddable
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ }
+
+ @Test
+ fun notAvailable_strategyDisabled() =
+ testWithFeatureAvailability(available = false) {
+ assertThat(underTest.autoAddTracking).isEqualTo(AutoAddTracking.Disabled)
+ }
+
+ @Test
+ fun available_strategyIfNotAdded() =
+ testWithFeatureAvailability(available = true) {
+ assertThat(underTest.autoAddTracking).isEqualTo(AutoAddTracking.IfNotAdded(SPEC))
+ }
+
+ @Test
+ fun activated_addSignal() = testWithFeatureAvailability {
+ val signal by collectLastValue(underTest.autoAddSignal(0))
+ runCurrent()
+
+ verify(reduceBrightColorsController).addCallback(capture(reduceBrightColorsListenerCaptor))
+
+ reduceBrightColorsListenerCaptor.value.onActivated(true)
+
+ assertThat(signal).isEqualTo(AutoAddSignal.Add(SPEC))
+ }
+
+ @Test
+ fun notActivated_noSignal() = testWithFeatureAvailability {
+ val signal by collectLastValue(underTest.autoAddSignal(0))
+ runCurrent()
+
+ verify(reduceBrightColorsController).addCallback(capture(reduceBrightColorsListenerCaptor))
+
+ reduceBrightColorsListenerCaptor.value.onActivated(false)
+
+ assertThat(signal).isNull()
+ }
+
+ private fun testWithFeatureAvailability(
+ available: Boolean = true,
+ body: suspend TestScope.() -> TestResult
+ ) = runTest {
+ underTest = ReduceBrightColorsAutoAddable(reduceBrightColorsController, available)
+ body()
+ }
+
+ companion object {
+ private val SPEC = TileSpec.create(ReduceBrightColorsTile.TILE_SPEC)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/SafetyCenterAutoAddableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/SafetyCenterAutoAddableTest.kt
new file mode 100644
index 0000000..fb35a3a
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/SafetyCenterAutoAddableTest.kt
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.pipeline.domain.autoaddable
+
+import android.content.ComponentName
+import android.content.pm.PackageManager
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.coroutines.collectValues
+import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
+import com.android.systemui.qs.pipeline.domain.model.AutoAddTracking
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.android.systemui.statusbar.policy.SafetyController
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.capture
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Captor
+import org.mockito.Mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class SafetyCenterAutoAddableTest : SysuiTestCase() {
+ private val testDispatcher = StandardTestDispatcher()
+ private val testScope = TestScope(testDispatcher)
+
+ @Mock private lateinit var safetyController: SafetyController
+ @Mock private lateinit var packageManager: PackageManager
+ @Captor
+ private lateinit var safetyControllerListenerCaptor: ArgumentCaptor<SafetyController.Listener>
+
+ private lateinit var underTest: SafetyCenterAutoAddable
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ context.ensureTestableResources()
+
+ // Set these by default, will also test special cases
+ context.orCreateTestableResources.addOverride(
+ R.string.safety_quick_settings_tile_class,
+ SAFETY_TILE_CLASS_NAME
+ )
+ whenever(packageManager.permissionControllerPackageName)
+ .thenReturn(PERMISSION_CONTROLLER_PACKAGE_NAME)
+
+ underTest =
+ SafetyCenterAutoAddable(
+ safetyController,
+ packageManager,
+ context.resources,
+ testDispatcher,
+ )
+ }
+
+ @Test
+ fun strategyAlwaysTrack() =
+ testScope.runTest {
+ assertThat(underTest.autoAddTracking).isEqualTo(AutoAddTracking.Always)
+ }
+
+ @Test
+ fun tileAlwaysAdded() =
+ testScope.runTest {
+ val signal by collectLastValue(underTest.autoAddSignal(0))
+
+ assertThat(signal).isEqualTo(AutoAddSignal.Add(SPEC))
+ }
+
+ @Test
+ fun safetyCenterDisabled_removeSignal() =
+ testScope.runTest {
+ val signal by collectLastValue(underTest.autoAddSignal(0))
+ runCurrent()
+
+ verify(safetyController).addCallback(capture(safetyControllerListenerCaptor))
+ safetyControllerListenerCaptor.value.onSafetyCenterEnableChanged(false)
+
+ assertThat(signal).isEqualTo(AutoAddSignal.Remove(SPEC))
+ }
+
+ @Test
+ fun safetyCenterEnabled_newAddSignal() =
+ testScope.runTest {
+ val signals by collectValues(underTest.autoAddSignal(0))
+ runCurrent()
+
+ verify(safetyController).addCallback(capture(safetyControllerListenerCaptor))
+ safetyControllerListenerCaptor.value.onSafetyCenterEnableChanged(true)
+
+ assertThat(signals.size).isEqualTo(2)
+ assertThat(signals.last()).isEqualTo(AutoAddSignal.Add(SPEC))
+ }
+
+ @Test
+ fun flowCancelled_removeListener() =
+ testScope.runTest {
+ val job = launch { underTest.autoAddSignal(0).collect() }
+ runCurrent()
+
+ verify(safetyController).addCallback(capture(safetyControllerListenerCaptor))
+
+ job.cancel()
+ runCurrent()
+ verify(safetyController).removeCallback(safetyControllerListenerCaptor.value)
+ }
+
+ @Test
+ fun emptyClassName_noSignals() =
+ testScope.runTest {
+ context.orCreateTestableResources.addOverride(
+ R.string.safety_quick_settings_tile_class,
+ ""
+ )
+ val signal by collectLastValue(underTest.autoAddSignal(0))
+ runCurrent()
+
+ verify(safetyController, never()).addCallback(any())
+
+ assertThat(signal).isNull()
+ }
+
+ companion object {
+ private const val SAFETY_TILE_CLASS_NAME = "cls"
+ private const val PERMISSION_CONTROLLER_PACKAGE_NAME = "pkg"
+ private val SPEC =
+ TileSpec.create(
+ ComponentName(PERMISSION_CONTROLLER_PACKAGE_NAME, SAFETY_TILE_CLASS_NAME)
+ )
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/WalletAutoAddableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/WalletAutoAddableTest.kt
new file mode 100644
index 0000000..6b250f4
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/WalletAutoAddableTest.kt
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.pipeline.domain.autoaddable
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
+import com.android.systemui.qs.pipeline.domain.model.AutoAddTracking
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.android.systemui.qs.tiles.QuickAccessWalletTile
+import com.android.systemui.statusbar.policy.WalletController
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class WalletAutoAddableTest : SysuiTestCase() {
+
+ @Mock private lateinit var walletController: WalletController
+
+ private lateinit var underTest: WalletAutoAddable
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ underTest = WalletAutoAddable(walletController)
+ }
+
+ @Test
+ fun strategyIfNotAdded() {
+ assertThat(underTest.autoAddTracking).isEqualTo(AutoAddTracking.IfNotAdded(SPEC))
+ }
+
+ @Test
+ fun walletPositionNull_noSignal() = runTest {
+ whenever(walletController.getWalletPosition()).thenReturn(null)
+
+ val signal by collectLastValue(underTest.autoAddSignal(0))
+
+ assertThat(signal).isNull()
+ }
+
+ @Test
+ fun walletPositionNumber_addedInThatPosition() = runTest {
+ val position = 4
+ whenever(walletController.getWalletPosition()).thenReturn(4)
+
+ val signal by collectLastValue(underTest.autoAddSignal(0))
+
+ assertThat(signal).isEqualTo(AutoAddSignal.Add(SPEC, position))
+ }
+
+ companion object {
+ private val SPEC = TileSpec.create(QuickAccessWalletTile.TILE_SPEC)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/WorkTileAutoAddableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/WorkTileAutoAddableTest.kt
new file mode 100644
index 0000000..e9f7c8ab
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/autoaddable/WorkTileAutoAddableTest.kt
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.pipeline.domain.autoaddable
+
+import android.content.pm.UserInfo
+import android.content.pm.UserInfo.FLAG_FULL
+import android.content.pm.UserInfo.FLAG_MANAGED_PROFILE
+import android.content.pm.UserInfo.FLAG_PRIMARY
+import android.content.pm.UserInfo.FLAG_PROFILE
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
+import com.android.systemui.qs.pipeline.domain.model.AutoAddTracking
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.android.systemui.qs.tiles.WorkModeTile
+import com.android.systemui.settings.FakeUserTracker
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.MockitoAnnotations
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class WorkTileAutoAddableTest : SysuiTestCase() {
+
+ private lateinit var userTracker: FakeUserTracker
+
+ private lateinit var underTest: WorkTileAutoAddable
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+
+ userTracker =
+ FakeUserTracker(
+ _userId = USER_INFO_0.id,
+ _userInfo = USER_INFO_0,
+ _userProfiles = listOf(USER_INFO_0)
+ )
+
+ underTest = WorkTileAutoAddable(userTracker)
+ }
+
+ @Test
+ fun changeInProfiles_hasManagedProfile_sendsAddSignal() = runTest {
+ val signal by collectLastValue(underTest.autoAddSignal(0))
+
+ userTracker.set(listOf(USER_INFO_0, USER_INFO_WORK), selectedUserIndex = 0)
+
+ assertThat(signal).isEqualTo(AutoAddSignal.Add(SPEC))
+ }
+
+ @Test
+ fun changeInProfiles_noManagedProfile_sendsRemoveSignal() = runTest {
+ userTracker.set(listOf(USER_INFO_0, USER_INFO_WORK), selectedUserIndex = 0)
+
+ val signal by collectLastValue(underTest.autoAddSignal(0))
+
+ userTracker.set(listOf(USER_INFO_0), selectedUserIndex = 0)
+
+ assertThat(signal).isEqualTo(AutoAddSignal.Remove(SPEC))
+ }
+
+ @Test
+ fun startingWithManagedProfile_sendsAddSignal() = runTest {
+ userTracker.set(listOf(USER_INFO_0, USER_INFO_WORK), selectedUserIndex = 0)
+
+ val signal by collectLastValue(underTest.autoAddSignal(0))
+
+ assertThat(signal).isEqualTo(AutoAddSignal.Add(SPEC))
+ }
+
+ @Test
+ fun userChangeToUserWithProfile_noSignalForOriginalUser() = runTest {
+ val signal by collectLastValue(underTest.autoAddSignal(0))
+
+ userTracker.set(listOf(USER_INFO_1, USER_INFO_WORK), selectedUserIndex = 0)
+
+ assertThat(signal).isNotEqualTo(AutoAddSignal.Add(SPEC))
+ }
+
+ @Test
+ fun userChangeToUserWithoutProfile_noSignalForOriginalUser() = runTest {
+ userTracker.set(listOf(USER_INFO_0, USER_INFO_WORK), selectedUserIndex = 0)
+ val signal by collectLastValue(underTest.autoAddSignal(0))
+
+ userTracker.set(listOf(USER_INFO_1), selectedUserIndex = 0)
+
+ assertThat(signal).isNotEqualTo(AutoAddSignal.Remove(SPEC))
+ }
+
+ @Test
+ fun strategyAlways() {
+ assertThat(underTest.autoAddTracking).isEqualTo(AutoAddTracking.Always)
+ }
+
+ companion object {
+ private val SPEC = TileSpec.create(WorkModeTile.TILE_SPEC)
+ private val USER_INFO_0 = UserInfo(0, "", FLAG_PRIMARY or FLAG_FULL)
+ private val USER_INFO_1 = UserInfo(1, "", FLAG_FULL)
+ private val USER_INFO_WORK = UserInfo(10, "", FLAG_PROFILE or FLAG_MANAGED_PROFILE)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractorTest.kt
new file mode 100644
index 0000000..f924b35
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractorTest.kt
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.pipeline.domain.interactor
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.qs.pipeline.data.repository.FakeAutoAddRepository
+import com.android.systemui.qs.pipeline.domain.autoaddable.FakeAutoAddable
+import com.android.systemui.qs.pipeline.domain.model.AutoAddTracking
+import com.android.systemui.qs.pipeline.domain.model.AutoAddable
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.android.systemui.qs.pipeline.shared.logging.QSPipelineLogger
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.Mock
+import org.mockito.Mockito.inOrder
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@OptIn(ExperimentalCoroutinesApi::class)
+class AutoAddInteractorTest : SysuiTestCase() {
+ private val testScope = TestScope()
+
+ private val autoAddRepository = FakeAutoAddRepository()
+
+ @Mock private lateinit var dumpManager: DumpManager
+ @Mock private lateinit var currentTilesInteractor: CurrentTilesInteractor
+ @Mock private lateinit var logger: QSPipelineLogger
+ private lateinit var underTest: AutoAddInteractor
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ whenever(currentTilesInteractor.userId).thenReturn(MutableStateFlow(USER))
+ }
+
+ @Test
+ fun autoAddable_alwaysTrack_addSignal_tileAddedAndMarked() =
+ testScope.runTest {
+ val fakeAutoAddable = FakeAutoAddable(SPEC, AutoAddTracking.Always)
+ val autoAddedTiles by collectLastValue(autoAddRepository.autoAddedTiles(USER))
+
+ underTest = createInteractor(setOf(fakeAutoAddable))
+
+ val position = 3
+ fakeAutoAddable.sendAddSignal(USER, position)
+ runCurrent()
+
+ verify(currentTilesInteractor).addTile(SPEC, position)
+ assertThat(autoAddedTiles).contains(SPEC)
+ }
+
+ @Test
+ fun autoAddable_alwaysTrack_addThenRemoveSignal_tileAddedAndRemoved() =
+ testScope.runTest {
+ val fakeAutoAddable = FakeAutoAddable(SPEC, AutoAddTracking.Always)
+ val autoAddedTiles by collectLastValue(autoAddRepository.autoAddedTiles(USER))
+
+ underTest = createInteractor(setOf(fakeAutoAddable))
+
+ val position = 3
+ fakeAutoAddable.sendAddSignal(USER, position)
+ runCurrent()
+ fakeAutoAddable.sendRemoveSignal(USER)
+ runCurrent()
+
+ val inOrder = inOrder(currentTilesInteractor)
+ inOrder.verify(currentTilesInteractor).addTile(SPEC, position)
+ inOrder.verify(currentTilesInteractor).removeTiles(setOf(SPEC))
+ assertThat(autoAddedTiles).doesNotContain(SPEC)
+ }
+
+ @Test
+ fun autoAddable_alwaysTrack_addSignalWhenAddedPreviously_noop() =
+ testScope.runTest {
+ val fakeAutoAddable = FakeAutoAddable(SPEC, AutoAddTracking.Always)
+ autoAddRepository.markTileAdded(USER, SPEC)
+ runCurrent()
+
+ underTest = createInteractor(setOf(fakeAutoAddable))
+
+ val position = 3
+ fakeAutoAddable.sendAddSignal(USER, position)
+ runCurrent()
+
+ verify(currentTilesInteractor, never()).addTile(SPEC, position)
+ }
+
+ @Test
+ fun autoAddable_disabled_noInteractionsWithCurrentTilesInteractor() =
+ testScope.runTest {
+ val fakeAutoAddable = FakeAutoAddable(SPEC, AutoAddTracking.Disabled)
+ val autoAddedTiles by collectLastValue(autoAddRepository.autoAddedTiles(USER))
+
+ underTest = createInteractor(setOf(fakeAutoAddable))
+
+ val position = 3
+ fakeAutoAddable.sendAddSignal(USER, position)
+ runCurrent()
+ fakeAutoAddable.sendRemoveSignal(USER)
+ runCurrent()
+
+ verify(currentTilesInteractor, never()).addTile(any(), anyInt())
+ verify(currentTilesInteractor, never()).removeTiles(any())
+ assertThat(autoAddedTiles).doesNotContain(SPEC)
+ }
+
+ @Test
+ fun autoAddable_trackIfNotAdded_removeSignal_noop() =
+ testScope.runTest {
+ val fakeAutoAddable = FakeAutoAddable(SPEC, AutoAddTracking.IfNotAdded(SPEC))
+ runCurrent()
+
+ underTest = createInteractor(setOf(fakeAutoAddable))
+
+ fakeAutoAddable.sendRemoveSignal(USER)
+ runCurrent()
+
+ verify(currentTilesInteractor, never()).addTile(any(), anyInt())
+ verify(currentTilesInteractor, never()).removeTiles(any())
+ }
+
+ @Test
+ fun autoAddable_trackIfNotAdded_addSignalWhenPreviouslyAdded_noop() =
+ testScope.runTest {
+ val fakeAutoAddable = FakeAutoAddable(SPEC, AutoAddTracking.IfNotAdded(SPEC))
+ autoAddRepository.markTileAdded(USER, SPEC)
+ runCurrent()
+
+ underTest = createInteractor(setOf(fakeAutoAddable))
+
+ fakeAutoAddable.sendAddSignal(USER)
+ runCurrent()
+
+ verify(currentTilesInteractor, never()).addTile(any(), anyInt())
+ verify(currentTilesInteractor, never()).removeTiles(any())
+ }
+
+ @Test
+ fun autoAddable_trackIfNotAdded_addSignal_addedAndMarked() =
+ testScope.runTest {
+ val fakeAutoAddable = FakeAutoAddable(SPEC, AutoAddTracking.IfNotAdded(SPEC))
+ val autoAddedTiles by collectLastValue(autoAddRepository.autoAddedTiles(USER))
+
+ underTest = createInteractor(setOf(fakeAutoAddable))
+
+ val position = 3
+ fakeAutoAddable.sendAddSignal(USER, position)
+ runCurrent()
+
+ verify(currentTilesInteractor).addTile(SPEC, position)
+ assertThat(autoAddedTiles).contains(SPEC)
+ }
+
+ private fun createInteractor(autoAddables: Set<AutoAddable>): AutoAddInteractor {
+ return AutoAddInteractor(
+ autoAddables,
+ autoAddRepository,
+ dumpManager,
+ logger,
+ testScope.backgroundScope
+ )
+ .apply { init(currentTilesInteractor) }
+ }
+
+ companion object {
+ private val SPEC = TileSpec.create("spec")
+ private val USER = 10
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt
index e7ad489..30cea2d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt
@@ -100,6 +100,7 @@
MockitoAnnotations.initMocks(this)
featureFlags.set(Flags.QS_PIPELINE_NEW_HOST, true)
+ featureFlags.set(Flags.QS_PIPELINE_AUTO_ADD, true)
userRepository.setUserInfos(listOf(USER_INFO_0, USER_INFO_1))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileViewImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileViewImplTest.kt
index 28aeba4..3c66772 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileViewImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileViewImplTest.kt
@@ -22,6 +22,7 @@
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.text.TextUtils
+import android.view.ContextThemeWrapper
import android.view.View
import android.view.accessibility.AccessibilityNodeInfo
import android.widget.TextView
@@ -386,7 +387,11 @@
context: Context,
icon: QSIconView,
collapsed: Boolean
- ) : QSTileViewImpl(context, icon, collapsed) {
+ ) : QSTileViewImpl(
+ ContextThemeWrapper(context, R.style.Theme_SystemUI_QuickSettings),
+ icon,
+ collapsed
+ ) {
fun changeState(state: QSTile.State) {
handleStateChanged(state)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DndTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DndTileTest.kt
index f0e4e3a..77a4436 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DndTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DndTileTest.kt
@@ -25,6 +25,7 @@
import android.provider.Settings.Global.ZEN_MODE_OFF
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import android.view.ContextThemeWrapper
import android.view.View
import androidx.test.filters.SmallTest
import com.android.internal.logging.MetricsLogger
@@ -110,7 +111,9 @@
whenever(qsHost.userId).thenReturn(DEFAULT_USER)
- val wrappedContext = object : ContextWrapper(context) {
+ val wrappedContext = object : ContextWrapper(
+ ContextThemeWrapper(context, R.style.Theme_SystemUI_QuickSettings)
+ ) {
override fun getSharedPreferences(file: File?, mode: Int): SharedPreferences {
return sharedPreferences
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt
index 05a1699..c85c8ba 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt
@@ -27,7 +27,6 @@
import com.android.systemui.scene.shared.model.SceneModel
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Test
@@ -39,8 +38,8 @@
@RunWith(JUnit4::class)
class QuickSettingsSceneViewModelTest : SysuiTestCase() {
- private val testScope = TestScope()
- private val utils = SceneTestUtils(this, testScope)
+ private val utils = SceneTestUtils(this)
+ private val testScope = utils.testScope
private val sceneInteractor = utils.sceneInteractor()
private val authenticationInteractor =
utils.authenticationInteractor(
@@ -70,8 +69,10 @@
fun onContentClicked_deviceUnlocked_switchesToGone() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
- authenticationInteractor.unlockDevice()
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
+ utils.authenticationRepository.setUnlocked(true)
runCurrent()
underTest.onContentClicked()
@@ -83,8 +84,10 @@
fun onContentClicked_deviceLockedSecurely_switchesToBouncer() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
- authenticationInteractor.lockDevice()
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
+ utils.authenticationRepository.setUnlocked(false)
runCurrent()
underTest.onContentClicked()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
index ef7c7bc..9188293 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -80,6 +80,7 @@
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.biometrics.AuthController;
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.common.ui.view.LongPressHandlingView;
@@ -91,7 +92,6 @@
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.KeyguardViewConfigurator;
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository;
-import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
@@ -629,7 +629,7 @@
mHeadsUpManager);
mNotificationPanelViewController.setTrackingStartedListener(() -> {});
mNotificationPanelViewController.setOpenCloseListener(
- new NotificationPanelViewController.OpenCloseListener() {
+ new OpenCloseListener() {
@Override
public void onClosingFinished() {}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeControllerImplTest.kt
index 00a0567..729c4a9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeControllerImplTest.kt
@@ -56,7 +56,7 @@
@Mock private lateinit var windowManager: WindowManager
@Mock private lateinit var assistManager: AssistManager
@Mock private lateinit var gutsManager: NotificationGutsManager
- @Mock private lateinit var notificationPanelViewController: NotificationPanelViewController
+ @Mock private lateinit var shadeViewController: ShadeViewController
@Mock private lateinit var nswvc: NotificationShadeWindowViewController
@Mock private lateinit var display: Display
@@ -82,7 +82,7 @@
Lazy { gutsManager },
)
shadeController.setNotificationShadeWindowViewController(nswvc)
- shadeController.setNotificationPanelViewController(notificationPanelViewController)
+ shadeController.setShadeViewController(shadeViewController)
}
@Test
@@ -91,9 +91,9 @@
// Trying to open it does nothing.
shadeController.animateExpandShade()
- verify(notificationPanelViewController, never()).expandToNotifications()
+ verify(shadeViewController, never()).expandToNotifications()
shadeController.animateExpandQs()
- verify(notificationPanelViewController, never()).expand(ArgumentMatchers.anyBoolean())
+ verify(shadeViewController, never()).expand(ArgumentMatchers.anyBoolean())
}
@Test
@@ -102,15 +102,15 @@
// Can now be opened.
shadeController.animateExpandShade()
- verify(notificationPanelViewController).expandToNotifications()
+ verify(shadeViewController).expandToNotifications()
shadeController.animateExpandQs()
- verify(notificationPanelViewController).expandToQs()
+ verify(shadeViewController).expandToQs()
}
@Test
fun cancelExpansionAndCollapseShade_callsCancelCurrentTouch() {
// GIVEN the shade is tracking a touch
- whenever(notificationPanelViewController.isTracking).thenReturn(true)
+ whenever(shadeViewController.isTracking).thenReturn(true)
// WHEN cancelExpansionAndCollapseShade is called
shadeController.cancelExpansionAndCollapseShade()
@@ -122,7 +122,7 @@
@Test
fun cancelExpansionAndCollapseShade_doesNotCallAnimateCollapseShade_whenCollapsed() {
// GIVEN the shade is tracking a touch
- whenever(notificationPanelViewController.isTracking).thenReturn(false)
+ whenever(shadeViewController.isTracking).thenReturn(false)
// WHEN cancelExpansionAndCollapseShade is called
shadeController.cancelExpansionAndCollapseShade()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt
index 2da2e92..f542ab0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt
@@ -237,11 +237,22 @@
whenever(mShadeCarrierGroupController.isSingleCarrier).thenReturn(false)
makeShadeVisible()
+ shadeHeaderController.qsExpandedFraction = 1.0f
verify(statusIcons).addIgnoredSlots(carrierIconSlots)
}
@Test
+ fun dualCarrier_enablesCarrierIconsInStatusIcons_qsExpanded() {
+ whenever(mShadeCarrierGroupController.isSingleCarrier).thenReturn(false)
+
+ makeShadeVisible()
+ shadeHeaderController.qsExpandedFraction = 0.0f
+
+ verify(statusIcons, times(2)).removeIgnoredSlots(carrierIconSlots)
+ }
+
+ @Test
fun disableQS_notDisabled_visible() {
makeShadeVisible()
shadeHeaderController.disable(0, 0, false)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierTest.java
index 4461310..dae9c97 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierTest.java
@@ -20,8 +20,10 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import android.content.Context;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
@@ -48,7 +50,9 @@
@Before
public void setUp() throws Exception {
mTestableLooper = TestableLooper.get(this);
- LayoutInflater inflater = LayoutInflater.from(mContext);
+ Context themedContext =
+ new ContextThemeWrapper(mContext, R.style.Theme_SystemUI_QuickSettings);
+ LayoutInflater inflater = LayoutInflater.from(themedContext);
mContext.ensureTestableResources();
mTestableLooper.runWithLooper(() ->
mShadeCarrier = (ShadeCarrier) inflater.inflate(R.layout.shade_carrier, null));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
index f8e1a9d..5d2d192 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
@@ -27,7 +27,6 @@
import com.android.systemui.scene.shared.model.SceneModel
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Test
@@ -39,8 +38,8 @@
@RunWith(JUnit4::class)
class ShadeSceneViewModelTest : SysuiTestCase() {
- private val testScope = TestScope()
- private val utils = SceneTestUtils(this, testScope)
+ private val utils = SceneTestUtils(this)
+ private val testScope = utils.testScope
private val sceneInteractor = utils.sceneInteractor()
private val authenticationInteractor =
utils.authenticationInteractor(
@@ -71,8 +70,10 @@
fun upTransitionSceneKey_deviceLocked_lockScreen() =
testScope.runTest {
val upTransitionSceneKey by collectLastValue(underTest.upDestinationSceneKey)
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
- authenticationInteractor.lockDevice()
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
+ utils.authenticationRepository.setUnlocked(false)
assertThat(upTransitionSceneKey).isEqualTo(SceneKey.Lockscreen)
}
@@ -81,8 +82,10 @@
fun upTransitionSceneKey_deviceUnlocked_gone() =
testScope.runTest {
val upTransitionSceneKey by collectLastValue(underTest.upDestinationSceneKey)
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
- authenticationInteractor.unlockDevice()
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
+ utils.authenticationRepository.setUnlocked(true)
assertThat(upTransitionSceneKey).isEqualTo(SceneKey.Gone)
}
@@ -91,8 +94,10 @@
fun onContentClicked_deviceUnlocked_switchesToGone() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
- authenticationInteractor.unlockDevice()
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
+ utils.authenticationRepository.setUnlocked(true)
runCurrent()
underTest.onContentClicked()
@@ -104,8 +109,10 @@
fun onContentClicked_deviceLockedSecurely_switchesToBouncer() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
- authenticationInteractor.setAuthenticationMethod(AuthenticationMethodModel.Pin(1234))
- authenticationInteractor.lockDevice()
+ utils.authenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.Pin(1234)
+ )
+ utils.authenticationRepository.setUnlocked(false)
runCurrent()
underTest.onContentClicked()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
index 385d556..1643e17 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
@@ -16,6 +16,7 @@
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
import static android.inputmethodservice.InputMethodService.BACK_DISPOSITION_DEFAULT;
+import static android.inputmethodservice.InputMethodService.IME_INVISIBLE;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowInsetsController.BEHAVIOR_DEFAULT;
@@ -200,7 +201,7 @@
mCommandQueue.setImeWindowStatus(SECONDARY_DISPLAY, null, 1, 2, true);
waitForIdleSync();
- verify(mCallbacks).setImeWindowStatus(eq(DEFAULT_DISPLAY), eq(null), eq(0),
+ verify(mCallbacks).setImeWindowStatus(eq(DEFAULT_DISPLAY), eq(null), eq(IME_INVISIBLE),
eq(BACK_DISPOSITION_DEFAULT), eq(false));
verify(mCallbacks).setImeWindowStatus(
eq(SECONDARY_DISPLAY), eq(null), eq(1), eq(2), eq(true));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImplTest.kt
index 914301f..2af0ceb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImplTest.kt
@@ -69,6 +69,8 @@
@Mock private lateinit var listener: SystemStatusAnimationCallback
+ @Mock private lateinit var logger: SystemStatusAnimationSchedulerLogger
+
private lateinit var systemClock: FakeSystemClock
private lateinit var chipAnimationController: SystemEventChipAnimationController
private lateinit var systemStatusAnimationScheduler: SystemStatusAnimationScheduler
@@ -538,7 +540,8 @@
statusBarWindowController,
dumpManager,
systemClock,
- CoroutineScope(StandardTestDispatcher(testScope.testScheduler))
+ CoroutineScope(StandardTestDispatcher(testScope.testScheduler)),
+ logger
)
// add a mock listener
systemStatusAnimationScheduler.addCallback(listener)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLoggerTest.kt
index a37c386..902dd51 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLoggerTest.kt
@@ -20,8 +20,8 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
import com.android.systemui.log.LogcatEchoTracker
+import com.android.systemui.log.core.LogLevel
import com.android.systemui.statusbar.StatusBarState
import com.google.common.truth.Truth.assertThat
import org.junit.Before
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/StackStateLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/StackStateLoggerTest.kt
index 7707a7e..47c5e5b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/StackStateLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/StackStateLoggerTest.kt
@@ -20,8 +20,8 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
import com.android.systemui.log.LogcatEchoTracker
+import com.android.systemui.log.core.LogLevel
import com.android.systemui.statusbar.notification.stack.StackStateLogger
import com.google.common.truth.Truth
import org.junit.Before
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
index e680a4e..e4a2236 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
@@ -34,6 +34,7 @@
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import android.content.ComponentName;
@@ -51,6 +52,7 @@
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.dagger.NightDisplayListenerModule;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.qs.AutoAddTracker;
import com.android.systemui.qs.QSHost;
@@ -111,6 +113,8 @@
@Mock private DataSaverController mDataSaverController;
@Mock private ManagedProfileController mManagedProfileController;
@Mock private NightDisplayListener mNightDisplayListener;
+ @Mock(answer = Answers.RETURNS_SELF)
+ private NightDisplayListenerModule.Builder mNightDisplayListenerBuilder;
@Mock private ReduceBrightColorsController mReduceBrightColorsController;
@Mock private DeviceControlsController mDeviceControlsController;
@Mock private WalletController mWalletController;
@@ -151,6 +155,7 @@
.thenReturn(TEST_CUSTOM_SAFETY_PKG);
Context context = Mockito.spy(mContext);
when(context.getPackageManager()).thenReturn(mPackageManager);
+ when(mNightDisplayListenerBuilder.build()).thenReturn(mNightDisplayListener);
mAutoTileManager = createAutoTileManager(context);
mAutoTileManager.init();
@@ -167,7 +172,7 @@
HotspotController hotspotController,
DataSaverController dataSaverController,
ManagedProfileController managedProfileController,
- NightDisplayListener nightDisplayListener,
+ NightDisplayListenerModule.Builder nightDisplayListenerBuilder,
CastController castController,
ReduceBrightColorsController reduceBrightColorsController,
DeviceControlsController deviceControlsController,
@@ -180,7 +185,7 @@
hotspotController,
dataSaverController,
managedProfileController,
- nightDisplayListener,
+ mNightDisplayListenerBuilder,
castController,
reduceBrightColorsController,
deviceControlsController,
@@ -191,7 +196,7 @@
private AutoTileManager createAutoTileManager(Context context) {
return createAutoTileManager(context, mAutoAddTrackerBuilder, mHotspotController,
- mDataSaverController, mManagedProfileController, mNightDisplayListener,
+ mDataSaverController, mManagedProfileController, mNightDisplayListenerBuilder,
mCastController, mReduceBrightColorsController, mDeviceControlsController,
mWalletController, mSafetyController, mIsReduceBrightColorsAvailable);
}
@@ -204,7 +209,7 @@
HotspotController hC = mock(HotspotController.class);
DataSaverController dSC = mock(DataSaverController.class);
ManagedProfileController mPC = mock(ManagedProfileController.class);
- NightDisplayListener nDS = mock(NightDisplayListener.class);
+ NightDisplayListenerModule.Builder nDSB = mock(NightDisplayListenerModule.Builder.class);
CastController cC = mock(CastController.class);
ReduceBrightColorsController rBC = mock(ReduceBrightColorsController.class);
DeviceControlsController dCC = mock(DeviceControlsController.class);
@@ -212,14 +217,14 @@
SafetyController sC = mock(SafetyController.class);
AutoTileManager manager =
- createAutoTileManager(mock(Context.class), builder, hC, dSC, mPC, nDS, cC, rBC,
+ createAutoTileManager(mock(Context.class), builder, hC, dSC, mPC, nDSB, cC, rBC,
dCC, wC, sC, true);
verify(tracker, never()).initialize();
verify(hC, never()).addCallback(any());
verify(dSC, never()).addCallback(any());
verify(mPC, never()).addCallback(any());
- verify(nDS, never()).setCallback(any());
+ verifyNoMoreInteractions(nDSB);
verify(cC, never()).addCallback(any());
verify(rBC, never()).addCallback(any());
verify(dCC, never()).setCallback(any());
@@ -615,6 +620,15 @@
createAutoTileManager(mContext).destroy();
}
+ @Test
+ public void testUserChange_newNightDisplayListenerCreated() {
+ UserHandle newUser = UserHandle.of(1000);
+ mAutoTileManager.changeUser(newUser);
+ InOrder inOrder = inOrder(mNightDisplayListenerBuilder);
+ inOrder.verify(mNightDisplayListenerBuilder).setUser(newUser.getIdentifier());
+ inOrder.verify(mNightDisplayListenerBuilder).build();
+ }
+
// Will only notify if it's listening
private void changeValue(String key, int value) {
mSecureSettings.putIntForUser(key, value, USER);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index 1ffffe4..88d8dfc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -450,7 +450,7 @@
() -> mAssistManager,
() -> mNotificationGutsManager
));
- mShadeController.setNotificationPanelViewController(mNotificationPanelViewController);
+ mShadeController.setShadeViewController(mNotificationPanelViewController);
mShadeController.setNotificationShadeWindowViewController(
mNotificationShadeWindowViewController);
mShadeController.setNotificationPresenter(mNotificationPresenter);
@@ -490,9 +490,11 @@
mMetricsLogger,
mShadeLogger,
mUiBgExecutor,
+ mNotificationPanelViewController,
mNotificationMediaManager,
mLockscreenUserManager,
mRemoteInputManager,
+ mQuickSettingsController,
mUserSwitcherController,
mBatteryController,
mColorExtractor,
@@ -587,8 +589,6 @@
// TODO: we should be able to call mCentralSurfaces.start() and have all the below values
// initialized automatically and make NPVC private.
mCentralSurfaces.mNotificationShadeWindowView = mNotificationShadeWindowView;
- mCentralSurfaces.mShadeSurface = mNotificationPanelViewController;
- mCentralSurfaces.mQsController = mQuickSettingsController;
mCentralSurfaces.mDozeScrimController = mDozeScrimController;
mCentralSurfaces.mPresenter = mNotificationPresenter;
mCentralSurfaces.mKeyguardIndicationController = mKeyguardIndicationController;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBypassControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBypassControllerTest.kt
index 3e90ed9..4aac841 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBypassControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBypassControllerTest.kt
@@ -42,6 +42,8 @@
import org.mockito.ArgumentCaptor
import org.mockito.Captor
import org.mockito.Mock
+import org.mockito.Mockito.anyBoolean
+import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
@@ -135,6 +137,19 @@
}
@Test
+ fun onFaceAuthEnabledChanged_notifiesBypassEnabledListeners() {
+ initKeyguardBypassController()
+ val bypassListener = mock(KeyguardBypassController.OnBypassStateChangedListener::class.java)
+ val callback = ArgumentCaptor.forClass(KeyguardStateController.Callback::class.java)
+
+ keyguardBypassController.registerOnBypassStateChangedListener(bypassListener)
+ verify(keyguardStateController).addCallback(callback.capture())
+
+ callback.value.onFaceAuthEnabledChanged()
+ verify(bypassListener).onBypassStateChanged(anyBoolean())
+ }
+
+ @Test
fun configDevicePostureClosed_matchState_isPostureAllowedForFaceAuth_returnTrue() {
defaultConfigPostureClosed()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt
index 6b18169..85fbef0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt
@@ -27,6 +27,8 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor
+import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor.State
import com.android.systemui.privacy.PrivacyItemController
import com.android.systemui.privacy.logging.PrivacyLogger
import com.android.systemui.screenrecord.RecordingController
@@ -46,9 +48,17 @@
import com.android.systemui.statusbar.policy.ZenModeController
import com.android.systemui.util.RingerModeTracker
import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.kotlin.JavaAdapter
import com.android.systemui.util.mockito.capture
import com.android.systemui.util.time.DateFormatUtil
import com.android.systemui.util.time.FakeSystemClock
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -57,6 +67,8 @@
import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.clearInvocations
+import org.mockito.Mockito.inOrder
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` as whenever
@@ -64,11 +76,13 @@
@RunWith(AndroidTestingRunner::class)
@RunWithLooper
+@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
class PhoneStatusBarPolicyTest : SysuiTestCase() {
companion object {
private const val ALARM_SLOT = "alarm"
+ private const val CONNECTED_DISPLAY_SLOT = "connected_display"
}
@Mock private lateinit var iconController: StatusBarIconController
@@ -102,6 +116,9 @@
private lateinit var alarmCallbackCaptor:
ArgumentCaptor<NextAlarmController.NextAlarmChangeCallback>
+ private val testScope = TestScope(UnconfinedTestDispatcher())
+ private val fakeConnectedDisplayStateProvider = FakeConnectedDisplayStateProvider()
+
private lateinit var executor: FakeExecutor
private lateinit var statusBarPolicy: PhoneStatusBarPolicy
private lateinit var testableLooper: TestableLooper
@@ -164,6 +181,57 @@
verify(iconController).setIconVisibility(ALARM_SLOT, true)
}
+ @Test
+ fun connectedDisplay_connected_iconShown() =
+ testScope.runTest {
+ statusBarPolicy.init()
+ clearInvocations(iconController)
+
+ fakeConnectedDisplayStateProvider.emit(State.CONNECTED)
+ runCurrent()
+
+ verify(iconController).setIconVisibility(CONNECTED_DISPLAY_SLOT, true)
+ }
+
+ @Test
+ fun connectedDisplay_disconnected_iconHidden() =
+ testScope.runTest {
+ statusBarPolicy.init()
+ clearInvocations(iconController)
+
+ fakeConnectedDisplayStateProvider.emit(State.DISCONNECTED)
+
+ verify(iconController).setIconVisibility(CONNECTED_DISPLAY_SLOT, false)
+ }
+
+ @Test
+ fun connectedDisplay_disconnectedThenConnected_iconShown() =
+ testScope.runTest {
+ statusBarPolicy.init()
+ clearInvocations(iconController)
+
+ fakeConnectedDisplayStateProvider.emit(State.CONNECTED)
+ fakeConnectedDisplayStateProvider.emit(State.DISCONNECTED)
+ fakeConnectedDisplayStateProvider.emit(State.CONNECTED)
+
+ inOrder(iconController).apply {
+ verify(iconController).setIconVisibility(CONNECTED_DISPLAY_SLOT, true)
+ verify(iconController).setIconVisibility(CONNECTED_DISPLAY_SLOT, false)
+ verify(iconController).setIconVisibility(CONNECTED_DISPLAY_SLOT, true)
+ }
+ }
+
+ @Test
+ fun connectedDisplay_connectSecureDisplay_iconShown() =
+ testScope.runTest {
+ statusBarPolicy.init()
+ clearInvocations(iconController)
+
+ fakeConnectedDisplayStateProvider.emit(State.CONNECTED_SECURE)
+
+ verify(iconController).setIconVisibility(CONNECTED_DISPLAY_SLOT, true)
+ }
+
private fun createAlarmInfo(): AlarmManager.AlarmClockInfo {
return AlarmManager.AlarmClockInfo(10L, null)
}
@@ -200,7 +268,16 @@
dateFormatUtil,
ringerModeTracker,
privacyItemController,
- privacyLogger
+ privacyLogger,
+ fakeConnectedDisplayStateProvider,
+ JavaAdapter(testScope.backgroundScope)
)
}
+
+ private class FakeConnectedDisplayStateProvider : ConnectedDisplayInteractor {
+ private val flow = MutableSharedFlow<State>()
+ suspend fun emit(value: State) = flow.emit(value)
+ override val connectedDisplayState: Flow<State>
+ get() = flow
+ }
}
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 548e1b5..c7143de 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
@@ -737,6 +737,16 @@
}
@Test
+ public void testResetBouncerAnimatingAway() {
+ reset(mPrimaryBouncerInteractor);
+ when(mPrimaryBouncerInteractor.isAnimatingAway()).thenReturn(true);
+
+ mStatusBarKeyguardViewManager.reset(true);
+
+ verify(mPrimaryBouncerInteractor, never()).hide();
+ }
+
+ @Test
public void handleDispatchTouchEvent_alternateBouncerNotVisible() {
mStatusBarKeyguardViewManager.addCallback(mCallback);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
index 9b1d93b..5dcb901 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
@@ -18,10 +18,6 @@
import static com.android.systemui.shade.ShadeExpansionStateManagerKt.STATE_CLOSED;
import static com.android.systemui.shade.ShadeExpansionStateManagerKt.STATE_OPEN;
-import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.ANIMATING_IN;
-import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.ANIMATING_OUT;
-import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.IDLE;
-import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.RUNNING_CHIP_ANIM;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -49,7 +45,7 @@
import android.view.ViewPropertyAnimator;
import android.widget.FrameLayout;
-import androidx.core.animation.Animator;
+import androidx.core.animation.AnimatorTestRule;
import androidx.test.filters.SmallTest;
import com.android.keyguard.KeyguardUpdateMonitor;
@@ -85,6 +81,7 @@
import com.android.systemui.util.time.FakeSystemClock;
import org.junit.Before;
+import org.junit.ClassRule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -139,6 +136,8 @@
private StatusBarWindowStateController mStatusBarWindowStateController;
@Mock
private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ @ClassRule
+ public static AnimatorTestRule mAnimatorTestRule = new AnimatorTestRule();
private List<StatusBarWindowStateListener> mStatusBarWindowStateListeners = new ArrayList<>();
@@ -172,7 +171,6 @@
@Test
public void testDisableSystemInfo_systemAnimationIdle_doesHide() {
- when(mAnimationScheduler.getAnimationState()).thenReturn(IDLE);
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_SYSTEM_INFO, 0, false);
@@ -192,24 +190,26 @@
public void testSystemStatusAnimation_startedDisabled_finishedWithAnimator_showsSystemInfo() {
// GIVEN the status bar hides the system info via disable flags, while there is no event
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
- when(mAnimationScheduler.getAnimationState()).thenReturn(IDLE);
fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_SYSTEM_INFO, 0, false);
assertEquals(View.INVISIBLE, getEndSideContentView().getVisibility());
+ // WHEN the system event animation starts
+ fragment.onSystemEventAnimationBegin().start();
+
+ // THEN the view remains invisible during the animation
+ assertEquals(0f, getEndSideContentView().getAlpha(), 0.01);
+ mAnimatorTestRule.advanceTimeBy(500);
+ assertEquals(0f, getEndSideContentView().getAlpha(), 0.01);
+
// WHEN the disable flags are cleared during a system event animation
- when(mAnimationScheduler.getAnimationState()).thenReturn(RUNNING_CHIP_ANIM);
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
- // THEN the view is made visible again, but still low alpha
- assertEquals(View.VISIBLE, getEndSideContentView().getVisibility());
+ // THEN the view remains invisible
assertEquals(0, getEndSideContentView().getAlpha(), 0.01);
// WHEN the system event animation finishes
- when(mAnimationScheduler.getAnimationState()).thenReturn(ANIMATING_OUT);
- Animator anim = fragment.onSystemEventAnimationFinish(false);
- anim.start();
- processAllMessages();
- anim.end();
+ fragment.onSystemEventAnimationFinish(false).start();
+ mAnimatorTestRule.advanceTimeBy(500);
// THEN the system info is full alpha
assertEquals(1, getEndSideContentView().getAlpha(), 0.01);
@@ -219,20 +219,15 @@
public void testSystemStatusAnimation_systemInfoDisabled_staysInvisible() {
// GIVEN the status bar hides the system info via disable flags, while there is no event
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
- when(mAnimationScheduler.getAnimationState()).thenReturn(IDLE);
fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_SYSTEM_INFO, 0, false);
assertEquals(View.INVISIBLE, getEndSideContentView().getVisibility());
// WHEN the system event animation finishes
- when(mAnimationScheduler.getAnimationState()).thenReturn(ANIMATING_OUT);
- Animator anim = fragment.onSystemEventAnimationFinish(false);
- anim.start();
- processAllMessages();
- anim.end();
+ fragment.onSystemEventAnimationFinish(false).start();
+ mAnimatorTestRule.advanceTimeBy(500);
- // THEN the system info is at full alpha, but still INVISIBLE (since the disable flag is
- // still set)
- assertEquals(1, getEndSideContentView().getAlpha(), 0.01);
+ // THEN the system info remains invisible (since the disable flag is still set)
+ assertEquals(0, getEndSideContentView().getAlpha(), 0.01);
assertEquals(View.INVISIBLE, getEndSideContentView().getVisibility());
}
@@ -241,15 +236,14 @@
public void testSystemStatusAnimation_notDisabled_animatesAlphaZero() {
// GIVEN the status bar is not disabled
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
- when(mAnimationScheduler.getAnimationState()).thenReturn(ANIMATING_IN);
- // WHEN the system event animation begins
- Animator anim = fragment.onSystemEventAnimationBegin();
- anim.start();
- processAllMessages();
- anim.end();
+ assertEquals(1, getEndSideContentView().getAlpha(), 0.01);
- // THEN the system info is visible but alpha 0
- assertEquals(View.VISIBLE, getEndSideContentView().getVisibility());
+ // WHEN the system event animation begins
+ fragment.onSystemEventAnimationBegin().start();
+ mAnimatorTestRule.advanceTimeBy(500);
+
+ // THEN the system info is invisible
+ assertEquals(View.INVISIBLE, getEndSideContentView().getVisibility());
assertEquals(0, getEndSideContentView().getAlpha(), 0.01);
}
@@ -257,25 +251,21 @@
public void testSystemStatusAnimation_notDisabled_animatesBackToAlphaOne() {
// GIVEN the status bar is not disabled
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
- when(mAnimationScheduler.getAnimationState()).thenReturn(ANIMATING_IN);
- // WHEN the system event animation begins
- Animator anim = fragment.onSystemEventAnimationBegin();
- anim.start();
- processAllMessages();
- anim.end();
+ assertEquals(1, getEndSideContentView().getAlpha(), 0.01);
- // THEN the system info is visible but alpha 0
- assertEquals(View.VISIBLE, getEndSideContentView().getVisibility());
+ // WHEN the system event animation begins
+ fragment.onSystemEventAnimationBegin().start();
+ mAnimatorTestRule.advanceTimeBy(500);
+
+ // THEN the system info is invisible
+ assertEquals(View.INVISIBLE, getEndSideContentView().getVisibility());
assertEquals(0, getEndSideContentView().getAlpha(), 0.01);
// WHEN the system event animation finishes
- when(mAnimationScheduler.getAnimationState()).thenReturn(ANIMATING_OUT);
- anim = fragment.onSystemEventAnimationFinish(false);
- anim.start();
- processAllMessages();
- anim.end();
+ fragment.onSystemEventAnimationFinish(false).start();
+ mAnimatorTestRule.advanceTimeBy(500);
- // THEN the syste info is full alpha and VISIBLE
+ // THEN the system info is full alpha and VISIBLE
assertEquals(View.VISIBLE, getEndSideContentView().getVisibility());
assertEquals(1, getEndSideContentView().getAlpha(), 0.01);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/MultiSourceMinAlphaControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/MultiSourceMinAlphaControllerTest.kt
new file mode 100644
index 0000000..2617613
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/MultiSourceMinAlphaControllerTest.kt
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone.fragment
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.view.View
+import androidx.core.animation.AnimatorTestRule
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import junit.framework.Assert.assertEquals
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+private const val TEST_SOURCE_1 = 1
+private const val TEST_SOURCE_2 = 2
+private const val TEST_ANIMATION_DURATION = 100L
+private const val INITIAL_ALPHA = 1f
+
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@SmallTest
+class MultiSourceMinAlphaControllerTest : SysuiTestCase() {
+
+ private val view = View(context)
+ private val multiSourceMinAlphaController =
+ MultiSourceMinAlphaController(view, initialAlpha = INITIAL_ALPHA)
+
+ @get:Rule val animatorTestRule = AnimatorTestRule()
+
+ @Before
+ fun setup() {
+ multiSourceMinAlphaController.reset()
+ }
+
+ @Test
+ fun testSetAlpha() {
+ multiSourceMinAlphaController.setAlpha(alpha = 0.5f, sourceId = TEST_SOURCE_1)
+ assertEquals(0.5f, view.alpha)
+ }
+
+ @Test
+ fun testAnimateToAlpha() {
+ multiSourceMinAlphaController.animateToAlpha(
+ alpha = 0.5f,
+ sourceId = TEST_SOURCE_1,
+ duration = TEST_ANIMATION_DURATION
+ )
+ animatorTestRule.advanceTimeBy(TEST_ANIMATION_DURATION)
+ assertEquals(0.5f, view.alpha)
+ }
+
+ @Test
+ fun testReset() {
+ multiSourceMinAlphaController.animateToAlpha(
+ alpha = 0.5f,
+ sourceId = TEST_SOURCE_1,
+ duration = TEST_ANIMATION_DURATION
+ )
+ multiSourceMinAlphaController.setAlpha(alpha = 0.7f, sourceId = TEST_SOURCE_2)
+ multiSourceMinAlphaController.reset()
+ // advance time to ensure that animators are cancelled when the controller is reset
+ animatorTestRule.advanceTimeBy(TEST_ANIMATION_DURATION)
+ assertEquals(INITIAL_ALPHA, view.alpha)
+ }
+
+ @Test
+ fun testMinOfTwoSourcesIsApplied() {
+ multiSourceMinAlphaController.setAlpha(alpha = 0f, sourceId = TEST_SOURCE_1)
+ multiSourceMinAlphaController.setAlpha(alpha = 0.5f, sourceId = TEST_SOURCE_2)
+ assertEquals(0f, view.alpha)
+ multiSourceMinAlphaController.setAlpha(alpha = 1f, sourceId = TEST_SOURCE_1)
+ assertEquals(0.5f, view.alpha)
+ }
+
+ @Test
+ fun testSetAlphaForSameSourceCancelsAnimator() {
+ multiSourceMinAlphaController.animateToAlpha(
+ alpha = 0f,
+ sourceId = TEST_SOURCE_1,
+ duration = TEST_ANIMATION_DURATION
+ )
+ animatorTestRule.advanceTimeBy(TEST_ANIMATION_DURATION / 2)
+ multiSourceMinAlphaController.setAlpha(alpha = 1f, sourceId = TEST_SOURCE_1)
+ animatorTestRule.advanceTimeBy(TEST_ANIMATION_DURATION / 2)
+ // verify that animation was cancelled and the setAlpha call overrides the alpha value of
+ // the animation
+ assertEquals(1f, view.alpha)
+ }
+}
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 d787ada..5cabcd4 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
@@ -24,6 +24,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.hardware.biometrics.BiometricSourceType;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -43,6 +44,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -66,6 +68,9 @@
@Mock
private KeyguardUpdateMonitorLogger mLogger;
+ @Captor
+ private ArgumentCaptor<KeyguardUpdateMonitorCallback> mUpdateCallbackCaptor;
+
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
@@ -84,6 +89,23 @@
}
@Test
+ public void testFaceAuthEnabledChanged_calledWhenFaceEnrollmentStateChanges() {
+ KeyguardStateController.Callback callback = mock(KeyguardStateController.Callback.class);
+
+ when(mKeyguardUpdateMonitor.isFaceAuthEnabledForUser(anyInt())).thenReturn(false);
+ verify(mKeyguardUpdateMonitor).registerCallback(mUpdateCallbackCaptor.capture());
+ mKeyguardStateController.addCallback(callback);
+ assertThat(mKeyguardStateController.isFaceAuthEnabled()).isFalse();
+
+ when(mKeyguardUpdateMonitor.isFaceAuthEnabledForUser(anyInt())).thenReturn(true);
+ mUpdateCallbackCaptor.getValue().onBiometricEnrollmentStateChanged(
+ BiometricSourceType.FACE);
+
+ assertThat(mKeyguardStateController.isFaceAuthEnabled()).isTrue();
+ verify(callback).onFaceAuthEnabledChanged();
+ }
+
+ @Test
public void testIsShowing() {
assertThat(mKeyguardStateController.isShowing()).isFalse();
mKeyguardStateController.notifyKeyguardState(true /* showing */, false /* occluded */);
@@ -177,16 +199,14 @@
@Test
public void testOnEnabledTrustAgentsChangedCallback() {
final Random random = new Random();
- final ArgumentCaptor<KeyguardUpdateMonitorCallback> updateCallbackCaptor =
- ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback.class);
- verify(mKeyguardUpdateMonitor).registerCallback(updateCallbackCaptor.capture());
+ verify(mKeyguardUpdateMonitor).registerCallback(mUpdateCallbackCaptor.capture());
final KeyguardStateController.Callback stateCallback =
mock(KeyguardStateController.Callback.class);
mKeyguardStateController.addCallback(stateCallback);
when(mLockPatternUtils.isSecure(anyInt())).thenReturn(true);
- updateCallbackCaptor.getValue().onEnabledTrustAgentsChanged(random.nextInt());
+ mUpdateCallbackCaptor.getValue().onEnabledTrustAgentsChanged(random.nextInt());
verify(stateCallback).onUnlockedChanged();
}
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt
new file mode 100644
index 0000000..a718f70
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.authentication.data.repository
+
+import com.android.keyguard.KeyguardSecurityModel.SecurityMode
+import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+
+class FakeAuthenticationRepository(
+ private val delegate: AuthenticationRepository,
+ private val onSecurityModeChanged: (SecurityMode) -> Unit,
+) : AuthenticationRepository by delegate {
+
+ private val _isUnlocked = MutableStateFlow(false)
+ override val isUnlocked: StateFlow<Boolean> = _isUnlocked.asStateFlow()
+
+ private var authenticationMethod: AuthenticationMethodModel = DEFAULT_AUTHENTICATION_METHOD
+
+ override suspend fun getAuthenticationMethod(): AuthenticationMethodModel {
+ return authenticationMethod
+ }
+
+ fun setAuthenticationMethod(authenticationMethod: AuthenticationMethodModel) {
+ this.authenticationMethod = authenticationMethod
+ onSecurityModeChanged(authenticationMethod.toSecurityMode())
+ }
+
+ fun setUnlocked(isUnlocked: Boolean) {
+ _isUnlocked.value = isUnlocked
+ }
+
+ companion object {
+ val DEFAULT_AUTHENTICATION_METHOD =
+ AuthenticationMethodModel.Pin(listOf(1, 2, 3, 4), autoConfirm = false)
+
+ fun AuthenticationMethodModel.toSecurityMode(): SecurityMode {
+ return when (this) {
+ is AuthenticationMethodModel.Pin -> SecurityMode.PIN
+ is AuthenticationMethodModel.Password -> SecurityMode.Password
+ is AuthenticationMethodModel.Pattern -> SecurityMode.Pattern
+ is AuthenticationMethodModel.Swipe,
+ is AuthenticationMethodModel.None -> SecurityMode.None
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFaceAuthRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFaceAuthRepository.kt
index 738f09d..2715aaa 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFaceAuthRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFaceAuthRepository.kt
@@ -41,7 +41,9 @@
fun setDetectionStatus(status: DetectionStatus) {
_detectionStatus.value = status
}
- override val isLockedOut = MutableStateFlow(false)
+
+ private val _isLockedOut = MutableStateFlow(false)
+ override val isLockedOut = _isLockedOut
private val _runningAuthRequest = MutableStateFlow<Pair<FaceAuthUiEvent, Boolean>?>(null)
val runningAuthRequest: StateFlow<Pair<FaceAuthUiEvent, Boolean>?> =
_runningAuthRequest.asStateFlow()
@@ -56,6 +58,10 @@
_isAuthRunning.value = true
}
+ fun setLockedOut(value: Boolean) {
+ _isLockedOut.value = value
+ }
+
override fun cancel() {
_isAuthRunning.value = false
_runningAuthRequest.value = null
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/data/repository/FakeAutoAddRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/data/repository/FakeAutoAddRepository.kt
new file mode 100644
index 0000000..9ea079f
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/data/repository/FakeAutoAddRepository.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.pipeline.data.repository
+
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+
+class FakeAutoAddRepository : AutoAddRepository {
+
+ private val autoAddedTilesPerUser = mutableMapOf<Int, MutableStateFlow<Set<TileSpec>>>()
+
+ override fun autoAddedTiles(userId: Int): Flow<Set<TileSpec>> {
+ return getFlow(userId)
+ }
+
+ override suspend fun markTileAdded(userId: Int, spec: TileSpec) {
+ if (spec == TileSpec.Invalid) return
+ with(getFlow(userId)) { value = value.toMutableSet().apply { add(spec) } }
+ }
+
+ override suspend fun unmarkTileAdded(userId: Int, spec: TileSpec) {
+ with(getFlow(userId)) { value = value.toMutableSet().apply { remove(spec) } }
+ }
+
+ private fun getFlow(userId: Int): MutableStateFlow<Set<TileSpec>> =
+ autoAddedTilesPerUser.getOrPut(userId) { MutableStateFlow(emptySet()) }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/domain/autoaddable/FakeAutoAddable.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/domain/autoaddable/FakeAutoAddable.kt
new file mode 100644
index 0000000..ebdd6fd
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/domain/autoaddable/FakeAutoAddable.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.pipeline.domain.autoaddable
+
+import com.android.systemui.qs.pipeline.data.repository.TileSpecRepository.Companion.POSITION_AT_END
+import com.android.systemui.qs.pipeline.domain.model.AutoAddSignal
+import com.android.systemui.qs.pipeline.domain.model.AutoAddTracking
+import com.android.systemui.qs.pipeline.domain.model.AutoAddable
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.filterNotNull
+
+class FakeAutoAddable(
+ private val spec: TileSpec,
+ override val autoAddTracking: AutoAddTracking,
+) : AutoAddable {
+
+ private val signalsPerUser = mutableMapOf<Int, MutableStateFlow<AutoAddSignal?>>()
+ private fun getFlow(userId: Int): MutableStateFlow<AutoAddSignal?> =
+ signalsPerUser.getOrPut(userId) { MutableStateFlow(null) }
+
+ override fun autoAddSignal(userId: Int): Flow<AutoAddSignal> {
+ return getFlow(userId).asStateFlow().filterNotNull()
+ }
+
+ suspend fun sendRemoveSignal(userId: Int) {
+ getFlow(userId).value = AutoAddSignal.Remove(spec)
+ }
+
+ suspend fun sendAddSignal(userId: Int, position: Int = POSITION_AT_END) {
+ getFlow(userId).value = AutoAddSignal.Add(spec, position)
+ }
+
+ override val description: String
+ get() = "FakeAutoAddable($spec)"
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
index 9c4fd94..0b6e2a2 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
@@ -16,20 +16,28 @@
package com.android.systemui.scene
+import com.android.keyguard.KeyguardSecurityModel.SecurityMode
import com.android.systemui.SysuiTestCase
import com.android.systemui.authentication.data.repository.AuthenticationRepository
import com.android.systemui.authentication.data.repository.AuthenticationRepositoryImpl
+import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository
+import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository.Companion.toSecurityMode
import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor
import com.android.systemui.bouncer.data.repository.BouncerRepository
import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
import com.android.systemui.bouncer.ui.viewmodel.BouncerViewModel
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.domain.interactor.LockscreenSceneInteractor
import com.android.systemui.scene.data.repository.SceneContainerRepository
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.model.SceneContainerConfig
import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.user.data.repository.FakeUserRepository
+import com.android.systemui.util.mockito.mock
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestDispatcher
import kotlinx.coroutines.test.TestScope
/**
@@ -39,9 +47,25 @@
@OptIn(ExperimentalCoroutinesApi::class)
class SceneTestUtils(
test: SysuiTestCase,
- private val testScope: TestScope? = null,
) {
-
+ val testDispatcher: TestDispatcher by lazy { StandardTestDispatcher() }
+ val testScope: TestScope by lazy { TestScope(testDispatcher) }
+ private var securityMode: SecurityMode =
+ FakeAuthenticationRepository.DEFAULT_AUTHENTICATION_METHOD.toSecurityMode()
+ val authenticationRepository: FakeAuthenticationRepository by lazy {
+ FakeAuthenticationRepository(
+ delegate =
+ AuthenticationRepositoryImpl(
+ applicationScope = applicationScope(),
+ getSecurityMode = { securityMode },
+ backgroundDispatcher = testDispatcher,
+ userRepository = FakeUserRepository(),
+ lockPatternUtils = mock(),
+ keyguardRepository = FakeKeyguardRepository(),
+ ),
+ onSecurityModeChanged = { securityMode = it },
+ )
+ }
private val context = test.context
fun fakeSceneContainerRepository(
@@ -82,7 +106,7 @@
}
fun authenticationRepository(): AuthenticationRepository {
- return AuthenticationRepositoryImpl()
+ return authenticationRepository
}
fun authenticationInteractor(
@@ -94,17 +118,6 @@
)
}
- private fun applicationScope(): CoroutineScope {
- return checkNotNull(testScope) {
- """
- TestScope not initialized, please create a TestScope and inject it into
- SceneTestUtils.
- """
- .trimIndent()
- }
- .backgroundScope
- }
-
fun bouncerInteractor(
authenticationInteractor: AuthenticationInteractor,
sceneInteractor: SceneInteractor,
@@ -154,6 +167,10 @@
)
}
+ private fun applicationScope(): CoroutineScope {
+ return testScope.backgroundScope
+ }
+
companion object {
const val CONTAINER_1 = "container1"
const val CONTAINER_2 = "container2"
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index ae24f1e..de6522e 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -1027,7 +1027,7 @@
private static final String KEY_ENABLE_WAIT_FOR_FINISH_ATTACH_APPLICATION =
"enable_wait_for_finish_attach_application";
- private static final boolean DEFAULT_ENABLE_WAIT_FOR_FINISH_ATTACH_APPLICATION = false;
+ private static final boolean DEFAULT_ENABLE_WAIT_FOR_FINISH_ATTACH_APPLICATION = true;
/** @see #KEY_ENABLE_WAIT_FOR_FINISH_ATTACH_APPLICATION */
public volatile boolean mEnableWaitForFinishAttachApplication =
diff --git a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
index e498384..753fdae 100644
--- a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
@@ -51,11 +51,11 @@
import com.android.internal.annotations.CompositeRWLock;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.modules.expresslog.Counter;
import com.android.internal.os.ProcessCpuTracker;
import com.android.internal.os.TimeoutRecord;
import com.android.internal.os.anr.AnrLatencyTracker;
import com.android.internal.util.FrameworkStatsLog;
+import com.android.modules.expresslog.Counter;
import com.android.server.ResourcePressureUtil;
import com.android.server.criticalevents.CriticalEventLog;
import com.android.server.stats.pull.ProcfsMemoryUtil.MemorySnapshot;
@@ -456,6 +456,11 @@
String currentPsiState = ResourcePressureUtil.currentPsiState();
latencyTracker.currentPsiStateReturned();
report.append(currentPsiState);
+ // The 'processCpuTracker' variable is a shared resource that might be initialized and
+ // updated in a different thread. In order to prevent thread visibility issues, which
+ // can occur when one thread does not immediately see the changes made to
+ // 'processCpuTracker' by another thread, it is necessary to use synchronization whenever
+ // 'processCpuTracker' is accessed or modified.
ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(true);
// We push the native pids collection task to the helper thread through
@@ -517,12 +522,16 @@
}
mService.updateCpuStatsNow();
mService.mAppProfiler.printCurrentCpuState(report, anrTime);
- info.append(processCpuTracker.printCurrentLoad());
+ synchronized (processCpuTracker) {
+ info.append(processCpuTracker.printCurrentLoad());
+ }
info.append(report);
}
report.append(tracesFileException.getBuffer());
- info.append(processCpuTracker.printCurrentState(anrTime));
+ synchronized (processCpuTracker) {
+ info.append(processCpuTracker.printCurrentState(anrTime));
+ }
Slog.e(TAG, info.toString());
if (tracesFile == null) {
diff --git a/services/core/java/com/android/server/am/StackTracesDumpHelper.java b/services/core/java/com/android/server/am/StackTracesDumpHelper.java
index cf69b53..ba0fd17 100644
--- a/services/core/java/com/android/server/am/StackTracesDumpHelper.java
+++ b/services/core/java/com/android/server/am/StackTracesDumpHelper.java
@@ -464,28 +464,31 @@
latencyTracker.processCpuTrackerMethodsCalled();
}
ArrayList<Integer> extraPids = new ArrayList<>();
- processCpuTracker.init();
+ synchronized (processCpuTracker) {
+ processCpuTracker.init();
+ }
try {
Thread.sleep(200);
} catch (InterruptedException ignored) {
}
- processCpuTracker.update();
+ synchronized (processCpuTracker) {
+ processCpuTracker.update();
+ // We'll take the stack crawls of just the top apps using CPU.
+ final int workingStatsNumber = processCpuTracker.countWorkingStats();
+ for (int i = 0; i < workingStatsNumber && extraPids.size() < 2; i++) {
+ ProcessCpuTracker.Stats stats = processCpuTracker.getWorkingStats(i);
+ if (lastPids.indexOfKey(stats.pid) >= 0) {
+ if (DEBUG_ANR) {
+ Slog.d(TAG, "Collecting stacks for extra pid " + stats.pid);
+ }
- // We'll take the stack crawls of just the top apps using CPU.
- final int workingStatsNumber = processCpuTracker.countWorkingStats();
- for (int i = 0; i < workingStatsNumber && extraPids.size() < 2; i++) {
- ProcessCpuTracker.Stats stats = processCpuTracker.getWorkingStats(i);
- if (lastPids.indexOfKey(stats.pid) >= 0) {
- if (DEBUG_ANR) {
- Slog.d(TAG, "Collecting stacks for extra pid " + stats.pid);
+ extraPids.add(stats.pid);
+ } else {
+ Slog.i(TAG,
+ "Skipping next CPU consuming process, not a java proc: "
+ + stats.pid);
}
-
- extraPids.add(stats.pid);
- } else {
- Slog.i(TAG,
- "Skipping next CPU consuming process, not a java proc: "
- + stats.pid);
}
}
if (latencyTracker != null) {
diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java
index e4a5a3e..ca15dd7 100644
--- a/services/core/java/com/android/server/app/GameManagerService.java
+++ b/services/core/java/com/android/server/app/GameManagerService.java
@@ -2166,7 +2166,7 @@
@Override
public void onUidStateChanged(int uid, int procState, long procStateSeq, int capability) {
synchronized (mUidObserverLock) {
- if (ActivityManager.isProcStateBackground(procState)) {
+ if (procState != ActivityManager.PROCESS_STATE_TOP) {
disableGameMode(uid);
return;
}
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index 50ffbcb9..3f4f981 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -957,6 +957,7 @@
players = (HashMap<Integer, AudioPlaybackConfiguration>) mPlayers.clone();
}
mFadingManager.unfadeOutUid(uid, players);
+ mDuckingManager.unduckUid(uid, players);
}
//=================================================================
diff --git a/services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java b/services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java
index 969a174..aeb6b6e 100644
--- a/services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java
+++ b/services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java
@@ -20,7 +20,6 @@
import android.annotation.Nullable;
import android.hardware.biometrics.BiometricOverlayConstants;
import android.hardware.fingerprint.ISidefpsController;
-import android.hardware.fingerprint.IUdfpsOverlay;
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.hardware.fingerprint.IUdfpsOverlayControllerCallback;
import android.os.RemoteException;
@@ -44,7 +43,6 @@
@NonNull private final Optional<IUdfpsOverlayController> mUdfpsOverlayController;
@NonNull private final Optional<ISidefpsController> mSidefpsController;
- @NonNull private final Optional<IUdfpsOverlay> mUdfpsOverlay;
/**
* Create an overlay controller for each modality.
@@ -54,11 +52,9 @@
*/
public SensorOverlays(
@Nullable IUdfpsOverlayController udfpsOverlayController,
- @Nullable ISidefpsController sidefpsController,
- @Nullable IUdfpsOverlay udfpsOverlay) {
+ @Nullable ISidefpsController sidefpsController) {
mUdfpsOverlayController = Optional.ofNullable(udfpsOverlayController);
mSidefpsController = Optional.ofNullable(sidefpsController);
- mUdfpsOverlay = Optional.ofNullable(udfpsOverlay);
}
/**
@@ -94,14 +90,6 @@
Slog.e(TAG, "Remote exception when showing the UDFPS overlay", e);
}
}
-
- if (mUdfpsOverlay.isPresent()) {
- try {
- mUdfpsOverlay.get().show(client.getRequestId(), sensorId, reason);
- } catch (RemoteException e) {
- Slog.e(TAG, "Remote exception when showing the new UDFPS overlay", e);
- }
- }
}
/**
@@ -125,14 +113,6 @@
Slog.e(TAG, "Remote exception when hiding the UDFPS overlay", e);
}
}
-
- if (mUdfpsOverlay.isPresent()) {
- try {
- mUdfpsOverlay.get().hide(sensorId);
- } catch (RemoteException e) {
- Slog.e(TAG, "Remote exception when hiding the new udfps overlay", e);
- }
- }
}
/**
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
index ea6bb62..28cb7d9 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
@@ -54,7 +54,6 @@
import android.hardware.fingerprint.IFingerprintService;
import android.hardware.fingerprint.IFingerprintServiceReceiver;
import android.hardware.fingerprint.ISidefpsController;
-import android.hardware.fingerprint.IUdfpsOverlay;
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.os.Binder;
import android.os.Build;
@@ -963,16 +962,6 @@
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
- public void setUdfpsOverlay(@NonNull IUdfpsOverlay controller) {
- super.setUdfpsOverlay_enforcePermission();
-
- for (ServiceProvider provider : mRegistry.getProviders()) {
- provider.setUdfpsOverlay(controller);
- }
- }
-
- @android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
- @Override
public void onPowerPressed() {
super.onPowerPressed_enforcePermission();
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
index d70ca8c..a15d1a4 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
@@ -28,7 +28,6 @@
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.IFingerprintServiceReceiver;
import android.hardware.fingerprint.ISidefpsController;
-import android.hardware.fingerprint.IUdfpsOverlay;
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.os.IBinder;
@@ -134,12 +133,6 @@
void setUdfpsOverlayController(@NonNull IUdfpsOverlayController controller);
- /**
- * Sets udfps overlay
- * @param controller udfps overlay
- */
- void setUdfpsOverlay(@NonNull IUdfpsOverlay controller);
-
void onPowerPressed();
/**
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
index 3fc36b6..54d1faa 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
@@ -30,7 +30,6 @@
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.ISidefpsController;
-import android.hardware.fingerprint.IUdfpsOverlay;
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.os.Build;
import android.os.Handler;
@@ -112,7 +111,6 @@
@NonNull LockoutCache lockoutCache,
@Nullable IUdfpsOverlayController udfpsOverlayController,
@Nullable ISidefpsController sidefpsController,
- @Nullable IUdfpsOverlay udfpsOverlay,
boolean allowBackgroundAuthentication,
@NonNull FingerprintSensorPropertiesInternal sensorProps,
@NonNull Handler handler,
@@ -137,8 +135,7 @@
false /* shouldVibrate */,
biometricStrength);
setRequestId(requestId);
- mSensorOverlays = new SensorOverlays(udfpsOverlayController,
- sidefpsController, udfpsOverlay);
+ mSensorOverlays = new SensorOverlays(udfpsOverlayController, sidefpsController);
mSensorProps = sensorProps;
mALSProbeCallback = getLogger().getAmbientLightProbe(false /* startWithClient */);
mHandler = handler;
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
index 46f62d3..51a9385 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
@@ -22,7 +22,6 @@
import android.hardware.biometrics.BiometricOverlayConstants;
import android.hardware.biometrics.common.ICancellationSignal;
import android.hardware.fingerprint.FingerprintAuthenticateOptions;
-import android.hardware.fingerprint.IUdfpsOverlay;
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.os.IBinder;
import android.os.RemoteException;
@@ -59,15 +58,13 @@
@NonNull FingerprintAuthenticateOptions options,
@NonNull BiometricLogger biometricLogger, @NonNull BiometricContext biometricContext,
@Nullable IUdfpsOverlayController udfpsOverlayController,
- @Nullable IUdfpsOverlay udfpsOverlay,
boolean isStrongBiometric) {
super(context, lazyDaemon, token, listener, options.getUserId(),
options.getOpPackageName(), 0 /* cookie */, options.getSensorId(),
true /* shouldVibrate */, biometricLogger, biometricContext);
setRequestId(requestId);
mIsStrongBiometric = isStrongBiometric;
- mSensorOverlays = new SensorOverlays(udfpsOverlayController,
- null /* sideFpsController*/, udfpsOverlay);
+ mSensorOverlays = new SensorOverlays(udfpsOverlayController, null /* sideFpsController*/);
mOptions = options;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
index d35469c..f9e08d6 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
@@ -29,7 +29,6 @@
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.ISidefpsController;
-import android.hardware.fingerprint.IUdfpsOverlay;
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.hardware.keymaster.HardwareAuthToken;
import android.os.IBinder;
@@ -87,7 +86,6 @@
@NonNull FingerprintSensorPropertiesInternal sensorProps,
@Nullable IUdfpsOverlayController udfpsOverlayController,
@Nullable ISidefpsController sidefpsController,
- @Nullable IUdfpsOverlay udfpsOverlay,
int maxTemplatesPerUser, @FingerprintManager.EnrollReason int enrollReason) {
// UDFPS haptics occur when an image is acquired (instead of when the result is known)
super(context, lazyDaemon, token, listener, userId, hardwareAuthToken, owner, utils,
@@ -95,8 +93,7 @@
biometricContext);
setRequestId(requestId);
mSensorProps = sensorProps;
- mSensorOverlays = new SensorOverlays(udfpsOverlayController,
- sidefpsController, udfpsOverlay);
+ mSensorOverlays = new SensorOverlays(udfpsOverlayController, sidefpsController);
mMaxTemplatesPerUser = maxTemplatesPerUser;
mALSProbeCallback = getLogger().getAmbientLightProbe(true /* startWithClient */);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
index f8d2566..0421d78 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
@@ -43,7 +43,6 @@
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.IFingerprintServiceReceiver;
import android.hardware.fingerprint.ISidefpsController;
-import android.hardware.fingerprint.IUdfpsOverlay;
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.os.Binder;
import android.os.Handler;
@@ -122,7 +121,6 @@
@Nullable private IFingerprint mDaemon;
@Nullable private IUdfpsOverlayController mUdfpsOverlayController;
@Nullable private ISidefpsController mSidefpsController;
- @Nullable private IUdfpsOverlay mUdfpsOverlay;
private AuthSessionCoordinator mAuthSessionCoordinator;
private final class BiometricTaskStackListener extends TaskStackListener {
@@ -420,7 +418,7 @@
BiometricsProtoEnums.CLIENT_UNKNOWN),
mBiometricContext,
mFingerprintSensors.get(sensorId).getSensorProperties(),
- mUdfpsOverlayController, mSidefpsController, mUdfpsOverlay,
+ mUdfpsOverlayController, mSidefpsController,
maxTemplatesPerUser, enrollReason);
scheduleForSensor(sensorId, client, new ClientMonitorCompositeCallback(
mBiometricStateCallback, new ClientMonitorCallback() {
@@ -458,8 +456,7 @@
mFingerprintSensors.get(sensorId).getLazySession(), token, id, callback,
options,
createLogger(BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient),
- mBiometricContext,
- mUdfpsOverlayController, mUdfpsOverlay, isStrongBiometric);
+ mBiometricContext, mUdfpsOverlayController, isStrongBiometric);
scheduleForSensor(sensorId, client, mBiometricStateCallback);
});
@@ -483,7 +480,7 @@
createLogger(BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient),
mBiometricContext, isStrongBiometric,
mTaskStackListener, mFingerprintSensors.get(sensorId).getLockoutCache(),
- mUdfpsOverlayController, mSidefpsController, mUdfpsOverlay,
+ mUdfpsOverlayController, mSidefpsController,
allowBackgroundAuthentication,
mFingerprintSensors.get(sensorId).getSensorProperties(), mHandler,
Utils.getCurrentStrength(sensorId),
@@ -719,11 +716,6 @@
}
@Override
- public void setUdfpsOverlay(@NonNull IUdfpsOverlay controller) {
- mUdfpsOverlay = controller;
- }
-
- @Override
public void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto,
boolean clearSchedulerBuffer) {
if (mFingerprintSensors.contains(sensorId)) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
index 1cbbf89..92b216d 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
@@ -40,7 +40,6 @@
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.IFingerprintServiceReceiver;
import android.hardware.fingerprint.ISidefpsController;
-import android.hardware.fingerprint.IUdfpsOverlay;
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.os.Handler;
import android.os.IBinder;
@@ -123,7 +122,6 @@
@NonNull private final HalResultController mHalResultController;
@Nullable private IUdfpsOverlayController mUdfpsOverlayController;
@Nullable private ISidefpsController mSidefpsController;
- @Nullable private IUdfpsOverlay mUdfpsOverlay;
@NonNull private final BiometricContext mBiometricContext;
// for requests that do not use biometric prompt
@NonNull private final AtomicLong mRequestCounter = new AtomicLong(0);
@@ -597,9 +595,7 @@
mSensorProperties.sensorId,
createLogger(BiometricsProtoEnums.ACTION_ENROLL,
BiometricsProtoEnums.CLIENT_UNKNOWN),
- mBiometricContext,
- mUdfpsOverlayController, mSidefpsController, mUdfpsOverlay,
- enrollReason);
+ mBiometricContext, mUdfpsOverlayController, mSidefpsController, enrollReason);
mScheduler.scheduleClientMonitor(client, new ClientMonitorCallback() {
@Override
public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
@@ -644,8 +640,7 @@
final FingerprintDetectClient client = new FingerprintDetectClient(mContext,
mLazyDaemon, token, id, listener, options,
createLogger(BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient),
- mBiometricContext, mUdfpsOverlayController, mUdfpsOverlay,
- isStrongBiometric);
+ mBiometricContext, mUdfpsOverlayController, isStrongBiometric);
mScheduler.scheduleClientMonitor(client, mBiometricStateCallback);
});
@@ -668,7 +663,7 @@
createLogger(BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient),
mBiometricContext, isStrongBiometric,
mTaskStackListener, mLockoutTracker,
- mUdfpsOverlayController, mSidefpsController, mUdfpsOverlay,
+ mUdfpsOverlayController, mSidefpsController,
allowBackgroundAuthentication, mSensorProperties,
Utils.getCurrentStrength(mSensorId));
mScheduler.scheduleClientMonitor(client, mBiometricStateCallback);
@@ -856,11 +851,6 @@
}
@Override
- public void setUdfpsOverlay(@NonNull IUdfpsOverlay controller) {
- mUdfpsOverlay = controller;
- }
-
- @Override
public void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto,
boolean clearSchedulerBuffer) {
final long sensorToken = proto.start(SensorServiceStateProto.SENSOR_STATES);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
index 2a62338..9966e91 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
@@ -30,7 +30,6 @@
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.ISidefpsController;
-import android.hardware.fingerprint.IUdfpsOverlay;
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.os.IBinder;
import android.os.RemoteException;
@@ -83,7 +82,6 @@
@NonNull LockoutFrameworkImpl lockoutTracker,
@Nullable IUdfpsOverlayController udfpsOverlayController,
@Nullable ISidefpsController sidefpsController,
- @Nullable IUdfpsOverlay udfpsOverlay,
boolean allowBackgroundAuthentication,
@NonNull FingerprintSensorPropertiesInternal sensorProps,
@Authenticators.Types int sensorStrength) {
@@ -93,8 +91,7 @@
false /* shouldVibrate */, sensorStrength);
setRequestId(requestId);
mLockoutFrameworkImpl = lockoutTracker;
- mSensorOverlays = new SensorOverlays(udfpsOverlayController,
- sidefpsController, udfpsOverlay);
+ mSensorOverlays = new SensorOverlays(udfpsOverlayController, sidefpsController);
mSensorProps = sensorProps;
mALSProbeCallback = getLogger().getAmbientLightProbe(false /* startWithClient */);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
index ed0a201..0d7f9f2 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
@@ -26,7 +26,6 @@
import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
import android.hardware.fingerprint.FingerprintAuthenticateOptions;
import android.hardware.fingerprint.FingerprintManager;
-import android.hardware.fingerprint.IUdfpsOverlay;
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.os.IBinder;
import android.os.RemoteException;
@@ -67,13 +66,12 @@
@NonNull FingerprintAuthenticateOptions options,
@NonNull BiometricLogger biometricLogger, @NonNull BiometricContext biometricContext,
@Nullable IUdfpsOverlayController udfpsOverlayController,
- @Nullable IUdfpsOverlay udfpsOverlay, boolean isStrongBiometric) {
+ boolean isStrongBiometric) {
super(context, lazyDaemon, token, listener, options.getUserId(),
options.getOpPackageName(), 0 /* cookie */, options.getSensorId(),
true /* shouldVibrate */, biometricLogger, biometricContext);
setRequestId(requestId);
- mSensorOverlays = new SensorOverlays(udfpsOverlayController,
- null /* sideFpsController */, udfpsOverlay);
+ mSensorOverlays = new SensorOverlays(udfpsOverlayController, null /* sideFpsController */);
mIsStrongBiometric = isStrongBiometric;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
index c2b7944..6fee84a 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
@@ -27,7 +27,6 @@
import android.hardware.fingerprint.Fingerprint;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.ISidefpsController;
-import android.hardware.fingerprint.IUdfpsOverlay;
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.os.IBinder;
import android.os.RemoteException;
@@ -69,14 +68,12 @@
@NonNull BiometricLogger biometricLogger, @NonNull BiometricContext biometricContext,
@Nullable IUdfpsOverlayController udfpsOverlayController,
@Nullable ISidefpsController sidefpsController,
- @Nullable IUdfpsOverlay udfpsOverlay,
@FingerprintManager.EnrollReason int enrollReason) {
super(context, lazyDaemon, token, listener, userId, hardwareAuthToken, owner, utils,
timeoutSec, sensorId, true /* shouldVibrate */, biometricLogger,
biometricContext);
setRequestId(requestId);
- mSensorOverlays = new SensorOverlays(udfpsOverlayController,
- sidefpsController, udfpsOverlay);
+ mSensorOverlays = new SensorOverlays(udfpsOverlayController, sidefpsController);
mEnrollReason = enrollReason;
if (enrollReason == FingerprintManager.ENROLL_FIND_SENSOR) {
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
index b0b1d67..ba9e280 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
@@ -352,7 +352,6 @@
clearCurMethodAndSessions();
mService.clearInputShownLocked();
mService.unbindCurrentClientLocked(UnbindReason.DISCONNECT_IME);
- mService.resetSystemUiLocked();
}
}
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 4dbd820..1ab83f7 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -48,6 +48,7 @@
import static com.android.server.inputmethod.ImeVisibilityStateComputer.ImeTargetWindowState;
import static com.android.server.inputmethod.ImeVisibilityStateComputer.ImeVisibilityResult;
+import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_HIDE_IME;
import static com.android.server.inputmethod.InputMethodBindingController.TIME_TO_RECONNECT;
import static com.android.server.inputmethod.InputMethodUtils.isSoftInputModeStateVisibleAllowed;
@@ -633,9 +634,8 @@
private InputMethodSubtype mCurrentSubtype;
/**
- * {@code true} if the IME has not been mostly hidden via {@link android.view.InsetsController}.
+ * {@code true} if the IME has not been mostly hidden via {@link android.view.InsetsController}
*/
- @GuardedBy("ImfLock.class")
private boolean mCurPerceptible;
/**
@@ -749,26 +749,33 @@
SparseArray<AccessibilitySessionState> mEnabledAccessibilitySessions = new SparseArray<>();
/**
- * {@code true} if the device is currently interactive with the user, initially true.
- *
- * @see #handleSetInteractive
+ * True if the device is currently interactive with user. The value is true initially.
*/
- @GuardedBy("ImfLock.class")
boolean mIsInteractive = true;
- @GuardedBy("ImfLock.class")
- @InputMethodService.BackDispositionMode
int mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT;
/**
- * The {@link InputMethodService.ImeWindowVisibility} of the currently bound IME,
- * or {@code 0} if no IME is bound.
+ * A set of status bits regarding the active IME.
*
- * <p><em>Do not update this value outside of {@link #setImeWindowStatus(IBinder, int, int)} and
+ * <p>This value is a combination of following two bits:</p>
+ * <dl>
+ * <dt>{@link InputMethodService#IME_ACTIVE}</dt>
+ * <dd>
+ * If this bit is ON, connected IME is ready to accept touch/key events.
+ * </dd>
+ * <dt>{@link InputMethodService#IME_VISIBLE}</dt>
+ * <dd>
+ * If this bit is ON, some of IME view, e.g. software input, candidate view, is visible.
+ * </dd>
+ * <dt>{@link InputMethodService#IME_INVISIBLE}</dt>
+ * <dd> If this bit is ON, IME is ready with views from last EditorInfo but is
+ * currently invisible.
+ * </dd>
+ * </dl>
+ * <em>Do not update this value outside of {@link #setImeWindowStatus(IBinder, int, int)} and
* {@link InputMethodBindingController#unbindCurrentMethod()}.</em>
*/
- @GuardedBy("ImfLock.class")
- @InputMethodService.ImeWindowVisibility
int mImeWindowVis;
private LocaleList mLastSystemLocales;
@@ -1529,6 +1536,7 @@
// Uh oh, current input method is no longer around!
// Pick another one...
Slog.i(TAG, "Current input method removed: " + curInputMethodId);
+ updateSystemUiLocked(0 /* vis */, mBackDisposition);
if (!chooseNewDefaultIMELocked()) {
changed = true;
curIm = null;
@@ -2360,6 +2368,28 @@
}
}
+ /**
+ * Called when {@link #resetCurrentMethodAndClientLocked(int)} invoked for clean-up states
+ * before unbinding the current method.
+ */
+ @GuardedBy("ImfLock.class")
+ void onUnbindCurrentMethodByReset() {
+ final ImeTargetWindowState winState = mVisibilityStateComputer.getWindowStateOrNull(
+ mCurFocusedWindow);
+ if (winState != null && !winState.isRequestedImeVisible()
+ && !mVisibilityStateComputer.isInputShown()) {
+ // Normally, the focus window will apply the IME visibility state to
+ // WindowManager when the IME has applied it. But it would be too late when
+ // switching IMEs in between different users. (Since the focused IME will
+ // first unbind the service to switch to bind the next user of the IME
+ // service, that wouldn't make the attached IME token validity check in time)
+ // As a result, we have to notify WM to apply IME visibility before clearing the
+ // binding states in the first place.
+ mVisibilityApplier.applyImeVisibility(mCurFocusedWindow, mCurStatsToken,
+ STATE_HIDE_IME);
+ }
+ }
+
/** {@code true} when a {@link ClientState} has attached from starting the input connection. */
@GuardedBy("ImfLock.class")
boolean hasAttachedClient() {
@@ -2831,6 +2861,8 @@
@GuardedBy("ImfLock.class")
void resetCurrentMethodAndClientLocked(@UnbindReason int unbindClientReason) {
setSelectedMethodIdLocked(null);
+ // Callback before clean-up binding states.
+ onUnbindCurrentMethodByReset();
mBindingController.unbindCurrentMethod();
unbindCurrentClientLocked(unbindClientReason);
}
@@ -2931,6 +2963,7 @@
sessionState.mSession.finishSession();
} catch (RemoteException e) {
Slog.w(TAG, "Session failed to close due to remote exception", e);
+ updateSystemUiLocked(0 /* vis */, mBackDisposition);
}
sessionState.mSession = null;
}
@@ -3040,8 +3073,7 @@
}
@GuardedBy("ImfLock.class")
- private boolean shouldShowImeSwitcherLocked(
- @InputMethodService.ImeWindowVisibility int visibility) {
+ private boolean shouldShowImeSwitcherLocked(int visibility) {
if (!mShowOngoingImeSwitcherForPhones) return false;
// When the IME switcher dialog is shown, the IME switcher button should be hidden.
if (mMenuController.getSwitchingDialogLocked() != null) return false;
@@ -3053,7 +3085,8 @@
&& mWindowManagerInternal.isKeyguardSecure(mSettings.getCurrentUserId())) {
return false;
}
- if ((visibility & InputMethodService.IME_ACTIVE) == 0) {
+ if ((visibility & InputMethodService.IME_ACTIVE) == 0
+ || (visibility & InputMethodService.IME_INVISIBLE) != 0) {
return false;
}
if (mWindowManagerInternal.isHardKeyboardAvailable()) {
@@ -3112,9 +3145,7 @@
@BinderThread
@SuppressWarnings("deprecation")
- private void setImeWindowStatus(@NonNull IBinder token,
- @InputMethodService.ImeWindowVisibility int vis,
- @InputMethodService.BackDispositionMode int backDisposition) {
+ private void setImeWindowStatus(@NonNull IBinder token, int vis, int backDisposition) {
final int topFocusedDisplayId = mWindowManagerInternal.getTopFocusedDisplayId();
synchronized (ImfLock.class) {
@@ -3131,7 +3162,7 @@
}
mImeWindowVis = vis;
mBackDisposition = backDisposition;
- updateSystemUiLocked(mImeWindowVis, mBackDisposition);
+ updateSystemUiLocked(vis, backDisposition);
}
final boolean dismissImeOnBackKeyPressed;
@@ -3166,46 +3197,37 @@
private void updateImeWindowStatus(boolean disableImeIcon) {
synchronized (ImfLock.class) {
- // TODO(b/285109020): disableImeIcon should be stored in a property like
- // mIsSwitcherIconDisabled, but it is currently not reliably cleared.
- updateSystemUiLocked(disableImeIcon ? 0 : mImeWindowVis, mBackDisposition);
+ if (disableImeIcon) {
+ updateSystemUiLocked(0, mBackDisposition);
+ } else {
+ updateSystemUiLocked();
+ }
}
}
@GuardedBy("ImfLock.class")
void updateSystemUiLocked() {
- // This is only used by InputMethodMenuController to trigger the IME switcher icon
- // visibility, by having {@code shouldShowImeSwitcherLocked} called, which depends on the
- // visibility of the IME switcher dialog.
updateSystemUiLocked(mImeWindowVis, mBackDisposition);
}
// Caution! This method is called in this class. Handle multi-user carefully
@GuardedBy("ImfLock.class")
- private void updateSystemUiLocked(@InputMethodService.ImeWindowVisibility int vis,
- @InputMethodService.BackDispositionMode int backDisposition) {
+ private void updateSystemUiLocked(int vis, int backDisposition) {
if (getCurTokenLocked() == null) {
return;
}
if (DEBUG) {
Slog.d(TAG, "IME window vis: " + vis
- + " active: " + ((vis & InputMethodService.IME_ACTIVE) != 0)
- + " visible: " + ((vis & InputMethodService.IME_VISIBLE) != 0)
- + " backDisposition: " + backDisposition
- + " isInteractive: " + mIsInteractive
- + " curPerceptible: " + mCurPerceptible
+ + " active: " + (vis & InputMethodService.IME_ACTIVE)
+ + " inv: " + (vis & InputMethodService.IME_INVISIBLE)
+ " displayId: " + mCurTokenDisplayId);
}
// TODO: Move this clearing calling identity block to setImeWindowStatus after making sure
- // all updateSystemUi happens on system privilege.
+ // all updateSystemUi happens on system privilege.
final long ident = Binder.clearCallingIdentity();
try {
- if (!mIsInteractive) {
- // When we are not interactive,
- // the visibility should be 0 (no IME icons should be shown).
- vis = 0;
- } else if (!mCurPerceptible) {
+ if (!mCurPerceptible) {
if ((vis & InputMethodService.IME_VISIBLE) != 0) {
vis &= ~InputMethodService.IME_VISIBLE;
vis |= InputMethodService.IME_VISIBLE_IMPERCEPTIBLE;
@@ -3540,7 +3562,7 @@
return;
}
mCurPerceptible = perceptible;
- updateSystemUiLocked(mImeWindowVis, mBackDisposition);
+ updateSystemUiLocked();
}
});
}
@@ -5102,11 +5124,8 @@
private void handleSetInteractive(final boolean interactive) {
synchronized (ImfLock.class) {
- if (mIsInteractive == interactive) {
- return;
- }
mIsInteractive = interactive;
- updateSystemUiLocked(mImeWindowVis, mBackDisposition);
+ updateSystemUiLocked(interactive ? mImeWindowVis : 0, mBackDisposition);
// Inform the current client of the change in active status
if (mCurClient == null || mCurClient.mClient == null) {
@@ -6741,8 +6760,7 @@
@BinderThread
@Override
- public void setImeWindowStatusAsync(@InputMethodService.ImeWindowVisibility int vis,
- @InputMethodService.BackDispositionMode int backDisposition) {
+ public void setImeWindowStatusAsync(int vis, int backDisposition) {
mImms.setImeWindowStatus(mToken, vis, backDisposition);
}
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 0292a99..b2d3fca 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -103,7 +103,7 @@
final int mTargetSdkVersion;
final int mOriginalFlags;
private final Context mContext;
- private final KeyguardManager mKeyguardManager;
+ private KeyguardManager mKeyguardManager;
private final PowerManager mPowerManager;
NotificationUsageStats.SingleNotificationStats stats;
boolean isCanceled;
@@ -1625,10 +1625,21 @@
}
boolean isLocked() {
- return mKeyguardManager.isKeyguardLocked()
+ return getKeyguardManager().isKeyguardLocked()
|| !mPowerManager.isInteractive(); // Unlocked AOD
}
+ /**
+ * For some early {@link NotificationRecord}, {@link KeyguardManager} can be {@code null} in
+ * the constructor. Retrieve it again if it is null.
+ */
+ private KeyguardManager getKeyguardManager() {
+ if (mKeyguardManager == null) {
+ mKeyguardManager = mContext.getSystemService(KeyguardManager.class);
+ }
+ return mKeyguardManager;
+ }
+
@VisibleForTesting
static final class Light {
public final int color;
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 7fda092..2411820 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -337,7 +337,7 @@
final long previousFirstInstallTime =
replacedPkgSetting.getUserStateOrDefault(userId).getFirstInstallTimeMillis();
if (previousFirstInstallTime != 0) {
- modifyUserState(userId).setFirstInstallTime(previousFirstInstallTime);
+ modifyUserState(userId).setFirstInstallTimeMillis(previousFirstInstallTime);
}
}
onChanged();
@@ -352,10 +352,10 @@
if (userId == UserHandle.USER_ALL) {
int userStateCount = mUserStates.size();
for (int i = 0; i < userStateCount; i++) {
- mUserStates.valueAt(i).setFirstInstallTime(firstInstallTime);
+ mUserStates.valueAt(i).setFirstInstallTimeMillis(firstInstallTime);
}
} else {
- modifyUserState(userId).setFirstInstallTime(firstInstallTime);
+ modifyUserState(userId).setFirstInstallTimeMillis(firstInstallTime);
}
onChanged();
return this;
@@ -894,7 +894,7 @@
.setVirtualPreload(virtualPreload)
.setHarmfulAppWarning(harmfulAppWarning)
.setSplashScreenTheme(splashScreenTheme)
- .setFirstInstallTime(firstInstallTime);
+ .setFirstInstallTimeMillis(firstInstallTime);
onChanged();
}
diff --git a/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java b/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java
index ed4aab9..e8e2d41 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java
@@ -16,6 +16,7 @@
package com.android.server.pm.pkg;
+import android.annotation.CurrentTimeMillisLong;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ComponentName;
@@ -61,6 +62,7 @@
private int mDistractionFlags;
private boolean mInstantApp;
private boolean mVirtualPreload;
+ @PackageManager.EnabledState
private int mEnabledState = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
@PackageManager.InstallReason
private int mInstallReason = PackageManager.INSTALL_REASON_UNKNOWN;
@@ -90,7 +92,7 @@
@Nullable
private WatchedArrayMap<ComponentName, Pair<String, Integer>> mComponentLabelIconOverrideMap;
- private long mFirstInstallTime;
+ private @CurrentTimeMillisLong long mFirstInstallTimeMillis;
// TODO(b/239050028): Remove, enforce notifying parent through PMS commit method
@Nullable
@@ -147,7 +149,7 @@
mSuspendParams = other.mSuspendParams == null ? null : other.mSuspendParams.snapshot();
mComponentLabelIconOverrideMap = other.mComponentLabelIconOverrideMap == null
? null : other.mComponentLabelIconOverrideMap.snapshot();
- mFirstInstallTime = other.mFirstInstallTime;
+ mFirstInstallTimeMillis = other.mFirstInstallTimeMillis;
mSnapshot = new SnapshotCache.Sealed<>();
}
@@ -538,8 +540,8 @@
return this;
}
- public @NonNull PackageUserStateImpl setFirstInstallTime(long value) {
- mFirstInstallTime = value;
+ public @NonNull PackageUserStateImpl setFirstInstallTimeMillis(long value) {
+ mFirstInstallTimeMillis = value;
onChanged();
return this;
}
@@ -643,7 +645,7 @@
}
@DataClass.Generated.Member
- public int getEnabledState() {
+ public @PackageManager.EnabledState int getEnabledState() {
return mEnabledState;
}
@@ -691,8 +693,8 @@
}
@DataClass.Generated.Member
- public long getFirstInstallTimeMillis() {
- return mFirstInstallTime;
+ public @CurrentTimeMillisLong long getFirstInstallTimeMillis() {
+ return mFirstInstallTimeMillis;
}
@DataClass.Generated.Member
@@ -766,7 +768,7 @@
&& Objects.equals(mSplashScreenTheme, that.mSplashScreenTheme)
&& Objects.equals(mSuspendParams, that.mSuspendParams)
&& Objects.equals(mComponentLabelIconOverrideMap, that.mComponentLabelIconOverrideMap)
- && mFirstInstallTime == that.mFirstInstallTime
+ && mFirstInstallTimeMillis == that.mFirstInstallTimeMillis
&& watchableEquals(that.mWatchable)
&& snapshotEquals(that.mSnapshot);
}
@@ -798,17 +800,17 @@
_hash = 31 * _hash + Objects.hashCode(mSplashScreenTheme);
_hash = 31 * _hash + Objects.hashCode(mSuspendParams);
_hash = 31 * _hash + Objects.hashCode(mComponentLabelIconOverrideMap);
- _hash = 31 * _hash + Long.hashCode(mFirstInstallTime);
+ _hash = 31 * _hash + Long.hashCode(mFirstInstallTimeMillis);
_hash = 31 * _hash + watchableHashCode();
_hash = 31 * _hash + snapshotHashCode();
return _hash;
}
@DataClass.Generated(
- time = 1668033772891L,
+ time = 1686952839807L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java",
- inputSignatures = "protected @android.annotation.Nullable com.android.server.utils.WatchedArraySet<java.lang.String> mDisabledComponentsWatched\nprotected @android.annotation.Nullable com.android.server.utils.WatchedArraySet<java.lang.String> mEnabledComponentsWatched\nprivate long mCeDataInode\nprivate boolean mInstalled\nprivate boolean mStopped\nprivate boolean mNotLaunched\nprivate boolean mHidden\nprivate int mDistractionFlags\nprivate boolean mInstantApp\nprivate boolean mVirtualPreload\nprivate int mEnabledState\nprivate @android.content.pm.PackageManager.InstallReason int mInstallReason\nprivate @android.content.pm.PackageManager.UninstallReason int mUninstallReason\nprivate @android.annotation.Nullable java.lang.String mHarmfulAppWarning\nprivate @android.annotation.Nullable java.lang.String mLastDisableAppCaller\nprivate @android.annotation.Nullable android.content.pm.overlay.OverlayPaths mOverlayPaths\nprotected @android.annotation.Nullable com.android.server.utils.WatchedArrayMap<java.lang.String,android.content.pm.overlay.OverlayPaths> mSharedLibraryOverlayPaths\nprivate @android.annotation.Nullable java.lang.String mSplashScreenTheme\nprivate @android.annotation.Nullable com.android.server.utils.WatchedArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams> mSuspendParams\nprivate @android.annotation.Nullable com.android.server.utils.WatchedArrayMap<android.content.ComponentName,android.util.Pair<java.lang.String,java.lang.Integer>> mComponentLabelIconOverrideMap\nprivate long mFirstInstallTime\nprivate @android.annotation.Nullable com.android.server.utils.Watchable mWatchable\nfinal @android.annotation.NonNull com.android.server.utils.SnapshotCache<com.android.server.pm.pkg.PackageUserStateImpl> mSnapshot\nprivate com.android.server.utils.SnapshotCache<com.android.server.pm.pkg.PackageUserStateImpl> makeCache()\nprivate void onChanged()\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageUserStateImpl snapshot()\npublic @android.annotation.Nullable boolean setOverlayPaths(android.content.pm.overlay.OverlayPaths)\npublic boolean setSharedLibraryOverlayPaths(java.lang.String,android.content.pm.overlay.OverlayPaths)\npublic @android.annotation.Nullable @java.lang.Override com.android.server.utils.WatchedArraySet<java.lang.String> getDisabledComponentsNoCopy()\npublic @android.annotation.Nullable @java.lang.Override com.android.server.utils.WatchedArraySet<java.lang.String> getEnabledComponentsNoCopy()\npublic @android.annotation.NonNull @java.lang.Override android.util.ArraySet<java.lang.String> getDisabledComponents()\npublic @android.annotation.NonNull @java.lang.Override android.util.ArraySet<java.lang.String> getEnabledComponents()\npublic @java.lang.Override boolean isComponentEnabled(java.lang.String)\npublic @java.lang.Override boolean isComponentDisabled(java.lang.String)\npublic @java.lang.Override android.content.pm.overlay.OverlayPaths getAllOverlayPaths()\npublic @com.android.internal.annotations.VisibleForTesting boolean overrideLabelAndIcon(android.content.ComponentName,java.lang.String,java.lang.Integer)\npublic void resetOverrideComponentLabelIcon()\npublic @android.annotation.Nullable android.util.Pair<java.lang.String,java.lang.Integer> getOverrideLabelIconForComponent(android.content.ComponentName)\npublic @java.lang.Override boolean isSuspended()\npublic com.android.server.pm.pkg.PackageUserStateImpl putSuspendParams(java.lang.String,com.android.server.pm.pkg.SuspendParams)\npublic com.android.server.pm.pkg.PackageUserStateImpl removeSuspension(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDisabledComponents(android.util.ArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledComponents(android.util.ArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDisabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setCeDataInode(long)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstalled(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setStopped(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setNotLaunched(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setHidden(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDistractionFlags(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstantApp(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setVirtualPreload(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledState(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstallReason(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setUninstallReason(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setHarmfulAppWarning(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setLastDisableAppCaller(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSharedLibraryOverlayPaths(android.util.ArrayMap<java.lang.String,android.content.pm.overlay.OverlayPaths>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSplashScreenTheme(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSuspendParams(android.util.ArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setComponentLabelIconOverrideMap(android.util.ArrayMap<android.content.ComponentName,android.util.Pair<java.lang.String,java.lang.Integer>>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setFirstInstallTime(long)\npublic @android.annotation.NonNull @java.lang.Override java.util.Map<java.lang.String,android.content.pm.overlay.OverlayPaths> getSharedLibraryOverlayPaths()\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setWatchable(com.android.server.utils.Watchable)\nprivate boolean watchableEquals(com.android.server.utils.Watchable)\nprivate int watchableHashCode()\nprivate boolean snapshotEquals(com.android.server.utils.SnapshotCache<com.android.server.pm.pkg.PackageUserStateImpl>)\nprivate int snapshotHashCode()\nclass PackageUserStateImpl extends com.android.server.utils.WatchableImpl implements [com.android.server.pm.pkg.PackageUserStateInternal, com.android.server.utils.Snappable]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=false, genEqualsHashCode=true)")
+ inputSignatures = "protected @android.annotation.Nullable com.android.server.utils.WatchedArraySet<java.lang.String> mDisabledComponentsWatched\nprotected @android.annotation.Nullable com.android.server.utils.WatchedArraySet<java.lang.String> mEnabledComponentsWatched\nprivate long mCeDataInode\nprivate boolean mInstalled\nprivate boolean mStopped\nprivate boolean mNotLaunched\nprivate boolean mHidden\nprivate int mDistractionFlags\nprivate boolean mInstantApp\nprivate boolean mVirtualPreload\nprivate @android.content.pm.PackageManager.EnabledState int mEnabledState\nprivate @android.content.pm.PackageManager.InstallReason int mInstallReason\nprivate @android.content.pm.PackageManager.UninstallReason int mUninstallReason\nprivate @android.annotation.Nullable java.lang.String mHarmfulAppWarning\nprivate @android.annotation.Nullable java.lang.String mLastDisableAppCaller\nprivate @android.annotation.Nullable android.content.pm.overlay.OverlayPaths mOverlayPaths\nprotected @android.annotation.Nullable com.android.server.utils.WatchedArrayMap<java.lang.String,android.content.pm.overlay.OverlayPaths> mSharedLibraryOverlayPaths\nprivate @android.annotation.Nullable java.lang.String mSplashScreenTheme\nprivate @android.annotation.Nullable com.android.server.utils.WatchedArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams> mSuspendParams\nprivate @android.annotation.Nullable com.android.server.utils.WatchedArrayMap<android.content.ComponentName,android.util.Pair<java.lang.String,java.lang.Integer>> mComponentLabelIconOverrideMap\nprivate @android.annotation.CurrentTimeMillisLong long mFirstInstallTimeMillis\nprivate @android.annotation.Nullable com.android.server.utils.Watchable mWatchable\nfinal @android.annotation.NonNull com.android.server.utils.SnapshotCache<com.android.server.pm.pkg.PackageUserStateImpl> mSnapshot\nprivate com.android.server.utils.SnapshotCache<com.android.server.pm.pkg.PackageUserStateImpl> makeCache()\nprivate void onChanged()\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageUserStateImpl snapshot()\npublic @android.annotation.Nullable boolean setOverlayPaths(android.content.pm.overlay.OverlayPaths)\npublic boolean setSharedLibraryOverlayPaths(java.lang.String,android.content.pm.overlay.OverlayPaths)\npublic @android.annotation.Nullable @java.lang.Override com.android.server.utils.WatchedArraySet<java.lang.String> getDisabledComponentsNoCopy()\npublic @android.annotation.Nullable @java.lang.Override com.android.server.utils.WatchedArraySet<java.lang.String> getEnabledComponentsNoCopy()\npublic @android.annotation.NonNull @java.lang.Override android.util.ArraySet<java.lang.String> getDisabledComponents()\npublic @android.annotation.NonNull @java.lang.Override android.util.ArraySet<java.lang.String> getEnabledComponents()\npublic @java.lang.Override boolean isComponentEnabled(java.lang.String)\npublic @java.lang.Override boolean isComponentDisabled(java.lang.String)\npublic @java.lang.Override android.content.pm.overlay.OverlayPaths getAllOverlayPaths()\npublic @com.android.internal.annotations.VisibleForTesting boolean overrideLabelAndIcon(android.content.ComponentName,java.lang.String,java.lang.Integer)\npublic void resetOverrideComponentLabelIcon()\npublic @android.annotation.Nullable android.util.Pair<java.lang.String,java.lang.Integer> getOverrideLabelIconForComponent(android.content.ComponentName)\npublic @java.lang.Override boolean isSuspended()\npublic com.android.server.pm.pkg.PackageUserStateImpl putSuspendParams(java.lang.String,com.android.server.pm.pkg.SuspendParams)\npublic com.android.server.pm.pkg.PackageUserStateImpl removeSuspension(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDisabledComponents(android.util.ArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledComponents(android.util.ArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDisabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setCeDataInode(long)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstalled(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setStopped(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setNotLaunched(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setHidden(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDistractionFlags(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstantApp(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setVirtualPreload(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledState(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstallReason(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setUninstallReason(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setHarmfulAppWarning(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setLastDisableAppCaller(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSharedLibraryOverlayPaths(android.util.ArrayMap<java.lang.String,android.content.pm.overlay.OverlayPaths>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSplashScreenTheme(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSuspendParams(android.util.ArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setComponentLabelIconOverrideMap(android.util.ArrayMap<android.content.ComponentName,android.util.Pair<java.lang.String,java.lang.Integer>>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setFirstInstallTimeMillis(long)\npublic @android.annotation.NonNull @java.lang.Override java.util.Map<java.lang.String,android.content.pm.overlay.OverlayPaths> getSharedLibraryOverlayPaths()\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setWatchable(com.android.server.utils.Watchable)\nprivate boolean watchableEquals(com.android.server.utils.Watchable)\nprivate int watchableHashCode()\nprivate boolean snapshotEquals(com.android.server.utils.SnapshotCache<com.android.server.pm.pkg.PackageUserStateImpl>)\nprivate int snapshotHashCode()\nclass PackageUserStateImpl extends com.android.server.utils.WatchableImpl implements [com.android.server.pm.pkg.PackageUserStateInternal, com.android.server.utils.Snappable]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=false, genEqualsHashCode=true)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index 6e9a22c..efd8b6d 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -19,7 +19,6 @@
import android.annotation.Nullable;
import android.app.ITransientNotificationCallback;
import android.hardware.fingerprint.IUdfpsRefreshRateRequestCallback;
-import android.inputmethodservice.InputMethodService;
import android.os.Bundle;
import android.os.IBinder;
import android.view.WindowInsets.Type.InsetsType;
@@ -55,13 +54,13 @@
* @param displayId The display to which the IME is bound to.
* @param token The IME token.
* @param vis Bit flags about the IME visibility.
+ * (e.g. {@link android.inputmethodservice.InputMethodService#IME_ACTIVE})
* @param backDisposition Bit flags about the IME back disposition.
+ * (e.g. {@link android.inputmethodservice.InputMethodService#BACK_DISPOSITION_DEFAULT})
* @param showImeSwitcher {@code true} when the IME switcher button should be shown.
*/
- void setImeWindowStatus(int displayId, IBinder token,
- @InputMethodService.ImeWindowVisibility int vis,
- @InputMethodService.BackDispositionMode int backDisposition,
- boolean showImeSwitcher);
+ void setImeWindowStatus(int displayId, IBinder token, int vis,
+ int backDisposition, boolean showImeSwitcher);
/**
* See {@link android.app.StatusBarManager#setIcon(String, int, int, String)}.
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 719b2d2..cc849b6 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -59,7 +59,6 @@
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManager.DisplayListener;
import android.hardware.fingerprint.IUdfpsRefreshRateRequestCallback;
-import android.inputmethodservice.InputMethodService;
import android.media.INearbyMediaDevicesProvider;
import android.media.MediaRoute2Info;
import android.net.Uri;
@@ -347,9 +346,10 @@
@Override
public void showScreenPinningRequest(int taskId) {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.showScreenPinningRequest(taskId);
+ bar.showScreenPinningRequest(taskId);
} catch (RemoteException e) {
}
}
@@ -357,9 +357,10 @@
@Override
public void showAssistDisclosure() {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.showAssistDisclosure();
+ bar.showAssistDisclosure();
} catch (RemoteException e) {
}
}
@@ -367,9 +368,10 @@
@Override
public void startAssist(Bundle args) {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.startAssist(args);
+ bar.startAssist(args);
} catch (RemoteException e) {
}
}
@@ -377,9 +379,10 @@
@Override
public void onCameraLaunchGestureDetected(int source) {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.onCameraLaunchGestureDetected(source);
+ bar.onCameraLaunchGestureDetected(source);
} catch (RemoteException e) {
}
}
@@ -393,9 +396,10 @@
@Override
public void onEmergencyActionLaunchGestureDetected() {
if (SPEW) Slog.d(TAG, "Launching emergency action");
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.onEmergencyActionLaunchGestureDetected();
+ bar.onEmergencyActionLaunchGestureDetected();
} catch (RemoteException e) {
if (SPEW) Slog.d(TAG, "Failed to launch emergency action");
}
@@ -410,9 +414,10 @@
@Override
public void toggleSplitScreen() {
enforceStatusBarService();
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.toggleSplitScreen();
+ bar.toggleSplitScreen();
} catch (RemoteException ex) {}
}
}
@@ -420,27 +425,30 @@
@Override
public void appTransitionFinished(int displayId) {
enforceStatusBarService();
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.appTransitionFinished(displayId);
+ bar.appTransitionFinished(displayId);
} catch (RemoteException ex) {}
}
}
@Override
public void toggleTaskbar() {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.toggleTaskbar();
+ bar.toggleTaskbar();
} catch (RemoteException ex) {}
}
}
@Override
public void toggleRecentApps() {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.toggleRecentApps();
+ bar.toggleRecentApps();
} catch (RemoteException ex) {}
}
}
@@ -454,45 +462,50 @@
@Override
public void preloadRecentApps() {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.preloadRecentApps();
+ bar.preloadRecentApps();
} catch (RemoteException ex) {}
}
}
@Override
public void cancelPreloadRecentApps() {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.cancelPreloadRecentApps();
+ bar.cancelPreloadRecentApps();
} catch (RemoteException ex) {}
}
}
@Override
public void showRecentApps(boolean triggeredFromAltTab) {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.showRecentApps(triggeredFromAltTab);
+ bar.showRecentApps(triggeredFromAltTab);
} catch (RemoteException ex) {}
}
}
@Override
public void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.hideRecentApps(triggeredFromAltTab, triggeredFromHomeKey);
+ bar.hideRecentApps(triggeredFromAltTab, triggeredFromHomeKey);
} catch (RemoteException ex) {}
}
}
@Override
public void collapsePanels() {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.animateCollapsePanels();
+ bar.animateCollapsePanels();
} catch (RemoteException ex) {
}
}
@@ -500,26 +513,26 @@
@Override
public void dismissKeyboardShortcutsMenu() {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.dismissKeyboardShortcutsMenu();
+ bar.dismissKeyboardShortcutsMenu();
} catch (RemoteException ex) {}
}
}
@Override
public void toggleKeyboardShortcutsMenu(int deviceId) {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.toggleKeyboardShortcutsMenu(deviceId);
+ bar.toggleKeyboardShortcutsMenu(deviceId);
} catch (RemoteException ex) {}
}
}
@Override
- public void setImeWindowStatus(int displayId, IBinder token,
- @InputMethodService.ImeWindowVisibility int vis,
- @InputMethodService.BackDispositionMode int backDisposition,
+ public void setImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition,
boolean showImeSwitcher) {
StatusBarManagerService.this.setImeWindowStatus(displayId, token, vis, backDisposition,
showImeSwitcher);
@@ -539,9 +552,10 @@
@Override
public void showChargingAnimation(int batteryLevel) {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.showWirelessChargingAnimation(batteryLevel);
+ bar.showWirelessChargingAnimation(batteryLevel);
} catch (RemoteException ex){
}
}
@@ -549,7 +563,8 @@
@Override
public void showPictureInPictureMenu() {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
mBar.showPictureInPictureMenu();
} catch (RemoteException ex) {}
@@ -558,27 +573,30 @@
@Override
public void setWindowState(int displayId, int window, int state) {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.setWindowState(displayId, window, state);
+ bar.setWindowState(displayId, window, state);
} catch (RemoteException ex) {}
}
}
@Override
public void appTransitionPending(int displayId) {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.appTransitionPending(displayId);
+ bar.appTransitionPending(displayId);
} catch (RemoteException ex) {}
}
}
@Override
public void appTransitionCancelled(int displayId) {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.appTransitionCancelled(displayId);
+ bar.appTransitionCancelled(displayId);
} catch (RemoteException ex) {}
}
}
@@ -586,9 +604,10 @@
@Override
public void appTransitionStarting(int displayId, long statusBarAnimationsStartTime,
long statusBarAnimationsDuration) {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.appTransitionStarting(
+ bar.appTransitionStarting(
displayId, statusBarAnimationsStartTime, statusBarAnimationsDuration);
} catch (RemoteException ex) {}
}
@@ -596,9 +615,10 @@
@Override
public void setTopAppHidesStatusBar(boolean hidesStatusBar) {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.setTopAppHidesStatusBar(hidesStatusBar);
+ bar.setTopAppHidesStatusBar(hidesStatusBar);
} catch (RemoteException ex) {}
}
}
@@ -608,9 +628,10 @@
if (!mContext.getResources().getBoolean(R.bool.config_showSysuiShutdown)) {
return false;
}
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.showShutdownUi(isReboot, reason);
+ bar.showShutdownUi(isReboot, reason);
return true;
} catch (RemoteException ex) {}
}
@@ -629,18 +650,20 @@
@Override
public void onDisplayReady(int displayId) {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.onDisplayReady(displayId);
+ bar.onDisplayReady(displayId);
} catch (RemoteException ex) {}
}
}
@Override
public void onRecentsAnimationStateChanged(boolean running) {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.onRecentsAnimationStateChanged(running);
+ bar.onRecentsAnimationStateChanged(running);
} catch (RemoteException ex) {}
}
@@ -654,9 +677,10 @@
getUiState(displayId).setBarAttributes(appearance, appearanceRegions,
navbarColorManagedByIme, behavior, requestedVisibleTypes, packageName,
letterboxDetails);
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.onSystemBarAttributesChanged(displayId, appearance, appearanceRegions,
+ bar.onSystemBarAttributesChanged(displayId, appearance, appearanceRegions,
navbarColorManagedByIme, behavior, requestedVisibleTypes, packageName,
letterboxDetails);
} catch (RemoteException ex) { }
@@ -667,9 +691,10 @@
public void showTransient(int displayId, @InsetsType int types,
boolean isGestureOnSystemBar) {
getUiState(displayId).showTransient(types);
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.showTransient(displayId, types, isGestureOnSystemBar);
+ bar.showTransient(displayId, types, isGestureOnSystemBar);
} catch (RemoteException ex) { }
}
}
@@ -677,9 +702,10 @@
@Override
public void abortTransient(int displayId, @InsetsType int types) {
getUiState(displayId).clearTransient(types);
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.abortTransient(displayId, types);
+ bar.abortTransient(displayId, types);
} catch (RemoteException ex) { }
}
}
@@ -688,9 +714,10 @@
public void showToast(int uid, String packageName, IBinder token, CharSequence text,
IBinder windowToken, int duration,
@Nullable ITransientNotificationCallback callback, int displayId) {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.showToast(uid, packageName, token, text, windowToken, duration, callback,
+ bar.showToast(uid, packageName, token, text, windowToken, duration, callback,
displayId);
} catch (RemoteException ex) { }
}
@@ -698,18 +725,20 @@
@Override
public void hideToast(String packageName, IBinder token) {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.hideToast(packageName, token);
+ bar.hideToast(packageName, token);
} catch (RemoteException ex) { }
}
}
@Override
public boolean requestWindowMagnificationConnection(boolean request) {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.requestWindowMagnificationConnection(request);
+ bar.requestWindowMagnificationConnection(request);
return true;
} catch (RemoteException ex) { }
}
@@ -718,9 +747,10 @@
@Override
public void setNavigationBarLumaSamplingEnabled(int displayId, boolean enable) {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.setNavigationBarLumaSamplingEnabled(displayId, enable);
+ bar.setNavigationBarLumaSamplingEnabled(displayId, enable);
} catch (RemoteException ex) { }
}
}
@@ -730,45 +760,50 @@
synchronized (mLock) {
mUdfpsRefreshRateRequestCallback = callback;
}
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.setUdfpsRefreshRateCallback(callback);
+ bar.setUdfpsRefreshRateCallback(callback);
} catch (RemoteException ex) { }
}
}
@Override
public void showRearDisplayDialog(int currentBaseState) {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.showRearDisplayDialog(currentBaseState);
+ bar.showRearDisplayDialog(currentBaseState);
} catch (RemoteException ex) { }
}
}
@Override
public void goToFullscreenFromSplit() {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.goToFullscreenFromSplit();
+ bar.goToFullscreenFromSplit();
} catch (RemoteException ex) { }
}
}
@Override
public void enterStageSplitFromRunningApp(boolean leftOrTop) {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.enterStageSplitFromRunningApp(leftOrTop);
+ bar.enterStageSplitFromRunningApp(leftOrTop);
} catch (RemoteException ex) { }
}
}
@Override
public void showMediaOutputSwitcher(String packageName) {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.showMediaOutputSwitcher(packageName);
+ bar.showMediaOutputSwitcher(packageName);
} catch (RemoteException ex) {
}
}
@@ -791,9 +826,10 @@
@Override
public void showGlobalActions() {
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.showGlobalActionsMenu();
+ bar.showGlobalActionsMenu();
} catch (RemoteException ex) {}
}
}
@@ -1116,9 +1152,10 @@
if (!state.disableEquals(net1, net2)) {
state.setDisabled(net1, net2);
mHandler.post(() -> mNotificationDelegate.onSetDisabled(net1));
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.disable(displayId, net1, net2);
+ bar.disable(displayId, net1, net2);
} catch (RemoteException ex) {
}
}
@@ -1176,9 +1213,10 @@
//Slog.d(TAG, "setIcon slot=" + slot + " index=" + index + " icon=" + icon);
mIcons.put(slot, icon);
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.setIcon(slot, icon);
+ bar.setIcon(slot, icon);
} catch (RemoteException ex) {
}
}
@@ -1197,9 +1235,10 @@
if (icon.visible != visibility) {
icon.visible = visibility;
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.setIcon(slot, icon);
+ bar.setIcon(slot, icon);
} catch (RemoteException ex) {
}
}
@@ -1214,9 +1253,10 @@
synchronized (mIcons) {
mIcons.remove(slot);
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.removeIcon(slot);
+ bar.removeIcon(slot);
} catch (RemoteException ex) {
}
}
@@ -1224,14 +1264,12 @@
}
@Override
- public void setImeWindowStatus(int displayId, final IBinder token,
- @InputMethodService.ImeWindowVisibility final int vis,
- @InputMethodService.BackDispositionMode final int backDisposition,
- final boolean showImeSwitcher) {
+ public void setImeWindowStatus(int displayId, final IBinder token, final int vis,
+ final int backDisposition, final boolean showImeSwitcher) {
enforceStatusBar();
if (SPEW) {
- Slog.d(TAG, "setImeWindowStatus vis=" + vis + " backDisposition=" + backDisposition);
+ Slog.d(TAG, "swetImeWindowStatus vis=" + vis + " backDisposition=" + backDisposition);
}
synchronized(mLock) {
@@ -1294,9 +1332,7 @@
private String mPackageName = "none";
private int mDisabled1 = 0;
private int mDisabled2 = 0;
- @InputMethodService.ImeWindowVisibility
private int mImeWindowVis = 0;
- @InputMethodService.BackDispositionMode
private int mImeBackDisposition = 0;
private boolean mShowImeSwitcher = false;
private IBinder mImeToken = null;
@@ -1341,8 +1377,7 @@
return mDisabled1 == disabled1 && mDisabled2 == disabled2;
}
- private void setImeWindowState(@InputMethodService.ImeWindowVisibility final int vis,
- @InputMethodService.BackDispositionMode final int backDisposition,
+ private void setImeWindowState(final int vis, final int backDisposition,
final boolean showImeSwitcher, final IBinder token) {
mImeWindowVis = vis;
mImeBackDisposition = backDisposition;
@@ -1823,9 +1858,10 @@
@Override
public void showInattentiveSleepWarning() {
enforceStatusBarService();
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.showInattentiveSleepWarning();
+ bar.showInattentiveSleepWarning();
} catch (RemoteException ex) {
}
}
@@ -1834,9 +1870,10 @@
@Override
public void dismissInattentiveSleepWarning(boolean animated) {
enforceStatusBarService();
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.dismissInattentiveSleepWarning(animated);
+ bar.dismissInattentiveSleepWarning(animated);
} catch (RemoteException ex) {
}
}
@@ -1845,9 +1882,10 @@
@Override
public void suppressAmbientDisplay(boolean suppress) {
enforceStatusBarService();
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.suppressAmbientDisplay(suppress);
+ bar.suppressAmbientDisplay(suppress);
} catch (RemoteException ex) {
}
}
@@ -1921,9 +1959,10 @@
}
}
}
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.requestTileServiceListeningState(componentName);
+ bar.requestTileServiceListeningState(componentName);
} catch (RemoteException e) {
Slog.e(TAG, "requestTileServiceListeningState", e);
}
@@ -2036,9 +2075,10 @@
CharSequence appName = r.serviceInfo.applicationInfo
.loadLabel(mContext.getPackageManager());
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.requestAddTile(componentName, appName, label, icon, proxyCallback);
+ bar.requestAddTile(componentName, appName, label, icon, proxyCallback);
return;
} catch (RemoteException e) {
Slog.e(TAG, "requestAddTile", e);
@@ -2060,9 +2100,10 @@
private void cancelRequestAddTileInternal(String packageName) {
clearTileAddRequest(packageName);
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.cancelRequestAddTile(packageName);
+ bar.cancelRequestAddTile(packageName);
} catch (RemoteException e) {
Slog.e(TAG, "requestAddTile", e);
}
@@ -2191,9 +2232,10 @@
@Nullable IUndoMediaTransferCallback undoCallback
) {
enforceMediaContentControl();
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.updateMediaTapToTransferSenderDisplay(displayState, routeInfo, undoCallback);
+ bar.updateMediaTapToTransferSenderDisplay(displayState, routeInfo, undoCallback);
} catch (RemoteException e) {
Slog.e(TAG, "updateMediaTapToTransferSenderDisplay", e);
}
@@ -2214,9 +2256,10 @@
@Nullable Icon appIcon,
@Nullable CharSequence appName) {
enforceMediaContentControl();
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.updateMediaTapToTransferReceiverDisplay(
+ bar.updateMediaTapToTransferReceiverDisplay(
displayState, routeInfo, appIcon, appName);
} catch (RemoteException e) {
Slog.e(TAG, "updateMediaTapToTransferReceiverDisplay", e);
@@ -2240,9 +2283,10 @@
@NonNull INearbyMediaDevicesProvider provider
) {
enforceMediaContentControl();
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.registerNearbyMediaDevicesProvider(provider);
+ bar.registerNearbyMediaDevicesProvider(provider);
} catch (RemoteException e) {
Slog.e(TAG, "registerNearbyMediaDevicesProvider", e);
}
@@ -2265,9 +2309,10 @@
@NonNull INearbyMediaDevicesProvider provider
) {
enforceMediaContentControl();
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.unregisterNearbyMediaDevicesProvider(provider);
+ bar.unregisterNearbyMediaDevicesProvider(provider);
} catch (RemoteException e) {
Slog.e(TAG, "unregisterNearbyMediaDevicesProvider", e);
}
@@ -2278,9 +2323,10 @@
@Override
public void showRearDisplayDialog(int currentState) {
enforceControlDeviceStatePermission();
- if (mBar != null) {
+ IStatusBar bar = mBar;
+ if (bar != null) {
try {
- mBar.showRearDisplayDialog(currentState);
+ bar.showRearDisplayDialog(currentState);
} catch (RemoteException e) {
Slog.e(TAG, "showRearDisplayDialog", e);
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 788bfbc..0994fa4 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -4560,6 +4560,26 @@
}
task.forAllActivities(fromActivity -> {
if (fromActivity == this) return true;
+ // The snapshot starting window could remove itself when receive resized request without
+ // redraw, so transfer it to a different size activity could only cause flicker.
+ // By schedule remove snapshot starting window, the remove process will happen when
+ // transition ready, transition ready means the app window is drawn.
+ final StartingData tmpStartingData = fromActivity.mStartingData;
+ if (tmpStartingData != null && tmpStartingData.mAssociatedTask == null
+ && mTransitionController.isCollecting(fromActivity)
+ && tmpStartingData instanceof SnapshotStartingData) {
+ final Rect fromBounds = fromActivity.getBounds();
+ final Rect myBounds = getBounds();
+ if (!fromBounds.equals(myBounds)) {
+ // Mark as no animation, so these changes won't merge into playing transition.
+ if (mTransitionController.inPlayingTransition(fromActivity)) {
+ mTransitionController.setNoAnimation(this);
+ mTransitionController.setNoAnimation(fromActivity);
+ }
+ fromActivity.removeStartingWindow();
+ return true;
+ }
+ }
return !fromActivity.isVisibleRequested() && transferStartingWindow(fromActivity);
});
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 4a658d6..10ff3a3 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -546,6 +546,7 @@
*/
private volatile long mLastStopAppSwitchesTime;
+ @GuardedBy("itself")
private final List<AnrController> mAnrController = new ArrayList<>();
IActivityController mController = null;
boolean mControllerIsAMonkey = false;
@@ -733,7 +734,7 @@
private boolean mShowDialogs = true;
/** Set if we are shutting down the system, similar to sleeping. */
- boolean mShuttingDown = false;
+ volatile boolean mShuttingDown;
/**
* We want to hold a wake lock while running a voice interaction session, since
@@ -2298,14 +2299,14 @@
/** Register an {@link AnrController} to control the ANR dialog behavior */
public void registerAnrController(AnrController controller) {
- synchronized (mGlobalLock) {
+ synchronized (mAnrController) {
mAnrController.add(controller);
}
}
/** Unregister an {@link AnrController} */
public void unregisterAnrController(AnrController controller) {
- synchronized (mGlobalLock) {
+ synchronized (mAnrController) {
mAnrController.remove(controller);
}
}
@@ -2321,7 +2322,7 @@
}
final ArrayList<AnrController> controllers;
- synchronized (mGlobalLock) {
+ synchronized (mAnrController) {
controllers = new ArrayList<>(mAnrController);
}
@@ -6034,15 +6035,13 @@
@Override
public boolean isShuttingDown() {
- synchronized (mGlobalLock) {
- return mShuttingDown;
- }
+ return mShuttingDown;
}
@Override
public boolean shuttingDown(boolean booted, int timeout) {
+ mShuttingDown = true;
synchronized (mGlobalLock) {
- mShuttingDown = true;
mRootWindowContainer.prepareForShutdown();
updateEventDispatchingLocked(booted);
notifyTaskPersisterLocked(null, true);
diff --git a/services/core/java/com/android/server/wm/AppWarnings.java b/services/core/java/com/android/server/wm/AppWarnings.java
index f7ccc0d..0273a30 100644
--- a/services/core/java/com/android/server/wm/AppWarnings.java
+++ b/services/core/java/com/android/server/wm/AppWarnings.java
@@ -16,7 +16,9 @@
package com.android.server.wm;
+import android.annotation.NonNull;
import android.annotation.UiThread;
+import android.annotation.WorkerThread;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -30,14 +32,18 @@
import android.os.Looper;
import android.os.Message;
import android.os.SystemProperties;
+import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.DisplayMetrics;
import android.util.Slog;
import android.util.Xml;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.ArrayUtils;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
+import com.android.server.IoThread;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -45,9 +51,7 @@
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
+import java.util.concurrent.atomic.AtomicReference;
/**
* Manages warning dialogs shown during application lifecycle.
@@ -61,11 +65,12 @@
public static final int FLAG_HIDE_DEPRECATED_SDK = 0x04;
public static final int FLAG_HIDE_DEPRECATED_ABI = 0x08;
- private final HashMap<String, Integer> mPackageFlags = new HashMap<>();
+ @GuardedBy("mPackageFlags")
+ private final ArrayMap<String, Integer> mPackageFlags = new ArrayMap<>();
private final ActivityTaskManagerService mAtm;
private final Context mUiContext;
- private final ConfigHandler mHandler;
+ private final WriteConfigTask mWriteConfigTask;
private final UiHandler mUiHandler;
private final AtomicFile mConfigFile;
@@ -75,30 +80,20 @@
private DeprecatedAbiDialog mDeprecatedAbiDialog;
/** @see android.app.ActivityManager#alwaysShowUnsupportedCompileSdkWarning */
- private HashSet<ComponentName> mAlwaysShowUnsupportedCompileSdkWarningActivities =
- new HashSet<>();
+ private final ArraySet<ComponentName> mAlwaysShowUnsupportedCompileSdkWarningActivities =
+ new ArraySet<>();
/** @see android.app.ActivityManager#alwaysShowUnsupportedCompileSdkWarning */
void alwaysShowUnsupportedCompileSdkWarning(ComponentName activity) {
mAlwaysShowUnsupportedCompileSdkWarningActivities.add(activity);
}
- /**
- * Creates a new warning dialog manager.
- * <p>
- * <strong>Note:</strong> Must be called from the ActivityManagerService thread.
- *
- * @param atm
- * @param uiContext
- * @param handler
- * @param uiHandler
- * @param systemDir
- */
+ /** Creates a new warning dialog manager. */
public AppWarnings(ActivityTaskManagerService atm, Context uiContext, Handler handler,
Handler uiHandler, File systemDir) {
mAtm = atm;
mUiContext = uiContext;
- mHandler = new ConfigHandler(handler.getLooper());
+ mWriteConfigTask = new WriteConfigTask();
mUiHandler = new UiHandler(uiHandler.getLooper());
mConfigFile = new AtomicFile(new File(systemDir, CONFIG_FILE_NAME), "warnings-config");
@@ -256,8 +251,9 @@
mUiHandler.hideDialogsForPackage(name);
synchronized (mPackageFlags) {
- mPackageFlags.remove(name);
- mHandler.scheduleWrite();
+ if (mPackageFlags.remove(name) != null) {
+ mWriteConfigTask.schedule();
+ }
}
}
@@ -425,7 +421,7 @@
} else {
mPackageFlags.remove(name);
}
- mHandler.scheduleWrite();
+ mWriteConfigTask.schedule();
}
}
}
@@ -556,46 +552,30 @@
}
}
- /**
- * Handles messages on the ActivityTaskManagerService thread.
- */
- private final class ConfigHandler extends Handler {
- private static final int MSG_WRITE = 1;
-
- private static final int DELAY_MSG_WRITE = 10000;
-
- public ConfigHandler(Looper looper) {
- super(looper, null, true);
- }
+ private final class WriteConfigTask implements Runnable {
+ private static final long WRITE_CONFIG_DELAY_MS = 10000;
+ final AtomicReference<ArrayMap<String, Integer>> mPendingPackageFlags =
+ new AtomicReference<>();
@Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_WRITE:
- writeConfigToFileAmsThread();
- break;
+ public void run() {
+ final ArrayMap<String, Integer> packageFlags = mPendingPackageFlags.getAndSet(null);
+ if (packageFlags != null) {
+ writeConfigToFile(packageFlags);
}
}
- public void scheduleWrite() {
- removeMessages(MSG_WRITE);
- sendEmptyMessageDelayed(MSG_WRITE, DELAY_MSG_WRITE);
+ @GuardedBy("mPackageFlags")
+ void schedule() {
+ if (mPendingPackageFlags.getAndSet(new ArrayMap<>(mPackageFlags)) == null) {
+ IoThread.getHandler().postDelayed(this, WRITE_CONFIG_DELAY_MS);
+ }
}
}
- /**
- * Writes the configuration file.
- * <p>
- * <strong>Note:</strong> Should be called from the ActivityManagerService thread unless you
- * don't care where you're doing I/O operations. But you <i>do</i> care, don't you?
- */
- private void writeConfigToFileAmsThread() {
- // Create a shallow copy so that we don't have to synchronize on config.
- final HashMap<String, Integer> packageFlags;
- synchronized (mPackageFlags) {
- packageFlags = new HashMap<>(mPackageFlags);
- }
-
+ /** Writes the configuration file. */
+ @WorkerThread
+ private void writeConfigToFile(@NonNull ArrayMap<String, Integer> packageFlags) {
FileOutputStream fos = null;
try {
fos = mConfigFile.startWrite();
@@ -605,9 +585,9 @@
out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
out.startTag(null, "packages");
- for (Map.Entry<String, Integer> entry : packageFlags.entrySet()) {
- String pkg = entry.getKey();
- int mode = entry.getValue();
+ for (int i = 0; i < packageFlags.size(); i++) {
+ final String pkg = packageFlags.keyAt(i);
+ final int mode = packageFlags.valueAt(i);
if (mode == 0) {
continue;
}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 54fec3e..d9a954f 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -1061,8 +1061,10 @@
displayHasContent = true;
} else if (displayContent != null &&
(!mObscureApplicationContentOnSecondaryDisplays
+ || displayContent.isKeyguardAlwaysUnlocked()
|| (obscured && type == TYPE_KEYGUARD_DIALOG))) {
- // Allow full screen keyguard presentation dialogs to be seen.
+ // Allow full screen keyguard presentation dialogs to be seen, or simply ignore the
+ // keyguard if this display is always unlocked.
displayHasContent = true;
}
if ((privateflags & PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE) != 0) {
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 39772dda..9c23beb 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -3473,6 +3473,11 @@
top.mLetterboxUiController.getLetterboxPositionForVerticalReachability();
}
}
+ // User Aspect Ratio Settings is enabled if the app is not in SCM
+ info.topActivityEligibleForUserAspectRatioButton =
+ mWmService.mLetterboxConfiguration.isUserAppAspectRatioSettingsEnabled()
+ && top != null && !info.topActivityInSizeCompat;
+ info.topActivityBoundsLetterboxed = top != null && top.areBoundsLetterboxed();
}
/**
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index c065cb5..e76cbe44 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -971,7 +971,7 @@
void NativeInputManager::notifyDeviceInteraction(int32_t deviceId, nsecs_t timestamp,
const std::set<gui::Uid>& uids) {
static const bool ENABLE_INPUT_DEVICE_USAGE_METRICS =
- sysprop::InputProperties::enable_input_device_usage_metrics().value_or(true);
+ sysprop::InputProperties::enable_input_device_usage_metrics().value_or(false);
if (!ENABLE_INPUT_DEVICE_USAGE_METRICS) return;
mInputManager->getMetricsCollector().notifyDeviceInteraction(deviceId, timestamp, uids);
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java
index a6ada4d..869497c 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java
@@ -20,6 +20,7 @@
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE;
import static com.android.internal.inputmethod.SoftInputShowHideReason.HIDE_SOFT_INPUT;
+import static com.android.internal.inputmethod.SoftInputShowHideReason.HIDE_SWITCH_USER;
import static com.android.internal.inputmethod.SoftInputShowHideReason.SHOW_SOFT_INPUT;
import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_HIDE_IME;
import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_HIDE_IME_EXPLICIT;
@@ -43,6 +44,7 @@
import androidx.test.ext.junit.runners.AndroidJUnit4;
+import com.android.dx.mockito.inline.extended.ExtendedMockito;
import com.android.internal.inputmethod.InputBindResult;
import com.android.internal.inputmethod.StartInputFlags;
import com.android.internal.inputmethod.StartInputReason;
@@ -165,6 +167,29 @@
verify(mMockImeTargetVisibilityPolicy).removeImeScreenshot(eq(Display.DEFAULT_DISPLAY));
}
+ @Test
+ public void testApplyImeVisibility_hideImeWhenUnbinding() {
+ mInputMethodManagerService.setAttachedClientForTesting(null);
+ startInputOrWindowGainedFocus(mWindowToken, SOFT_INPUT_STATE_ALWAYS_VISIBLE);
+ ExtendedMockito.spyOn(mVisibilityApplier);
+
+ synchronized (ImfLock.class) {
+ // Simulate the system hides the IME when switching IME services in different users.
+ // (e.g. unbinding the IME from the current user to the profile user)
+ final int displayIdToShowIme = mInputMethodManagerService.getDisplayIdToShowImeLocked();
+ mInputMethodManagerService.hideCurrentInputLocked(mWindowToken, null, 0, null,
+ HIDE_SWITCH_USER);
+ mInputMethodManagerService.onUnbindCurrentMethodByReset();
+
+ // Expects applyImeVisibility() -> hideIme() will be called to notify WM for syncing
+ // the IME hidden state.
+ verify(mVisibilityApplier).applyImeVisibility(eq(mWindowToken), any(),
+ eq(STATE_HIDE_IME));
+ verify(mInputMethodManagerService.mWindowManagerInternal).hideIme(
+ eq(mWindowToken), eq(displayIdToShowIme), eq(null));
+ }
+ }
+
private InputBindResult startInputOrWindowGainedFocus(IBinder windowToken, int softInputMode) {
return mInputMethodManagerService.startInputOrWindowGainedFocus(
StartInputReason.WINDOW_FOCUS_GAIN /* startInputReason */,
diff --git a/services/tests/displayservicetests/Android.bp b/services/tests/displayservicetests/Android.bp
index b242ec2..f1ff338 100644
--- a/services/tests/displayservicetests/Android.bp
+++ b/services/tests/displayservicetests/Android.bp
@@ -22,11 +22,20 @@
"src/**/*.java",
],
+ libs: [
+ "android.test.mock",
+ ],
+
static_libs: [
- "services.core",
- "androidx.test.runner",
- "androidx.test.rules",
+ "androidx.test.ext.junit",
+ "display-core-libs",
+ "frameworks-base-testutils",
+ "junit",
+ "junit-params",
+ "platform-compat-test-rules",
"platform-test-annotations",
+ "services.core",
+ "servicestests-utils",
],
defaults: [
@@ -47,3 +56,10 @@
enabled: false,
},
}
+
+java_library {
+ name: "display-core-libs",
+ srcs: [
+ "src/com/android/server/display/TestUtils.java",
+ ],
+}
diff --git a/services/tests/displayservicetests/AndroidManifest.xml b/services/tests/displayservicetests/AndroidManifest.xml
index c2e4174..d2bd10d 100644
--- a/services/tests/displayservicetests/AndroidManifest.xml
+++ b/services/tests/displayservicetests/AndroidManifest.xml
@@ -21,6 +21,16 @@
Insert permissions here. eg:
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
-->
+ <uses-permission android:name="android.permission.CONTROL_DISPLAY_BRIGHTNESS" />
+ <uses-permission android:name="android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS" />
+ <uses-permission android:name="android.permission.DEVICE_POWER" />
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+ <uses-permission android:name="android.permission.LOG_COMPAT_CHANGE" />
+ <uses-permission android:name="android.permission.MANAGE_ACTIVITY_TASKS" />
+ <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
+ <uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG" />
+ <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
+ <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
<application android:debuggable="true"
android:testOnly="true">
diff --git a/services/tests/servicestests/src/com/android/server/display/AmbientBrightnessStatsTrackerTest.java b/services/tests/displayservicetests/src/com/android/server/display/AmbientBrightnessStatsTrackerTest.java
similarity index 99%
rename from services/tests/servicestests/src/com/android/server/display/AmbientBrightnessStatsTrackerTest.java
rename to services/tests/displayservicetests/src/com/android/server/display/AmbientBrightnessStatsTrackerTest.java
index 2c4fe53..7333bc7 100644
--- a/services/tests/servicestests/src/com/android/server/display/AmbientBrightnessStatsTrackerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/AmbientBrightnessStatsTrackerTest.java
@@ -11,7 +11,7 @@
* 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
+ * limitations under the License.
*/
package com.android.server.display;
diff --git a/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
rename to services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
diff --git a/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/BrightnessMappingStrategyTest.java
similarity index 98%
rename from services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java
rename to services/tests/displayservicetests/src/com/android/server/display/BrightnessMappingStrategyTest.java
index 5f81869..ee7826f 100644
--- a/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/BrightnessMappingStrategyTest.java
@@ -11,7 +11,7 @@
* 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
+ * limitations under the License.
*/
package com.android.server.display;
@@ -206,11 +206,11 @@
BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
strategy.setBrightnessConfiguration(null);
- final int N = DISPLAY_LEVELS_BACKLIGHT.length;
+ final int n = DISPLAY_LEVELS_BACKLIGHT.length;
final float expectedBrightness =
- (float) DISPLAY_LEVELS_BACKLIGHT[N - 1] / PowerManager.BRIGHTNESS_ON;
+ (float) DISPLAY_LEVELS_BACKLIGHT[n - 1] / PowerManager.BRIGHTNESS_ON;
assertEquals(expectedBrightness,
- strategy.getBrightness(LUX_LEVELS[N - 1]), 0.0001f /*tolerance*/);
+ strategy.getBrightness(LUX_LEVELS[n - 1]), 0.0001f /*tolerance*/);
}
@Test
@@ -270,10 +270,10 @@
// Check that null returns us to the default configuration.
strategy.setBrightnessConfiguration(null);
- final int N = DISPLAY_LEVELS_NITS.length;
- final float expectedBrightness = DISPLAY_LEVELS_NITS[N - 1] / DISPLAY_RANGE_NITS[1];
+ final int n = DISPLAY_LEVELS_NITS.length;
+ final float expectedBrightness = DISPLAY_LEVELS_NITS[n - 1] / DISPLAY_RANGE_NITS[1];
assertEquals(expectedBrightness,
- strategy.getBrightness(LUX_LEVELS[N - 1]), 0.0001f /*tolerance*/);
+ strategy.getBrightness(LUX_LEVELS[n - 1]), 0.0001f /*tolerance*/);
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/display/BrightnessThrottlerTest.java b/services/tests/displayservicetests/src/com/android/server/display/BrightnessThrottlerTest.java
similarity index 97%
rename from services/tests/servicestests/src/com/android/server/display/BrightnessThrottlerTest.java
rename to services/tests/displayservicetests/src/com/android/server/display/BrightnessThrottlerTest.java
index 46956d7..8faaf59 100644
--- a/services/tests/servicestests/src/com/android/server/display/BrightnessThrottlerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/BrightnessThrottlerTest.java
@@ -159,7 +159,7 @@
@Test
public void testThermalThrottlingSingleLevel() throws Exception {
final ThrottlingLevel level = new ThrottlingLevel(PowerManager.THERMAL_STATUS_CRITICAL,
- 0.25f);
+ 0.25f);
List<ThrottlingLevel> levels = new ArrayList<>();
levels.add(level);
@@ -184,7 +184,7 @@
assertEquals(level.brightness, throttler.getBrightnessCap(), 0f);
assertTrue(throttler.isThrottled());
assertEquals(BrightnessInfo.BRIGHTNESS_MAX_REASON_THERMAL,
- throttler.getBrightnessMaxReason());
+ throttler.getBrightnessMaxReason());
// Set status more than high enough to trigger throttling
listener.notifyThrottling(getSkinTemp(level.thermalStatus + 1));
@@ -192,7 +192,7 @@
assertEquals(level.brightness, throttler.getBrightnessCap(), 0f);
assertTrue(throttler.isThrottled());
assertEquals(BrightnessInfo.BRIGHTNESS_MAX_REASON_THERMAL,
- throttler.getBrightnessMaxReason());
+ throttler.getBrightnessMaxReason());
// Return to the lower throttling level
listener.notifyThrottling(getSkinTemp(level.thermalStatus));
@@ -200,7 +200,7 @@
assertEquals(level.brightness, throttler.getBrightnessCap(), 0f);
assertTrue(throttler.isThrottled());
assertEquals(BrightnessInfo.BRIGHTNESS_MAX_REASON_THERMAL,
- throttler.getBrightnessMaxReason());
+ throttler.getBrightnessMaxReason());
// Cool down
listener.notifyThrottling(getSkinTemp(level.thermalStatus - 1));
@@ -208,15 +208,15 @@
assertEquals(PowerManager.BRIGHTNESS_MAX, throttler.getBrightnessCap(), 0f);
assertFalse(throttler.isThrottled());
assertEquals(BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE,
- throttler.getBrightnessMaxReason());
+ throttler.getBrightnessMaxReason());
}
@Test
public void testThermalThrottlingMultiLevel() throws Exception {
final ThrottlingLevel levelLo = new ThrottlingLevel(PowerManager.THERMAL_STATUS_MODERATE,
- 0.62f);
+ 0.62f);
final ThrottlingLevel levelHi = new ThrottlingLevel(PowerManager.THERMAL_STATUS_CRITICAL,
- 0.25f);
+ 0.25f);
List<ThrottlingLevel> levels = new ArrayList<>();
levels.add(levelLo);
@@ -242,7 +242,7 @@
assertEquals(levelLo.brightness, throttler.getBrightnessCap(), 0f);
assertTrue(throttler.isThrottled());
assertEquals(BrightnessInfo.BRIGHTNESS_MAX_REASON_THERMAL,
- throttler.getBrightnessMaxReason());
+ throttler.getBrightnessMaxReason());
// Set status to an intermediate throttling level
listener.notifyThrottling(getSkinTemp(levelLo.thermalStatus + 1));
@@ -250,7 +250,7 @@
assertEquals(levelLo.brightness, throttler.getBrightnessCap(), 0f);
assertTrue(throttler.isThrottled());
assertEquals(BrightnessInfo.BRIGHTNESS_MAX_REASON_THERMAL,
- throttler.getBrightnessMaxReason());
+ throttler.getBrightnessMaxReason());
// Set status to the highest configured throttling level
listener.notifyThrottling(getSkinTemp(levelHi.thermalStatus));
@@ -258,7 +258,7 @@
assertEquals(levelHi.brightness, throttler.getBrightnessCap(), 0f);
assertTrue(throttler.isThrottled());
assertEquals(BrightnessInfo.BRIGHTNESS_MAX_REASON_THERMAL,
- throttler.getBrightnessMaxReason());
+ throttler.getBrightnessMaxReason());
// Set status to exceed the highest configured throttling level
listener.notifyThrottling(getSkinTemp(levelHi.thermalStatus + 1));
@@ -266,7 +266,7 @@
assertEquals(levelHi.brightness, throttler.getBrightnessCap(), 0f);
assertTrue(throttler.isThrottled());
assertEquals(BrightnessInfo.BRIGHTNESS_MAX_REASON_THERMAL,
- throttler.getBrightnessMaxReason());
+ throttler.getBrightnessMaxReason());
// Return to an intermediate throttling level
listener.notifyThrottling(getSkinTemp(levelLo.thermalStatus + 1));
@@ -274,7 +274,7 @@
assertEquals(levelLo.brightness, throttler.getBrightnessCap(), 0f);
assertTrue(throttler.isThrottled());
assertEquals(BrightnessInfo.BRIGHTNESS_MAX_REASON_THERMAL,
- throttler.getBrightnessMaxReason());
+ throttler.getBrightnessMaxReason());
// Return to the lowest configured throttling level
listener.notifyThrottling(getSkinTemp(levelLo.thermalStatus));
@@ -282,7 +282,7 @@
assertEquals(levelLo.brightness, throttler.getBrightnessCap(), 0f);
assertTrue(throttler.isThrottled());
assertEquals(BrightnessInfo.BRIGHTNESS_MAX_REASON_THERMAL,
- throttler.getBrightnessMaxReason());
+ throttler.getBrightnessMaxReason());
// Cool down
listener.notifyThrottling(getSkinTemp(levelLo.thermalStatus - 1));
diff --git a/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java b/services/tests/displayservicetests/src/com/android/server/display/BrightnessTrackerTest.java
similarity index 98%
rename from services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java
rename to services/tests/displayservicetests/src/com/android/server/display/BrightnessTrackerTest.java
index 021f2d1..44c7dec 100644
--- a/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/BrightnessTrackerTest.java
@@ -11,7 +11,7 @@
* 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
+ * limitations under the License.
*/
package com.android.server.display;
@@ -395,8 +395,8 @@
final long currentTime = mInjector.currentTimeMillis();
notifyBrightnessChanged(mTracker, brightness, displayId, new float[] {1000.0f},
new long[] {TimeUnit.NANOSECONDS.toMillis(mInjector.elapsedRealtimeNanos())});
- List<BrightnessChangeEvent> eventsNoPackage
- = mTracker.getEvents(0, false).getList();
+ List<BrightnessChangeEvent> eventsNoPackage =
+ mTracker.getEvents(0, false).getList();
List<BrightnessChangeEvent> events = mTracker.getEvents(0, true).getList();
mTracker.stop();
@@ -1037,9 +1037,9 @@
}
void setBrightnessMode(boolean isBrightnessModeAutomatic) {
- mIsBrightnessModeAutomatic = isBrightnessModeAutomatic;
- mContentObserver.dispatchChange(false, null);
- waitForHandler();
+ mIsBrightnessModeAutomatic = isBrightnessModeAutomatic;
+ mContentObserver.dispatchChange(false, null);
+ waitForHandler();
}
void sendScreenChange(boolean screenOn) {
@@ -1184,8 +1184,8 @@
@Override
public int getNightDisplayColorTemperature(Context context) {
- return mSecureIntSettings.getOrDefault(Settings.Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE,
- mDefaultNightModeColorTemperature);
+ return mSecureIntSettings.getOrDefault(Settings.Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE,
+ mDefaultNightModeColorTemperature);
}
@Override
diff --git a/services/tests/servicestests/src/com/android/server/display/ColorFadeTest.java b/services/tests/displayservicetests/src/com/android/server/display/ColorFadeTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/display/ColorFadeTest.java
rename to services/tests/displayservicetests/src/com/android/server/display/ColorFadeTest.java
diff --git a/services/tests/servicestests/src/com/android/server/display/DeviceStateToLayoutMapTest.java b/services/tests/displayservicetests/src/com/android/server/display/DeviceStateToLayoutMapTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/display/DeviceStateToLayoutMapTest.java
rename to services/tests/displayservicetests/src/com/android/server/display/DeviceStateToLayoutMapTest.java
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java
rename to services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceConfigTest.java
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
similarity index 99%
rename from services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
rename to services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
index 5db9d1f..d16c9c5 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -142,7 +142,7 @@
private static final float FLOAT_TOLERANCE = 0.01f;
private static final String VIRTUAL_DISPLAY_NAME = "Test Virtual Display";
- private static final String PACKAGE_NAME = "com.android.frameworks.servicestests";
+ private static final String PACKAGE_NAME = "com.android.frameworks.displayservicetests";
private static final long STANDARD_DISPLAY_EVENTS = DisplayManager.EVENT_FLAG_DISPLAY_ADDED
| DisplayManager.EVENT_FLAG_DISPLAY_CHANGED
| DisplayManager.EVENT_FLAG_DISPLAY_REMOVED;
@@ -238,7 +238,7 @@
boolean getHdrOutputConversionSupport() {
return true;
}
- }
+ }
private final DisplayManagerService.Injector mBasicInjector = new BasicInjector();
diff --git a/services/tests/servicestests/src/com/android/server/display/HbmEventTest.java b/services/tests/displayservicetests/src/com/android/server/display/HbmEventTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/display/HbmEventTest.java
rename to services/tests/displayservicetests/src/com/android/server/display/HbmEventTest.java
diff --git a/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/HighBrightnessModeControllerTest.java
similarity index 89%
rename from services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java
rename to services/tests/displayservicetests/src/com/android/server/display/HighBrightnessModeControllerTest.java
index e2a66f0..76e6ec7 100644
--- a/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/HighBrightnessModeControllerTest.java
@@ -483,8 +483,10 @@
// Verify Stats HBM_ON_HDR
verify(mInjectorMock).reportHbmStateChange(eq(displayStatsId),
- eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_ON_HDR),
- eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__REASON__HBM_TRANSITION_REASON_UNKNOWN));
+ eq(FrameworkStatsLog
+ .DISPLAY_HBM_STATE_CHANGED__STATE__HBM_ON_HDR),
+ eq(FrameworkStatsLog
+ .DISPLAY_HBM_STATE_CHANGED__REASON__HBM_TRANSITION_REASON_UNKNOWN));
hbmc.getHdrListener().onHdrInfoChanged(null /*displayToken*/, 0 /*numberOfHdrLayers*/,
0, 0, 0 /*flags*/, 1.0f /*maxDesiredHdrSdrRatio*/);
@@ -492,8 +494,10 @@
// Verify Stats HBM_OFF
verify(mInjectorMock).reportHbmStateChange(eq(displayStatsId),
- eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_OFF),
- eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__REASON__HBM_TRANSITION_REASON_UNKNOWN));
+ eq(FrameworkStatsLog
+ .DISPLAY_HBM_STATE_CHANGED__STATE__HBM_OFF),
+ eq(FrameworkStatsLog
+ .DISPLAY_HBM_STATE_CHANGED__REASON__HBM_TRANSITION_REASON_UNKNOWN));
hbmc.setAutoBrightnessEnabled(AUTO_BRIGHTNESS_ENABLED);
hbmc.onAmbientLuxChange(MINIMUM_LUX + 1);
@@ -501,16 +505,20 @@
// Verify Stats HBM_ON_SUNLIGHT
verify(mInjectorMock).reportHbmStateChange(eq(displayStatsId),
- eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_ON_SUNLIGHT),
- eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__REASON__HBM_TRANSITION_REASON_UNKNOWN));
+ eq(FrameworkStatsLog
+ .DISPLAY_HBM_STATE_CHANGED__STATE__HBM_ON_SUNLIGHT),
+ eq(FrameworkStatsLog
+ .DISPLAY_HBM_STATE_CHANGED__REASON__HBM_TRANSITION_REASON_UNKNOWN));
hbmc.onAmbientLuxChange(1);
advanceTime(TIME_ALLOWED_IN_WINDOW_MILLIS / 2 + 1);
// Verify Stats HBM_OFF
verify(mInjectorMock).reportHbmStateChange(eq(displayStatsId),
- eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_OFF),
- eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__REASON__HBM_SV_OFF_LUX_DROP));
+ eq(FrameworkStatsLog
+ .DISPLAY_HBM_STATE_CHANGED__STATE__HBM_OFF),
+ eq(FrameworkStatsLog
+ .DISPLAY_HBM_STATE_CHANGED__REASON__HBM_SV_OFF_LUX_DROP));
}
@Test
@@ -527,8 +535,8 @@
// Verify Stats HBM_ON_HDR not report
verify(mInjectorMock, never()).reportHbmStateChange(eq(displayStatsId),
- eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_ON_HDR),
- anyInt());
+ eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_ON_HDR),
+ anyInt());
}
@Test
@@ -545,8 +553,8 @@
// Verify Stats HBM_ON_SUNLIGHT not report
verify(mInjectorMock, never()).reportHbmStateChange(eq(displayStatsId),
- eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_ON_SUNLIGHT),
- anyInt());
+ eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_ON_SUNLIGHT),
+ anyInt());
}
// Test reporting of thermal throttling when triggered externally through
@@ -565,8 +573,10 @@
BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE);
advanceTime(1);
verify(mInjectorMock).reportHbmStateChange(eq(displayStatsId),
- eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_ON_SUNLIGHT),
- eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__REASON__HBM_TRANSITION_REASON_UNKNOWN));
+ eq(FrameworkStatsLog
+ .DISPLAY_HBM_STATE_CHANGED__STATE__HBM_ON_SUNLIGHT),
+ eq(FrameworkStatsLog
+ .DISPLAY_HBM_STATE_CHANGED__REASON__HBM_TRANSITION_REASON_UNKNOWN));
// Brightness is thermally throttled, HBM brightness denied (NBM brightness granted)
hbmc.onBrightnessChanged(nbmBrightness, hbmBrightness,
@@ -578,8 +588,8 @@
// the HBM transition point.
assertEquals(HIGH_BRIGHTNESS_MODE_SUNLIGHT, hbmc.getHighBrightnessMode());
verify(mInjectorMock).reportHbmStateChange(eq(displayStatsId),
- eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_OFF),
- eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__REASON__HBM_SV_OFF_THERMAL_LIMIT));
+ eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_OFF),
+ eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__REASON__HBM_SV_OFF_THERMAL_LIMIT));
}
@Test
@@ -592,15 +602,17 @@
hbmcOnBrightnessChanged(hbmc, TRANSITION_POINT + 0.01f);
advanceTime(0);
verify(mInjectorMock).reportHbmStateChange(eq(displayStatsId),
- eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_ON_SUNLIGHT),
- eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__REASON__HBM_TRANSITION_REASON_UNKNOWN));
+ eq(FrameworkStatsLog
+ .DISPLAY_HBM_STATE_CHANGED__STATE__HBM_ON_SUNLIGHT),
+ eq(FrameworkStatsLog
+ .DISPLAY_HBM_STATE_CHANGED__REASON__HBM_TRANSITION_REASON_UNKNOWN));
// Use up all the time in the window.
advanceTime(TIME_WINDOW_MILLIS + 1);
verify(mInjectorMock).reportHbmStateChange(eq(displayStatsId),
- eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_OFF),
- eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__REASON__HBM_SV_OFF_TIME_LIMIT));
+ eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_OFF),
+ eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__REASON__HBM_SV_OFF_TIME_LIMIT));
}
@Test
@@ -613,13 +625,17 @@
hbmcOnBrightnessChanged(hbmc, TRANSITION_POINT + 0.01f);
advanceTime(0);
verify(mInjectorMock).reportHbmStateChange(eq(displayStatsId),
- eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_ON_SUNLIGHT),
- eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__REASON__HBM_TRANSITION_REASON_UNKNOWN));
+ eq(FrameworkStatsLog
+ .DISPLAY_HBM_STATE_CHANGED__STATE__HBM_ON_SUNLIGHT),
+ eq(FrameworkStatsLog
+ .DISPLAY_HBM_STATE_CHANGED__REASON__HBM_TRANSITION_REASON_UNKNOWN));
hbmc.setAutoBrightnessEnabled(AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE);
verify(mInjectorMock).reportHbmStateChange(eq(displayStatsId),
- eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_OFF),
- eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__REASON__HBM_SV_OFF_DISPLAY_OFF));
+ eq(FrameworkStatsLog
+ .DISPLAY_HBM_STATE_CHANGED__STATE__HBM_OFF),
+ eq(FrameworkStatsLog
+ .DISPLAY_HBM_STATE_CHANGED__REASON__HBM_SV_OFF_DISPLAY_OFF));
}
@Test
@@ -632,16 +648,18 @@
hbmcOnBrightnessChanged(hbmc, TRANSITION_POINT + 0.01f);
advanceTime(0);
verify(mInjectorMock).reportHbmStateChange(eq(displayStatsId),
- eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_ON_SUNLIGHT),
- eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__REASON__HBM_TRANSITION_REASON_UNKNOWN));
+ eq(FrameworkStatsLog
+ .DISPLAY_HBM_STATE_CHANGED__STATE__HBM_ON_SUNLIGHT),
+ eq(FrameworkStatsLog
+ .DISPLAY_HBM_STATE_CHANGED__REASON__HBM_TRANSITION_REASON_UNKNOWN));
hbmc.getHdrListener().onHdrInfoChanged(null /*displayToken*/, 1 /*numberOfHdrLayers*/,
DISPLAY_WIDTH, DISPLAY_HEIGHT, 0 /*flags*/, 1.0f /*maxDesiredHdrSdrRatio*/);
advanceTime(0);
verify(mInjectorMock).reportHbmStateChange(eq(displayStatsId),
- eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_ON_HDR),
- eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__REASON__HBM_SV_OFF_HDR_PLAYING));
+ eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_ON_HDR),
+ eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__REASON__HBM_SV_OFF_HDR_PLAYING));
}
@Test
@@ -657,15 +675,17 @@
assertEquals(HIGH_BRIGHTNESS_MODE_SUNLIGHT, hbmc.getHighBrightnessMode());
// verify HBM_ON_SUNLIGHT
verify(mInjectorMock).reportHbmStateChange(eq(displayStatsId),
- eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_ON_SUNLIGHT),
- eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__REASON__HBM_TRANSITION_REASON_UNKNOWN));
+ eq(FrameworkStatsLog
+ .DISPLAY_HBM_STATE_CHANGED__STATE__HBM_ON_SUNLIGHT),
+ eq(FrameworkStatsLog
+ .DISPLAY_HBM_STATE_CHANGED__REASON__HBM_TRANSITION_REASON_UNKNOWN));
hbmcOnBrightnessChanged(hbmc, DEFAULT_MIN);
// verify HBM_SV_OFF due to LOW_REQUESTED_BRIGHTNESS
verify(mInjectorMock).reportHbmStateChange(eq(displayStatsId),
- eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_OFF),
- eq(FrameworkStatsLog
- .DISPLAY_HBM_STATE_CHANGED__REASON__HBM_SV_OFF_LOW_REQUESTED_BRIGHTNESS));
+ eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_OFF),
+ eq(FrameworkStatsLog
+ .DISPLAY_HBM_STATE_CHANGED__REASON__HBM_SV_OFF_LOW_REQUESTED_BRIGHTNESS));
}
private void assertState(HighBrightnessModeController hbmc,
diff --git a/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeMetadataTest.java b/services/tests/displayservicetests/src/com/android/server/display/HighBrightnessModeMetadataTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/display/HighBrightnessModeMetadataTest.java
rename to services/tests/displayservicetests/src/com/android/server/display/HighBrightnessModeMetadataTest.java
diff --git a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java
rename to services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java
diff --git a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayTest.java b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayTest.java
similarity index 98%
rename from services/tests/servicestests/src/com/android/server/display/LogicalDisplayTest.java
rename to services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayTest.java
index 30ff8ba..2065479 100644
--- a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayTest.java
@@ -40,6 +40,7 @@
import com.android.server.display.layout.Layout;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import java.io.InputStream;
@@ -121,7 +122,9 @@
assertEquals(expectedPosition, mLogicalDisplay.getDisplayPosition());
}
+ // TODO: b/288880734 - fix test after display tests migration
@Test
+ @Ignore
public void testDisplayInputFlags() {
SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);
mLogicalDisplay.configureDisplayLocked(t, mDisplayDevice, false);
diff --git a/services/tests/servicestests/src/com/android/server/display/NormalBrightnessModeControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/NormalBrightnessModeControllerTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/display/NormalBrightnessModeControllerTest.java
rename to services/tests/displayservicetests/src/com/android/server/display/NormalBrightnessModeControllerTest.java
diff --git a/services/tests/servicestests/src/com/android/server/display/PersistentDataStoreTest.java b/services/tests/displayservicetests/src/com/android/server/display/PersistentDataStoreTest.java
similarity index 99%
rename from services/tests/servicestests/src/com/android/server/display/PersistentDataStoreTest.java
rename to services/tests/displayservicetests/src/com/android/server/display/PersistentDataStoreTest.java
index 642f54c..9f91916 100644
--- a/services/tests/servicestests/src/com/android/server/display/PersistentDataStoreTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/PersistentDataStoreTest.java
@@ -11,7 +11,7 @@
* 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
+ * limitations under the License.
*/
package com.android.server.display;
diff --git a/services/tests/servicestests/src/com/android/server/display/ScreenOffBrightnessSensorControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/ScreenOffBrightnessSensorControllerTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/display/ScreenOffBrightnessSensorControllerTest.java
rename to services/tests/displayservicetests/src/com/android/server/display/ScreenOffBrightnessSensorControllerTest.java
diff --git a/services/tests/servicestests/src/com/android/server/display/utils/SensorUtilsTest.java b/services/tests/displayservicetests/src/com/android/server/display/SensorUtilsTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/display/utils/SensorUtilsTest.java
rename to services/tests/displayservicetests/src/com/android/server/display/SensorUtilsTest.java
diff --git a/services/tests/displayservicetests/src/com/android/server/display/TestUtils.java b/services/tests/displayservicetests/src/com/android/server/display/TestUtils.java
new file mode 100644
index 0000000..8b45145
--- /dev/null
+++ b/services/tests/displayservicetests/src/com/android/server/display/TestUtils.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2019 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.display;
+
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.input.InputSensorInfo;
+import android.os.Parcel;
+import android.os.SystemClock;
+import android.view.DisplayAddress;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+public final class TestUtils {
+
+ public static SensorEvent createSensorEvent(Sensor sensor, int value) throws Exception {
+ final Constructor<SensorEvent> constructor =
+ SensorEvent.class.getDeclaredConstructor(int.class);
+ constructor.setAccessible(true);
+ final SensorEvent event = constructor.newInstance(1);
+ event.sensor = sensor;
+ event.values[0] = value;
+ event.timestamp = SystemClock.elapsedRealtimeNanos();
+ return event;
+ }
+
+
+ public static void setSensorType(Sensor sensor, int type, String strType) throws Exception {
+ Method setter = Sensor.class.getDeclaredMethod("setType", Integer.TYPE);
+ setter.setAccessible(true);
+ setter.invoke(sensor, type);
+ if (strType != null) {
+ Field f = sensor.getClass().getDeclaredField("mStringType");
+ f.setAccessible(true);
+ f.set(sensor, strType);
+ }
+ }
+
+ public static void setMaximumRange(Sensor sensor, float maximumRange) throws Exception {
+ Method setter = Sensor.class.getDeclaredMethod("setRange", Float.TYPE, Float.TYPE);
+ setter.setAccessible(true);
+ setter.invoke(sensor, maximumRange, 1);
+ }
+
+ public static Sensor createSensor(int type, String strType) throws Exception {
+ Constructor<Sensor> constr = Sensor.class.getDeclaredConstructor();
+ constr.setAccessible(true);
+ Sensor sensor = constr.newInstance();
+ setSensorType(sensor, type, strType);
+ return sensor;
+ }
+
+ public static Sensor createSensor(int type, String strType, float maximumRange)
+ throws Exception {
+ Constructor<Sensor> constr = Sensor.class.getDeclaredConstructor();
+ constr.setAccessible(true);
+ Sensor sensor = constr.newInstance();
+ setSensorType(sensor, type, strType);
+ setMaximumRange(sensor, maximumRange);
+ return sensor;
+ }
+
+ public static Sensor createSensor(String type, String name) {
+ return new Sensor(new InputSensorInfo(
+ name, "vendor", 0, 0, 0, 1f, 1f, 1, 1, 1, 1,
+ type, "", 0, 0, 0));
+ }
+
+ /**
+ * Create a custom {@link DisplayAddress} to ensure we're not relying on any specific
+ * display-address implementation in our code. Intentionally uses default object (reference)
+ * equality rules.
+ */
+ public static class TestDisplayAddress extends DisplayAddress {
+ @Override
+ public void writeToParcel(Parcel out, int flags) { }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/display/brightness/BrightnessEventTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/BrightnessEventTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/display/brightness/BrightnessEventTest.java
rename to services/tests/displayservicetests/src/com/android/server/display/brightness/BrightnessEventTest.java
diff --git a/services/tests/servicestests/src/com/android/server/display/brightness/BrightnessReasonTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/BrightnessReasonTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/display/brightness/BrightnessReasonTest.java
rename to services/tests/displayservicetests/src/com/android/server/display/brightness/BrightnessReasonTest.java
diff --git a/services/tests/servicestests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java
rename to services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java
diff --git a/services/tests/servicestests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java
rename to services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java
diff --git a/services/tests/servicestests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java
rename to services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java
diff --git a/services/tests/servicestests/src/com/android/server/display/brightness/strategy/BoostBrightnessStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/BoostBrightnessStrategyTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/display/brightness/strategy/BoostBrightnessStrategyTest.java
rename to services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/BoostBrightnessStrategyTest.java
diff --git a/services/tests/servicestests/src/com/android/server/display/brightness/strategy/DozeBrightnessStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/DozeBrightnessStrategyTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/display/brightness/strategy/DozeBrightnessStrategyTest.java
rename to services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/DozeBrightnessStrategyTest.java
diff --git a/services/tests/servicestests/src/com/android/server/display/brightness/strategy/FollowerBrightnessStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/FollowerBrightnessStrategyTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/display/brightness/strategy/FollowerBrightnessStrategyTest.java
rename to services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/FollowerBrightnessStrategyTest.java
diff --git a/services/tests/servicestests/src/com/android/server/display/brightness/strategy/OverrideBrightnessStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/OverrideBrightnessStrategyTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/display/brightness/strategy/OverrideBrightnessStrategyTest.java
rename to services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/OverrideBrightnessStrategyTest.java
diff --git a/services/tests/servicestests/src/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategyTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategyTest.java
rename to services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategyTest.java
diff --git a/services/tests/servicestests/src/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategyTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategyTest.java
rename to services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategyTest.java
diff --git a/services/tests/servicestests/src/com/android/server/display/color/AppSaturationControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/color/AppSaturationControllerTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/display/color/AppSaturationControllerTest.java
rename to services/tests/displayservicetests/src/com/android/server/display/color/AppSaturationControllerTest.java
diff --git a/services/tests/servicestests/src/com/android/server/display/color/CctEvaluatorTest.java b/services/tests/displayservicetests/src/com/android/server/display/color/CctEvaluatorTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/display/color/CctEvaluatorTest.java
rename to services/tests/displayservicetests/src/com/android/server/display/color/CctEvaluatorTest.java
diff --git a/services/tests/servicestests/src/com/android/server/display/color/ColorDisplayServiceTest.java b/services/tests/displayservicetests/src/com/android/server/display/color/ColorDisplayServiceTest.java
similarity index 98%
rename from services/tests/servicestests/src/com/android/server/display/color/ColorDisplayServiceTest.java
rename to services/tests/displayservicetests/src/com/android/server/display/color/ColorDisplayServiceTest.java
index 618ab1b..c7c09b5 100644
--- a/services/tests/servicestests/src/com/android/server/display/color/ColorDisplayServiceTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/color/ColorDisplayServiceTest.java
@@ -1093,15 +1093,15 @@
@Test
public void compositionColorSpaces_invalidResources() {
when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorModes))
- .thenReturn(new int[] {
- ColorDisplayManager.COLOR_MODE_NATURAL,
- // Missing second color mode
- });
+ .thenReturn(new int[] {
+ ColorDisplayManager.COLOR_MODE_NATURAL,
+ // Missing second color mode
+ });
when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorSpaces))
- .thenReturn(new int[] {
- Display.COLOR_MODE_SRGB,
- Display.COLOR_MODE_DISPLAY_P3
- });
+ .thenReturn(new int[] {
+ Display.COLOR_MODE_SRGB,
+ Display.COLOR_MODE_DISPLAY_P3
+ });
setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
startService();
verify(mDisplayTransformManager).setColorMode(
@@ -1111,13 +1111,13 @@
@Test
public void compositionColorSpaces_validResources_validColorMode() {
when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorModes))
- .thenReturn(new int[] {
- ColorDisplayManager.COLOR_MODE_NATURAL
- });
+ .thenReturn(new int[] {
+ ColorDisplayManager.COLOR_MODE_NATURAL
+ });
when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorSpaces))
- .thenReturn(new int[] {
- Display.COLOR_MODE_SRGB,
- });
+ .thenReturn(new int[] {
+ Display.COLOR_MODE_SRGB,
+ });
setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
startService();
verify(mDisplayTransformManager).setColorMode(
@@ -1127,13 +1127,13 @@
@Test
public void compositionColorSpaces_validResources_invalidColorMode() {
when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorModes))
- .thenReturn(new int[] {
- ColorDisplayManager.COLOR_MODE_NATURAL
- });
+ .thenReturn(new int[] {
+ ColorDisplayManager.COLOR_MODE_NATURAL
+ });
when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorSpaces))
- .thenReturn(new int[] {
- Display.COLOR_MODE_SRGB,
- });
+ .thenReturn(new int[] {
+ Display.COLOR_MODE_SRGB,
+ });
setColorMode(ColorDisplayManager.COLOR_MODE_BOOSTED);
startService();
verify(mDisplayTransformManager).setColorMode(
@@ -1143,7 +1143,7 @@
@Test
public void getColorMode_noAvailableModes_returnsNotSet() {
when(mResourcesSpy.getIntArray(R.array.config_availableColorModes))
- .thenReturn(new int[] {});
+ .thenReturn(new int[] {});
startService();
verify(mDisplayTransformManager, never()).setColorMode(anyInt(), any(), anyInt());
assertThat(mBinderService.getColorMode()).isEqualTo(-1);
diff --git a/services/tests/servicestests/src/com/android/server/display/color/DisplayWhiteBalanceTintControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/color/DisplayWhiteBalanceTintControllerTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/display/color/DisplayWhiteBalanceTintControllerTest.java
rename to services/tests/displayservicetests/src/com/android/server/display/color/DisplayWhiteBalanceTintControllerTest.java
diff --git a/services/tests/servicestests/src/com/android/server/display/color/GlobalSaturationTintControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/color/GlobalSaturationTintControllerTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/display/color/GlobalSaturationTintControllerTest.java
rename to services/tests/displayservicetests/src/com/android/server/display/color/GlobalSaturationTintControllerTest.java
diff --git a/services/tests/servicestests/src/com/android/server/display/color/ReduceBrightColorsTintControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/color/ReduceBrightColorsTintControllerTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/display/color/ReduceBrightColorsTintControllerTest.java
rename to services/tests/displayservicetests/src/com/android/server/display/color/ReduceBrightColorsTintControllerTest.java
diff --git a/services/tests/servicestests/src/com/android/server/display/mode/DisplayModeDirectorTest.java b/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/display/mode/DisplayModeDirectorTest.java
rename to services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java
diff --git a/services/tests/servicestests/src/com/android/server/display/mode/SkinThermalStatusObserverTest.java b/services/tests/displayservicetests/src/com/android/server/display/mode/SkinThermalStatusObserverTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/display/mode/SkinThermalStatusObserverTest.java
rename to services/tests/displayservicetests/src/com/android/server/display/mode/SkinThermalStatusObserverTest.java
diff --git a/services/tests/servicestests/src/com/android/server/display/mode/VotesStorageTest.java b/services/tests/displayservicetests/src/com/android/server/display/mode/VotesStorageTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/display/mode/VotesStorageTest.java
rename to services/tests/displayservicetests/src/com/android/server/display/mode/VotesStorageTest.java
diff --git a/services/tests/servicestests/src/com/android/server/display/utils/AmbientFilterTest.java b/services/tests/displayservicetests/src/com/android/server/display/utils/AmbientFilterTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/display/utils/AmbientFilterTest.java
rename to services/tests/displayservicetests/src/com/android/server/display/utils/AmbientFilterTest.java
diff --git a/services/tests/servicestests/src/com/android/server/display/whitebalance/AmbientFilterStubber.java b/services/tests/displayservicetests/src/com/android/server/display/whitebalance/AmbientFilterStubber.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/display/whitebalance/AmbientFilterStubber.java
rename to services/tests/displayservicetests/src/com/android/server/display/whitebalance/AmbientFilterStubber.java
diff --git a/services/tests/servicestests/src/com/android/server/display/whitebalance/AmbientLuxTest.java b/services/tests/displayservicetests/src/com/android/server/display/whitebalance/AmbientLuxTest.java
similarity index 94%
rename from services/tests/servicestests/src/com/android/server/display/whitebalance/AmbientLuxTest.java
rename to services/tests/displayservicetests/src/com/android/server/display/whitebalance/AmbientLuxTest.java
index ac97911..f975b6f 100644
--- a/services/tests/servicestests/src/com/android/server/display/whitebalance/AmbientLuxTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/whitebalance/AmbientLuxTest.java
@@ -268,9 +268,9 @@
controller.mBrightnessFilter = spy(new AmbientFilterStubber());
for (float luxOverride = 0.1f; luxOverride <= 10000; luxOverride *= 10) {
- setEstimatedBrightnessAndUpdate(controller, luxOverride);
- assertEquals(controller.mPendingAmbientColorTemperature,
- ambientColorTemperature, 0.001);
+ setEstimatedBrightnessAndUpdate(controller, luxOverride);
+ assertEquals(controller.mPendingAmbientColorTemperature,
+ ambientColorTemperature, 0.001);
}
}
@@ -286,9 +286,9 @@
controller.mBrightnessFilter = spy(new AmbientFilterStubber());
for (float luxOverride = 0.1f; luxOverride <= 10000; luxOverride *= 10) {
- setEstimatedBrightnessAndUpdate(controller, luxOverride);
- assertEquals(controller.mPendingAmbientColorTemperature,
- ambientColorTemperature, 0.001);
+ setEstimatedBrightnessAndUpdate(controller, luxOverride);
+ assertEquals(controller.mPendingAmbientColorTemperature,
+ ambientColorTemperature, 0.001);
}
}
@@ -366,22 +366,22 @@
@Test
public void testSpline_InvalidCombinations() throws Exception {
- setBrightnesses(100.0f, 200.0f);
- setBiases(0.0f, 1.0f);
- setHighLightBrightnesses(150.0f, 250.0f);
- setHighLightBiases(0.0f, 1.0f);
+ setBrightnesses(100.0f, 200.0f);
+ setBiases(0.0f, 1.0f);
+ setHighLightBrightnesses(150.0f, 250.0f);
+ setHighLightBiases(0.0f, 1.0f);
- DisplayWhiteBalanceController controller =
- DisplayWhiteBalanceFactory.create(mHandler, mSensorManagerMock, mResourcesSpy);
- final float ambientColorTemperature = 8000.0f;
- setEstimatedColorTemperature(controller, ambientColorTemperature);
- controller.mBrightnessFilter = spy(new AmbientFilterStubber());
+ DisplayWhiteBalanceController controller =
+ DisplayWhiteBalanceFactory.create(mHandler, mSensorManagerMock, mResourcesSpy);
+ final float ambientColorTemperature = 8000.0f;
+ setEstimatedColorTemperature(controller, ambientColorTemperature);
+ controller.mBrightnessFilter = spy(new AmbientFilterStubber());
- for (float luxOverride = 0.1f; luxOverride <= 10000; luxOverride *= 10) {
- setEstimatedBrightnessAndUpdate(controller, luxOverride);
- assertEquals(controller.mPendingAmbientColorTemperature,
- ambientColorTemperature, 0.001);
- }
+ for (float luxOverride = 0.1f; luxOverride <= 10000; luxOverride *= 10) {
+ setEstimatedBrightnessAndUpdate(controller, luxOverride);
+ assertEquals(controller.mPendingAmbientColorTemperature,
+ ambientColorTemperature, 0.001);
+ }
}
@Test
@@ -486,7 +486,7 @@
private void mockResourcesFloat(int id, float floatValue) {
doAnswer(new Answer<Void>() {
public Void answer(InvocationOnMock invocation) {
- TypedValue value = (TypedValue)invocation.getArgument(1);
+ TypedValue value = (TypedValue) invocation.getArgument(1);
value.type = TypedValue.TYPE_FLOAT;
value.data = Float.floatToIntBits(floatValue);
return null;
diff --git a/services/tests/servicestests/src/com/android/server/display/whitebalance/AmbientSensorTest.java b/services/tests/displayservicetests/src/com/android/server/display/whitebalance/AmbientSensorTest.java
similarity index 100%
rename from services/tests/servicestests/src/com/android/server/display/whitebalance/AmbientSensorTest.java
rename to services/tests/displayservicetests/src/com/android/server/display/whitebalance/AmbientSensorTest.java
diff --git a/services/tests/mockingservicestests/src/android/service/games/GameSessionTrampolineActivityTest.java b/services/tests/mockingservicestests/src/android/service/games/GameSessionTrampolineActivityTest.java
index 353341e..82e02ca 100644
--- a/services/tests/mockingservicestests/src/android/service/games/GameSessionTrampolineActivityTest.java
+++ b/services/tests/mockingservicestests/src/android/service/games/GameSessionTrampolineActivityTest.java
@@ -47,11 +47,14 @@
import com.android.internal.infra.AndroidFuture;
+import com.google.common.util.concurrent.Uninterruptibles;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.time.Duration;
import java.util.concurrent.TimeUnit;
/**
@@ -62,6 +65,8 @@
@Presubmit
public class GameSessionTrampolineActivityTest {
+ private static final Duration TEST_ACTIVITY_OPEN_DURATION = Duration.ofSeconds(5);
+
@Before
public void setUp() {
setAlwaysFinishActivities(false);
@@ -145,10 +150,15 @@
startTestActivityViaGameSessionTrampolineActivity() {
Intent testActivityIntent = new Intent();
testActivityIntent.setClass(getInstrumentation().getTargetContext(), TestActivity.class);
+ sleep(TEST_ACTIVITY_OPEN_DURATION);
return startGameSessionTrampolineActivity(testActivityIntent);
}
+ private static void sleep(Duration sleepDuration) {
+ Uninterruptibles.sleepUninterruptibly(sleepDuration.toMillis(), TimeUnit.MILLISECONDS);
+ }
+
private static AndroidFuture<GameSessionActivityResult> startGameSessionTrampolineActivity(
Intent targetIntent) {
AndroidFuture<GameSessionActivityResult> resultFuture = new AndroidFuture<>();
diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
index 32243f0..212a243 100644
--- a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
@@ -2221,7 +2221,7 @@
String[] packages = {mPackageName};
when(mMockPackageManager.getPackagesForUid(DEFAULT_PACKAGE_UID)).thenReturn(packages);
gameManagerService.mUidObserver.onUidStateChanged(
- DEFAULT_PACKAGE_UID, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0, 0);
+ DEFAULT_PACKAGE_UID, ActivityManager.PROCESS_STATE_TOP, 0, 0);
verify(mMockPowerManager, times(1)).setPowerMode(Mode.GAME, true);
}
@@ -2238,12 +2238,12 @@
doAnswer(inv -> powerState.put(inv.getArgument(0), inv.getArgument(1)))
.when(mMockPowerManager).setPowerMode(anyInt(), anyBoolean());
gameManagerService.mUidObserver.onUidStateChanged(
- DEFAULT_PACKAGE_UID, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0, 0);
+ DEFAULT_PACKAGE_UID, ActivityManager.PROCESS_STATE_TOP, 0, 0);
assertTrue(powerState.get(Mode.GAME));
gameManagerService.mUidObserver.onUidStateChanged(
DEFAULT_PACKAGE_UID, ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND, 0, 0);
gameManagerService.mUidObserver.onUidStateChanged(
- somePackageId, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0, 0);
+ somePackageId, ActivityManager.PROCESS_STATE_TOP, 0, 0);
assertTrue(powerState.get(Mode.GAME));
gameManagerService.mUidObserver.onUidStateChanged(
somePackageId, ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND, 0, 0);
@@ -2260,13 +2260,13 @@
int somePackageId = DEFAULT_PACKAGE_UID + 1;
when(mMockPackageManager.getPackagesForUid(somePackageId)).thenReturn(packages2);
gameManagerService.mUidObserver.onUidStateChanged(
+ DEFAULT_PACKAGE_UID, ActivityManager.PROCESS_STATE_TOP, 0, 0);
+ gameManagerService.mUidObserver.onUidStateChanged(
+ somePackageId, ActivityManager.PROCESS_STATE_TOP, 0, 0);
+ gameManagerService.mUidObserver.onUidStateChanged(
DEFAULT_PACKAGE_UID, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0, 0);
gameManagerService.mUidObserver.onUidStateChanged(
somePackageId, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0, 0);
- gameManagerService.mUidObserver.onUidStateChanged(
- DEFAULT_PACKAGE_UID, ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND, 0, 0);
- gameManagerService.mUidObserver.onUidStateChanged(
- somePackageId, ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND, 0, 0);
verify(mMockPowerManager, times(1)).setPowerMode(Mode.GAME, true);
verify(mMockPowerManager, times(1)).setPowerMode(Mode.GAME, false);
}
@@ -2277,9 +2277,9 @@
String[] packages = {mPackageName};
when(mMockPackageManager.getPackagesForUid(DEFAULT_PACKAGE_UID)).thenReturn(packages);
gameManagerService.mUidObserver.onUidStateChanged(
- DEFAULT_PACKAGE_UID, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0, 0);
+ DEFAULT_PACKAGE_UID, ActivityManager.PROCESS_STATE_TOP, 0, 0);
gameManagerService.mUidObserver.onUidStateChanged(
- DEFAULT_PACKAGE_UID, ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND, 0, 0);
+ DEFAULT_PACKAGE_UID, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0, 0);
verify(mMockPowerManager, times(1)).setPowerMode(Mode.GAME, false);
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/SensorOverlaysTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/SensorOverlaysTest.java
index 21c9c75..5012335 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/SensorOverlaysTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/SensorOverlaysTest.java
@@ -61,7 +61,7 @@
@Test
public void noopWhenBothNull() {
- final SensorOverlays useless = new SensorOverlays(null, null, null);
+ final SensorOverlays useless = new SensorOverlays(null, null);
useless.show(SENSOR_ID, 2, null);
useless.hide(SENSOR_ID);
}
@@ -69,12 +69,12 @@
@Test
public void testProvidesUdfps() {
final List<IUdfpsOverlayController> udfps = new ArrayList<>();
- SensorOverlays sensorOverlays = new SensorOverlays(null, mSidefpsController, null);
+ SensorOverlays sensorOverlays = new SensorOverlays(null, mSidefpsController);
sensorOverlays.ifUdfps(udfps::add);
assertThat(udfps).isEmpty();
- sensorOverlays = new SensorOverlays(mUdfpsOverlayController, mSidefpsController, null);
+ sensorOverlays = new SensorOverlays(mUdfpsOverlayController, mSidefpsController);
sensorOverlays.ifUdfps(udfps::add);
assertThat(udfps).containsExactly(mUdfpsOverlayController);
}
@@ -96,7 +96,7 @@
private void testShow(IUdfpsOverlayController udfps, ISidefpsController sidefps)
throws Exception {
- final SensorOverlays sensorOverlays = new SensorOverlays(udfps, sidefps, null);
+ final SensorOverlays sensorOverlays = new SensorOverlays(udfps, sidefps);
final int reason = BiometricOverlayConstants.REASON_UNKNOWN;
sensorOverlays.show(SENSOR_ID, reason, mAcquisitionClient);
@@ -126,7 +126,7 @@
private void testHide(IUdfpsOverlayController udfps, ISidefpsController sidefps)
throws Exception {
- final SensorOverlays sensorOverlays = new SensorOverlays(udfps, sidefps, null);
+ final SensorOverlays sensorOverlays = new SensorOverlays(udfps, sidefps);
sensorOverlays.hide(SENSOR_ID);
if (udfps != null) {
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
index c383a96..46af905 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
@@ -436,7 +436,7 @@
mBiometricLogger, mBiometricContext,
true /* isStrongBiometric */,
null /* taskStackListener */, null /* lockoutCache */,
- mUdfpsOverlayController, mSideFpsController, null, allowBackgroundAuthentication,
+ mUdfpsOverlayController, mSideFpsController, allowBackgroundAuthentication,
mSensorProps,
new Handler(mLooper.getLooper()), 0 /* biometricStrength */, mClock) {
@Override
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClientTest.java
index 6dfdd87..20d5f93 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClientTest.java
@@ -163,6 +163,6 @@
.setOpPackageName("a-test")
.build(),
mBiometricLogger, mBiometricContext,
- mUdfpsOverlayController, null, true /* isStrongBiometric */);
+ mUdfpsOverlayController, true /* isStrongBiometric */);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
index 3c89278..ef25380 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
@@ -296,6 +296,6 @@
mClientMonitorCallbackConverter, 0 /* userId */,
HAT, "owner", mBiometricUtils, 8 /* sensorId */,
mBiometricLogger, mBiometricContext, mSensorProps, mUdfpsOverlayController,
- mSideFpsController, null, 6 /* maxTemplatesPerUser */, FingerprintManager.ENROLL_ENROLL);
+ mSideFpsController, 6 /* maxTemplatesPerUser */, FingerprintManager.ENROLL_ENROLL);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/display/OWNERS b/services/tests/servicestests/src/com/android/server/display/OWNERS
deleted file mode 100644
index 6ce1ee4..0000000
--- a/services/tests/servicestests/src/com/android/server/display/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-include /services/core/java/com/android/server/display/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/display/TEST_MAPPING b/services/tests/servicestests/src/com/android/server/display/TEST_MAPPING
deleted file mode 100644
index 92d8abd..0000000
--- a/services/tests/servicestests/src/com/android/server/display/TEST_MAPPING
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "presubmit": [
- {
- "name": "FrameworksServicesTests",
- "options": [
- {"include-filter": "com.android.server.display"},
- {"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
- {"exclude-annotation": "androidx.test.filters.FlakyTest"},
- {"exclude-annotation": "org.junit.Ignore"}
- ]
- }
- ]
-}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
index 28241d3..f332b69 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -563,6 +563,36 @@
assertEquals(freeformBounds, task.getBounds());
}
+ @Test
+ public void testTopActivityEligibleForUserAspectRatioButton() {
+ DisplayContent display = mAtm.mRootWindowContainer.getDefaultDisplay();
+ final Task rootTask = new TaskBuilder(mSupervisor).setCreateActivity(true)
+ .setWindowingMode(WINDOWING_MODE_FULLSCREEN).setDisplay(display).build();
+ final Task task = rootTask.getBottomMostTask();
+ final ActivityRecord root = task.getTopNonFinishingActivity();
+ spyOn(mWm.mLetterboxConfiguration);
+
+ // When device config flag is disabled the button is not enabled
+ doReturn(false).when(mWm.mLetterboxConfiguration)
+ .isUserAppAspectRatioSettingsEnabled();
+ doReturn(false).when(mWm.mLetterboxConfiguration)
+ .isTranslucentLetterboxingEnabled();
+ assertFalse(task.getTaskInfo().topActivityEligibleForUserAspectRatioButton);
+
+ // The flag is enabled
+ doReturn(true).when(mWm.mLetterboxConfiguration)
+ .isUserAppAspectRatioSettingsEnabled();
+ spyOn(root);
+ doReturn(task).when(root).getOrganizedTask();
+ // When the flag is enabled and the top activity is not in size compat mode.
+ doReturn(false).when(root).inSizeCompatMode();
+ assertTrue(task.getTaskInfo().topActivityEligibleForUserAspectRatioButton);
+
+ // When in size compat mode the button is not enabled
+ doReturn(true).when(root).inSizeCompatMode();
+ assertFalse(task.getTaskInfo().topActivityEligibleForUserAspectRatioButton);
+ }
+
/**
* Tests that a task with forced orientation has orientation-consistent bounds within the
* parent.
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaDevice.java b/services/usb/java/com/android/server/usb/UsbAlsaDevice.java
index 7fe8582..c508fa9 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaDevice.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaDevice.java
@@ -59,6 +59,8 @@
private String mDeviceName = "";
private String mDeviceDescription = "";
+ private boolean mHasJackDetect = true;
+
public UsbAlsaDevice(IAudioService audioService, int card, int device, String deviceAddress,
boolean hasOutput, boolean hasInput,
boolean isInputHeadset, boolean isOutputHeadset, boolean isDock) {
@@ -168,8 +170,14 @@
if (mJackDetector != null) {
return;
}
+ if (!mHasJackDetect) {
+ return;
+ }
// If no jack detect capabilities exist, mJackDetector will be null.
mJackDetector = UsbAlsaJackDetector.startJackDetect(this);
+ if (mJackDetector == null) {
+ mHasJackDetect = false;
+ }
}
/** Stops a jack-detection thread. */
@@ -182,8 +190,8 @@
/** Start using this device as the selected USB Audio Device. */
public synchronized void start() {
- startInput();
startOutput();
+ startInput();
}
/** Start using this device as the selected USB input device. */
@@ -208,8 +216,8 @@
/** Stop using this device as the selected USB Audio Device. */
public synchronized void stop() {
- stopInput();
stopOutput();
+ stopInput();
}
/** Stop using this device as the selected USB input device. */
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
index 13945a1..997015f 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
@@ -407,7 +407,9 @@
var eventLogger = new EventLogger(SESSION_MAX_EVENT_SIZE,
"SoundTriggerSessionLogs for package: "
+ Objects.requireNonNull(originatorIdentity.packageName)
- + "#" + sessionId);
+ + "#" + sessionId
+ + " - " + originatorIdentity.uid
+ + "|" + originatorIdentity.pid);
return new SoundTriggerSessionStub(client,
newSoundTriggerHelper(moduleProperties, eventLogger), eventLogger);
}
@@ -428,7 +430,9 @@
var eventLogger = new EventLogger(SESSION_MAX_EVENT_SIZE,
"SoundTriggerSessionLogs for package: "
+ Objects.requireNonNull(originatorIdentity.packageName) + "#"
- + sessionId);
+ + sessionId
+ + " - " + originatorIdentity.uid
+ + "|" + originatorIdentity.pid);
return new SoundTriggerSessionStub(client,
newSoundTriggerHelper(moduleProperties, eventLogger), eventLogger);
}
@@ -1801,7 +1805,9 @@
ServiceEvent.Type.ATTACH, identity.packageName + "#" + sessionId));
var eventLogger = new EventLogger(SESSION_MAX_EVENT_SIZE,
"LocalSoundTriggerEventLogger for package: " +
- identity.packageName + "#" + sessionId);
+ identity.packageName + "#" + sessionId
+ + " - " + identity.uid
+ + "|" + identity.pid);
return new SessionImpl(newSoundTriggerHelper(underlyingModule, eventLogger, isTrusted),
client, eventLogger, identity);
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/DefaultHalFactory.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/DefaultHalFactory.java
index 2f2cb59..55cbf29 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/DefaultHalFactory.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/DefaultHalFactory.java
@@ -22,7 +22,7 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
-import android.util.Log;
+import android.util.Slog;
import java.util.ArrayList;
import java.util.Arrays;
@@ -62,7 +62,7 @@
android.hardware.soundtrigger3.ISoundTriggerHw.class.getCanonicalName()
+ "/default";
if (ServiceManager.isDeclared(aidlServiceName)) {
- Log.i(TAG, "Connecting to default soundtrigger3.ISoundTriggerHw");
+ Slog.i(TAG, "Connecting to default soundtrigger3.ISoundTriggerHw");
return new SoundTriggerHw3Compat(ServiceManager.waitForService(aidlServiceName),
() -> {
// This property needs to be defined in an init.rc script and
@@ -72,7 +72,7 @@
}
// Fallback to soundtrigger-V2.x (HIDL).
- Log.i(TAG, "Connecting to default soundtrigger-V2.x.ISoundTriggerHw");
+ Slog.i(TAG, "Connecting to default soundtrigger-V2.x.ISoundTriggerHw");
ISoundTriggerHw driver = ISoundTriggerHw.getService(true);
return SoundTriggerHw2Compat.create(driver, () -> {
// This property needs to be defined in an init.rc script and
@@ -81,7 +81,7 @@
}, mCaptureStateNotifier);
} else if (mockHal == USE_MOCK_HAL_V2) {
// Use V2 mock.
- Log.i(TAG, "Connecting to mock soundtrigger-V2.x.ISoundTriggerHw");
+ Slog.i(TAG, "Connecting to mock soundtrigger-V2.x.ISoundTriggerHw");
HwBinder.setTrebleTestingOverride(true);
try {
ISoundTriggerHw driver = ISoundTriggerHw.getService("mock", true);
@@ -89,7 +89,7 @@
try {
driver.debug(null, new ArrayList<>(Arrays.asList("reboot")));
} catch (Exception e) {
- Log.e(TAG, "Failed to reboot mock HAL", e);
+ Slog.e(TAG, "Failed to reboot mock HAL", e);
}
}, mCaptureStateNotifier);
} finally {
@@ -100,14 +100,14 @@
final String aidlServiceName =
android.hardware.soundtrigger3.ISoundTriggerHw.class.getCanonicalName()
+ "/mock";
- Log.i(TAG, "Connecting to mock soundtrigger3.ISoundTriggerHw");
+ Slog.i(TAG, "Connecting to mock soundtrigger3.ISoundTriggerHw");
return new SoundTriggerHw3Compat(ServiceManager.waitForService(aidlServiceName),
() -> {
try {
ServiceManager.waitForService(aidlServiceName).shellCommand(null,
null, null, new String[]{"reboot"}, null, null);
} catch (Exception e) {
- Log.e(TAG, "Failed to reboot mock HAL", e);
+ Slog.e(TAG, "Failed to reboot mock HAL", e);
}
});
} else {
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/ExternalCaptureStateTracker.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/ExternalCaptureStateTracker.java
index d195fbe..e3d64d4 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/ExternalCaptureStateTracker.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/ExternalCaptureStateTracker.java
@@ -17,7 +17,7 @@
package com.android.server.soundtrigger_middleware;
import android.annotation.NonNull;
-import android.util.Log;
+import android.util.Slog;
import java.util.LinkedList;
import java.util.List;
@@ -94,7 +94,7 @@
}
}
} catch (Exception e) {
- Log.e(TAG, "Exception caught while setting capture state", e);
+ Slog.e(TAG, "Exception caught while setting capture state", e);
}
}
@@ -102,7 +102,7 @@
* Called by native code when the remote service died.
*/
private void binderDied() {
- Log.w(TAG, "Audio policy service died");
+ Slog.w(TAG, "Audio policy service died");
mNeedToConnect.release();
}
}
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHalEnforcer.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHalEnforcer.java
index c3e0a3c..0f63347 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHalEnforcer.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHalEnforcer.java
@@ -27,7 +27,7 @@
import android.media.soundtrigger_middleware.RecognitionEventSys;
import android.os.DeadObjectException;
import android.os.IBinder;
-import android.util.Log;
+import android.util.Slog;
import java.util.HashMap;
import java.util.Map;
@@ -227,10 +227,10 @@
}
if (e.getCause() instanceof DeadObjectException) {
// Server is dead, no need to reboot.
- Log.e(TAG, "HAL died");
+ Slog.e(TAG, "HAL died");
throw new RecoverableException(Status.DEAD_OBJECT);
}
- Log.e(TAG, "Exception caught from HAL, rebooting HAL");
+ Slog.e(TAG, "Exception caught from HAL, rebooting HAL");
reboot();
throw e;
}
@@ -257,14 +257,14 @@
synchronized (mModelStates) {
ModelState state = mModelStates.get(model);
if (state == null) {
- Log.wtfStack(TAG, "Unexpected recognition event for model: " + model);
+ Slog.wtfStack(TAG, "Unexpected recognition event for model: " + model);
reboot();
return;
}
if (event.recognitionEvent.recognitionStillActive
&& event.recognitionEvent.status != RecognitionStatus.SUCCESS
&& event.recognitionEvent.status != RecognitionStatus.FORCED) {
- Log.wtfStack(TAG,
+ Slog.wtfStack(TAG,
"recognitionStillActive is only allowed when the recognition status "
+ "is SUCCESS");
reboot();
@@ -283,14 +283,14 @@
synchronized (mModelStates) {
ModelState state = mModelStates.get(model);
if (state == null) {
- Log.wtfStack(TAG, "Unexpected recognition event for model: " + model);
+ Slog.wtfStack(TAG, "Unexpected recognition event for model: " + model);
reboot();
return;
}
if (event.phraseRecognitionEvent.common.recognitionStillActive
&& event.phraseRecognitionEvent.common.status != RecognitionStatus.SUCCESS
&& event.phraseRecognitionEvent.common.status != RecognitionStatus.FORCED) {
- Log.wtfStack(TAG,
+ Slog.wtfStack(TAG,
"recognitionStillActive is only allowed when the recognition status "
+ "is SUCCESS");
reboot();
@@ -309,13 +309,13 @@
synchronized (mModelStates) {
ModelState state = mModelStates.get(modelHandle);
if (state == null) {
- Log.wtfStack(TAG, "Unexpected unload event for model: " + modelHandle);
+ Slog.wtfStack(TAG, "Unexpected unload event for model: " + modelHandle);
reboot();
return;
}
if (state == ModelState.ACTIVE) {
- Log.wtfStack(TAG, "Trying to unload an active model: " + modelHandle);
+ Slog.wtfStack(TAG, "Trying to unload an active model: " + modelHandle);
reboot();
return;
}
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHalWatchdog.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHalWatchdog.java
index 0390f03..5e525e0 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHalWatchdog.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHalWatchdog.java
@@ -23,7 +23,7 @@
import android.media.soundtrigger.RecognitionConfig;
import android.media.soundtrigger.SoundModel;
import android.os.IBinder;
-import android.util.Log;
+import android.util.Slog;
import java.util.Objects;
@@ -172,7 +172,7 @@
Watchdog() {
mTask = mTimer.createTask(() -> {
- Log.e(TAG, "HAL deadline expired. Rebooting.", mException);
+ Slog.e(TAG, "HAL deadline expired. Rebooting.", mException);
reboot();
}, TIMEOUT_MS);
}
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Compat.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Compat.java
index df2e9b4..730e92c 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Compat.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Compat.java
@@ -32,7 +32,7 @@
import android.os.RemoteException;
import android.os.SystemClock;
import android.system.OsConstants;
-import android.util.Log;
+import android.util.Slog;
import java.io.IOException;
import java.util.HashMap;
@@ -240,7 +240,7 @@
try {
hidlModel.data.close();
} catch (IOException e) {
- Log.e(TAG, "Failed to close file", e);
+ Slog.e(TAG, "Failed to close file", e);
}
}
}
@@ -276,7 +276,7 @@
try {
hidlModel.common.data.close();
} catch (IOException e) {
- Log.e(TAG, "Failed to close file", e);
+ Slog.e(TAG, "Failed to close file", e);
}
}
}
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImpl.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImpl.java
index 3b800de..5a064da 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImpl.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImpl.java
@@ -20,7 +20,7 @@
import android.media.soundtrigger_middleware.ISoundTriggerCallback;
import android.media.soundtrigger_middleware.ISoundTriggerModule;
import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor;
-import android.util.Log;
+import android.util.Slog;
import java.util.ArrayList;
import java.util.List;
@@ -85,7 +85,7 @@
try {
modules.add(new SoundTriggerModule(halFactory, audioSessionProvider));
} catch (Exception e) {
- Log.e(TAG, "Failed to add a SoundTriggerModule instance", e);
+ Slog.e(TAG, "Failed to add a SoundTriggerModule instance", e);
}
}
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
index 7ec2d9f..0b9ed8c 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
@@ -36,7 +36,7 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
-import android.util.Log;
+import android.util.Slog;
import android.util.SparseArray;
import com.android.internal.util.Preconditions;
@@ -150,7 +150,7 @@
e.getMessage());
}
- Log.wtf(TAG, "Unexpected exception", e);
+ Slog.wtf(TAG, "Unexpected exception", e);
throw new ServiceSpecificException(Status.INTERNAL_ERROR, e.getMessage());
}
@@ -701,7 +701,7 @@
try {
mCallback.onRecognition(modelHandle, event, captureSession);
} catch (Exception e) {
- Log.w(TAG, "Client callback exception.", e);
+ Slog.w(TAG, "Client callback exception.", e);
}
}
@@ -719,7 +719,7 @@
try {
mCallback.onPhraseRecognition(modelHandle, event, captureSession);
} catch (Exception e) {
- Log.w(TAG, "Client callback exception.", e);
+ Slog.w(TAG, "Client callback exception.", e);
}
}
@@ -734,7 +734,7 @@
try {
mCallback.onModelUnloaded(modelHandle);
} catch (Exception e) {
- Log.w(TAG, "Client callback exception.", e);
+ Slog.w(TAG, "Client callback exception.", e);
}
}
@@ -746,7 +746,7 @@
} catch (RemoteException e) {
// Dead client will be handled by binderDied() - no need to handle here.
// In any case, client callbacks are considered best effort.
- Log.e(TAG, "Client callback exception.", e);
+ Slog.e(TAG, "Client callback exception.", e);
}
}
@@ -761,7 +761,7 @@
} catch (RemoteException e) {
// Dead client will be handled by binderDied() - no need to handle here.
// In any case, client callbacks are considered best effort.
- Log.e(TAG, "Client callback exception.", e);
+ Slog.e(TAG, "Client callback exception.", e);
}
}
@@ -795,11 +795,11 @@
// Check if state updated unexpectedly to log race conditions.
for (Map.Entry<Integer, ModelState> entry : mLoadedModels.entrySet()) {
if (cachedMap.get(entry.getKey()) != entry.getValue().activityState) {
- Log.e(TAG, "Unexpected state update in binderDied. Race occurred!");
+ Slog.e(TAG, "Unexpected state update in binderDied. Race occurred!");
}
}
if (mLoadedModels.size() != cachedMap.size()) {
- Log.e(TAG, "Unexpected state update in binderDied. Race occurred!");
+ Slog.e(TAG, "Unexpected state update in binderDied. Race occurred!");
}
try {
// Detach
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
index e793f31..45a7faf 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
@@ -31,7 +31,7 @@
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
-import android.util.Log;
+import android.util.Slog;
import java.util.ArrayList;
import java.util.HashMap;
@@ -136,7 +136,7 @@
@Override
public void binderDied() {
- Log.w(TAG, "Underlying HAL driver died.");
+ Slog.w(TAG, "Underlying HAL driver died.");
List<ISoundTriggerCallback> callbacks;
synchronized (this) {
callbacks = new ArrayList<>(mActiveSessions.size());
@@ -270,7 +270,7 @@
try {
mAudioSessionProvider.releaseSession(audioSession.mSessionHandle);
} catch (Exception ee) {
- Log.e(TAG, "Failed to release session.", ee);
+ Slog.e(TAG, "Failed to release session.", ee);
}
throw e;
}
@@ -286,7 +286,7 @@
checkValid();
Model loadedModel = new Model();
int result = loadedModel.load(model, audioSession);
- Log.d(TAG, String.format("loadPhraseModel()->%d", result));
+ Slog.d(TAG, String.format("loadPhraseModel()->%d", result));
return result;
} catch (Exception e) {
// We must do this outside the lock, to avoid possible deadlocks with the remote
@@ -294,7 +294,7 @@
try {
mAudioSessionProvider.releaseSession(audioSession.mSessionHandle);
} catch (Exception ee) {
- Log.e(TAG, "Failed to release session.", ee);
+ Slog.e(TAG, "Failed to release session.", ee);
}
throw e;
}